Перейти к основному содержимому

Python

Для корректной работы программы показанной в статье необходим Python 3.8.10

Создадим Python файл

type nul > shared_client.py

Если вы используете текстовый редактор,то необходимо изменить кодировку shared_client.py на UTF-8 без BOM, либо использовать IDE (VsCode,etc.).

Структура проекта

. workspace/
--- > shared_client.py
--- > librisdk.h
--- > librisdk.so/.dll
--- > libusb-1.0.so/.dll

Подключим библиотеку

from ctypes.util import find_library
from ctypes import *
import platform

# Подключаем внешнюю библиотеку для работы с SDK
platform=platform.system()
if platform=="Windows":
lib = cdll.LoadLibrary("librisdk.dll")
if platform=="Linux":
lib = cdll.LoadLibrary("librisdk.so")

def main():
print("Success")

main()

Для запуска скрипта выполним в терминале следующую команду

python3 shared_client.py

Создадим компонент внутри функции main

# Инициализируем SDK
errCode, errText = RI_SDK_InitSDK_()
if errCode != 0:
# Выведем текст и код ошибки в терминал, при возникновении
print(errCode, decodeErr(errText))
return

# Создаем базовый компонент
descriptor, errCode, errText = RI_SDK_CreateBasic_()
if errCode != 0:
# Выведем текст и код ошибки в терминал, при возникновении
print(errCode, decodeErr(errText))
return

# Выведем полученный дескриптор компонента
print("descriptor:", descriptor, "--")

# для получения текста ошибки
def decodeErr(err):
return err.value.decode('utf-8')


# RI_SDK_InitSDK_ - вызов функции из Shared Object для инициализации SDK
def RI_SDK_InitSDK_():
logLevel = 2
errTextC = c_char_p() # Текст ошибки. C type: char*

# Указываем типы аргументов для функций библиотеки RI_SDK
lib.RI_SDK_InitSDK.argtypes = [c_int, POINTER(c_char_p)]
# Вызываем функцию инициализации
errCode = lib.RI_SDK_InitSDK(logLevel, errTextC)
if errCode != 0:
return errCode, errTextC

return errCode, errTextC.value


# RI_SDK_CreateBasic_ - вызов функции из Shared Object для создания компонента
def RI_SDK_CreateBasic_():
descriptor = c_int() # Дескриптор компонента. C type: int

errTextC = c_char_p() # Текст ошибки. C type: char*
# Указываем типы аргументов
lib.RI_SDK_CreateBasic.argtypes = [POINTER(c_int), POINTER(c_char_p)]
# Создаем компонент
errCode = lib.RI_SDK_CreateBasic(descriptor, errTextC)
if errCode != 0:
return descriptor.value, errCode, errTextC

return descriptor.value, errCode, errTextC.value

Компилируем и запустим скрипт

python3 shared_client.py

Результат успешной работы должен выглядеть следующим образом:

Success
descriptor:1--

Пример программы на Python использующий RISDK

Описание

Данная программа является примером, использования библиотеки. Она реализует простой сценарий поведения робота. Сперва все сервоприводы встают в условное стартовое положение. После робот берет кубик с позиции слева и перемещает его на позицию справа. После сервоприводы возвращаются в первоначальное положение.
Одновременно с движением робота, происходит свечение светодиода. Светодиод горит красным цветом пока сервоприводы приводятся к стартовому положению, после загорается зеленым. Далее светодиоды моргает зеленым при передвижении тела робота и мерцает синим, пока робот кладет/берет кубик.

Структура проекта

. workspace/
--- > demo.php
--- > librisdk.h
--- > librisdk.dll/.so
--- > CH341DLL.DLL/ CH341DLLA64.DLL
--- > SLABHIDDevice.dll
--- > SLABHIDtoSMBus.dll
--- > libusb-1.0.dll/.so

Реализация

from ctypes.util import find_library
from ctypes import *
import platform
import time

# Подключаем внешнюю библиотеку для работы с SDK
platform = platform.system()
if platform == "Windows":
libName = "librisdk.dll"
if platform == "Linux":
libName = "librisdk.so"

pathLib = find_library(libName)
lib = cdll.LoadLibrary(pathLib)

# Инициализируем глобальные переменные
body_start_pulse = 1500 # стартовая позиция тела
arrowR_start_pulse = 2000 # стартовая позиция правой стрелы
arrowL_start_pulse = 1000 # стартовая позиция левой стрелы
claw_start_pulse = 1000 # стартовая позиция клешни
claw_rotate_start_pulse = 1500 # стартовая позиция поворота клешни

arrowR_over_cube_position = -30 # позиция правой стрелы над кубиком
arrowL_over_cube_position = -10 # позиция левой стрелы над кубиком
claw_unclenched_position = 80 # позиция открытой клешни
arrowR_cube_position = -75 # позиция правой стрелы на месте кубика
arrowL_cube_position = 55 # позиция левой стрелы на месте кубика

logLevel = 2 # уровень логирования
speed = 100 # скорость в градусах в секунду

# структура дескрипторов устройства: ключ-имя - значение дескриптора
device = {
"i2c": c_int(), # дескриптор i2c
"pwm": c_int(), # дескриптор pwm
"body": c_int(), # дескриптор сервопривода тела
"claw": c_int(), # дескриптор сервопривода клешни
"arrowR": c_int(), # дескриптор сервопривода правой стрелы
"arrowL": c_int(), # дескриптор сервопривода левой стрелы
"clawRotate": c_int(), # дескриптор сервопривода поворота клешни
"led": c_int(), # дескриптор светодиода
}

# массив дескрипторов сервоприводов и их стартовых позиций
servos = [
{"descriptor": device["body"],
"start_position": body_start_pulse
},
{"descriptor": device["claw"],
"start_position": claw_start_pulse
},
{"descriptor": device["arrowR"],
"start_position": arrowR_start_pulse
},
{"descriptor": device["arrowL"],
"start_position": arrowL_start_pulse
},
{"descriptor": device["clawRotate"],
"start_position": claw_rotate_start_pulse
},
]

# Указываем типы аргументов для функций
lib.RI_SDK_InitSDK.argtypes = [c_int, POINTER(c_char_p)]
lib.RI_SDK_CreateModelComponent.argtypes = [c_char_p, c_char_p, c_char_p, POINTER(c_int), POINTER(c_char_p)]
lib.RI_SDK_LinkPWMToController.argtypes = [c_int, c_int, c_uint8, POINTER(c_char_p)]
lib.RI_SDK_LinkLedToController.argtypes = [c_int, c_int, c_int, c_int, c_int, POINTER(c_char_p)]
lib.RI_SDK_LinkServodriveToController.argtypes = [c_int, c_int, c_int, POINTER(c_char_p)]
lib.RI_SDK_exec_RGB_LED_SinglePulse.argtypes = [c_int, c_int, c_int, c_int, c_int, c_bool, POINTER(c_char_p)]
lib.RI_SDK_exec_ServoDrive_TurnByPulse.argtypes = [c_int, c_int, POINTER(c_char_p)]
lib.RI_SDK_DestroyComponent.argtypes = [c_int, POINTER(c_char_p)]
lib.RI_SDK_exec_RGB_LED_Stop.argtypes = [c_int, POINTER(c_char_p)]
lib.RI_SDK_sigmod_PWM_ResetAll.argtypes = [c_int, POINTER(c_char_p)]
lib.RI_SDK_DestroySDK.argtypes = [c_bool, POINTER(c_char_p)]
lib.RI_SDK_exec_RGB_LED_FlashingWithFrequency.argtypes = [c_int, c_int, c_int, c_int, c_int, c_int, c_bool,
POINTER(c_char_p)]
lib.RI_SDK_exec_RGB_LED_Flicker.argtypes = [c_int, c_int, c_int, c_int, c_int, c_int, c_bool, POINTER(c_char_p)]
lib.RI_SDK_exec_ServoDrive_Turn.argtypes = [c_int, c_int, c_int, c_bool, POINTER(c_char_p)]


# для получения текста ошибки
def decodeErr(err):
return err.value.decode()


# initServos - создает сервоприводы и линкует их
def initServos():

errTextC = c_char_p() # Текст ошибки. C type: char*
errCode = c_int
# создаем 5 сервоприводов и линкуем их к пинам 0-4
for i in range(len(servos)):
# создаем компонент сервопривода с конкретной моделью как исполняемое устройство и получаем дескриптор сервопривода
errCode = lib.RI_SDK_CreateModelComponent("executor".encode(), "servodrive".encode(), "mg90s".encode(),
servos[i]["descriptor"], errTextC)
if errCode != 0:
return errCode, errTextC
# связываем сервопривод с ШИМ,передаем дескриптор сервопривода и ШИМ
errCode = lib.RI_SDK_LinkServodriveToController(servos[i]["descriptor"], device["pwm"], i, errTextC)
if errCode != 0:
return errCode, errTextC
return errCode, errTextC


# initDevice - инициализация библиотеки и устройств
def initDevice():
errTextC = c_char_p() # Текст ошибки. C type: char*
# Вызываем функцию инициализации
errCode = lib.RI_SDK_InitSDK(logLevel, errTextC)
if errCode != 0:
return errCode, errTextC
# создаем компонент ШИМ с конкретной моделью как исполняемое устройство,получаем дескриптор сервопривода
errCode = lib.RI_SDK_CreateModelComponent("connector".encode(), "pwm".encode(), "pca9685".encode(), device["pwm"],
errTextC)
if errCode != 0:
return errCode, errTextC

# создаем компонент i2c адатера
# Здесь осуществлен примитивное определение подключенной модели адаптера
# Сначала пробуем создать i2c адаптер модели ch341 и связать с ним ШИМ
errCode = lib.RI_SDK_CreateModelComponent("connector".encode(), "i2c_adapter".encode(), "ch341".encode(),
device["i2c"], errTextC)
if errCode != 0:
return errCode, errTextC

# связываем i2c адаптер с ШИМ по адресу 0x40
errCode = lib.RI_SDK_LinkPWMToController(device["pwm"], device["i2c"], c_uint8(0x40), errTextC)
if errCode != 0:

# Если не получается то пробуем создать i2c адаптер модели cp2112
errCode = lib.RI_SDK_CreateModelComponent("connector".encode(), "i2c_adapter".encode(), "cp2112".encode(),
device["i2c"], errTextC)
if errCode != 0:
return errCode, errTextC
# связываем i2c адаптер с ШИМ по адресу 0x40
errCode = lib.RI_SDK_LinkPWMToController(device["pwm"], device["i2c"], c_uint8(0x40), errTextC)

if errCode != 0:
return errCode, errTextC



# создаем компонент светодиода с конкретной моделью (ky016) как исполняемое устройство и получаем дескриптор светодиода
errCode = lib.RI_SDK_CreateModelComponent("executor".encode(), "led".encode(), "ky016".encode(), device["led"],
errTextC)
if errCode != 0:
return errCode, errTextC
# связываем светодиод с ШИМ,передаем значения трех пинов к которым подключен светодиод
errCode = lib.RI_SDK_LinkLedToController(device["led"], device["pwm"], 15, 14, 13, errTextC)
if errCode != 0:
return errCode, errTextC
# инициализируем сервоприводы
errCode, errTextC = initServos()
if errCode != 0:
return errCode, errTextC
return errCode, errTextC.value


# startPosition - переводит сервопривод в стартовое положение
def startPosition(servo):
errTextC = c_char_p() # Текст ошибки. C type: char*
errCode = 0
# выполняем поворот сервопривода в заданный угол,передаем дескриптор сервопривода,значение угла
errCode = lib.RI_SDK_exec_ServoDrive_TurnByPulse(servo["descriptor"], servo["start_position"], errTextC)
if errCode != 0:
return errCode, errTextC

time.sleep(0.5)

return errCode, errTextC


# startPositionAllServo - переводит все сервоприводы в стартовую позицию
def startPositionAllServo():
errTextC = c_char_p() # Текст ошибки. C type: char*
# выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errCode = lib.RI_SDK_exec_RGB_LED_SinglePulse(device["led"], 255, 0, 0, 0, c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC
# приводим сервоприводы в стартовое положение
for i in range(len(servos)):
errCode, errTextC = startPosition(servos[i])
if errCode != 0:
return errCode, errTextC
# выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errCode = lib.RI_SDK_exec_RGB_LED_SinglePulse(device["led"], 0, 255, 0, 0, c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC
# небольшая пауза для последовательного движения
time.sleep(0.5)

return errCode, errTextC.value


# destructServos - уничтожает сервоприводы
def destructServos():
errTextC = c_char_p() # Текст ошибки. C type: char*

for i in range(len(servos)):
errCode = lib.RI_SDK_DestroyComponent(servos[i]["descriptor"], errTextC)
if errCode != 0:
return errCode, errTextC

return errCode, errTextC


# destruct - уничтожает все компоненты и библиотеку
def destruct():
errTextC = c_char_p() # Текст ошибки. C type: char*
# выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errCode = lib.RI_SDK_exec_RGB_LED_SinglePulse(device["led"], 255, 0, 0, 0, c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC
# уничтожаем сервоприводы
errCode, errTextC = destructServos()
if errCode != 0:
return errCode, errTextC
# останавливаем свечение светодиода с определенным дескриптором
errCode = lib.RI_SDK_exec_RGB_LED_Stop(device["led"], errTextC)
if errCode != 0:
return errCode, errTextC
# удаляем компонент светодиода по дескриптору
errCode = lib.RI_SDK_DestroyComponent(device["led"], errTextC)
if errCode != 0:
return errCode, errTextC
# сбрасываем все порты на ШИМ
errCode = lib.RI_SDK_sigmod_PWM_ResetAll(device["pwm"], errTextC)
if errCode != 0:
return errCode, errTextC
# удаляем компонент ШИМ
errCode = lib.RI_SDK_DestroyComponent(device["pwm"], errTextC)
if errCode != 0:
return errCode, errTextC
# удаляем компонент i2c
errCode = lib.RI_SDK_DestroyComponent(device["i2c"], errTextC)
if errCode != 0:
return errCode, errTextC
# удаляем sdk со всеми компонентами в реестре компонентов
errCode = lib.RI_SDK_DestroySDK(c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC

return errCode, errTextC

# rotateBody - вращение тела в указанный угол
def rotateBody(angle, speed):
errTextC = c_char_p() # Текст ошибки. C type: char*
# выполняем мигание с заданной частотой,передаем дескриптор светодиода,3 параметра цвета(RGB),частоту,продолжительность и включаем асинхронный режим работы
errCode = lib.RI_SDK_exec_RGB_LED_FlashingWithFrequency(device["led"], 0, 255, 0, 5, 0, c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор тела,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["body"], angle, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["clawRotate"], 45, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["clawRotate"], -45, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC

return errCode, errTextC


# get - берет кубик
def get():
errTextC = c_char_p() # Текст ошибки. C type: char*
# выполняем мерцание светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB),продолжительность,кол-во повторений и включаем асинхронный режим работы
errCode = lib.RI_SDK_exec_RGB_LED_FlashingWithFrequency(device["led"], 0, 0, 255, 500, 0, c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowR"], arrowR_over_cube_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowL"], arrowL_over_cube_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["claw"], claw_unclenched_position, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowR"], (arrowR_cube_position - arrowR_over_cube_position),
speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowL"], (arrowL_cube_position - arrowL_over_cube_position),
speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["claw"], (-1) * claw_unclenched_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowR"], (-1) * arrowR_cube_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowL"], (-1) * arrowL_cube_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC

return errCode, errTextC


# put - кладет кубик
def put():
errTextC = c_char_p() # Текст ошибки. C type: char*
# выполняем мерцание светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB),продолжительность,кол-во повторений и включаем асинхронный режим работы
errCode = lib.RI_SDK_exec_RGB_LED_Flicker(device["led"], 0, 0, 255, 500, 0, c_bool(True), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowR"], arrowR_cube_position, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowL"], arrowL_cube_position, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["claw"], claw_unclenched_position, speed, c_bool(False), errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowR"], (-1) * arrowR_cube_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["arrowL"], (-1) * arrowL_cube_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC
# выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = lib.RI_SDK_exec_ServoDrive_Turn(device["claw"], (-1) * claw_unclenched_position, speed, c_bool(False),
errTextC)
if errCode != 0:
return errCode, errTextC

return errCode, errTextC


# start - запускает демо программу
def start():
# Инициализируем библиотеку и компоненты
errCode, errText = initDevice()
if errCode != 0:
return errCode, errText

# Приводим сервоприводы к стартовой позиции
errCode, errText = startPositionAllServo()
if errCode != 0:
return errCode, errText

# Двигаем тело к местонахождению кубика
errCode, errText = rotateBody(45, speed)
if errCode != 0:
return errCode, errText

# Берем кубик
errCode, errText = get()
if errCode != 0:
return errCode, errText

# Двигаем тело к новому местонахождению кубика
errCode, errText = rotateBody(-90, speed)
if errCode != 0:
return errCode, errText

# Кладем кубик
errCode, errText = put()
if errCode != 0:
return errCode, errText

# Возвращаем тело в стартовое положение
errCode, errText = rotateBody(45, speed)
if errCode != 0:
return errCode, errText

# Уничтожаем компоненты и библиотеку
errCode, errText = destruct()
if errCode != 0:
return errCode, errText
return errCode, errText


# Главная функция запускающая все остальное
def main():
errCode, errText = start()
if errCode != 0:
print(errCode, errText)
return

print("Success", device)


main()