Skip to main content

Golang

Подключение RI_SDK динамической библиотеки к приложению на Golang.

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

На данный момент Golang не поддерживает работу с Shared Object на Windows

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

. workspace/
--- > shared_client.go
--- > librisdk.h
--- > librisdk.so

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

package main
/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lrisdk
#include <librisdk.h>
*/
import "C"
import (
"fmt"
)

func main() {

fmt.Println("Success")
}

Для запуска скрипта выполним в терминале следующие команды:
Укажем компилятору gcc что динамические библиотеки можно искать в текущей директории.

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

Выполним компиляцию

go build -o go_shared_client.bin shared_client.go

Значение shared_client.go указывает на файл, который необходимо собрать.
Значение -o go_shared_client.bin указывает на путь к скомпиленному файлу.

Получаем результат выполнения собранной программы

./go_shared_client.bin

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

var (
logLevel = C.int(1) //уровень логирования
errorTextC [1000]C.char //текст ошибки
errorCode C.int //код ошибки
)

// Инициализируем SDK
errorCode = C.RI_SDK_InitSDK(logLevel, &errorTextC[0])
if errorCode != 0 {
// Возвращаем текст и код ошибки
errorText := C.GoString(&errorTextC[0])
err = fmt.Errorf("errorCode:%d - errorText:%s", errorCode, errorText)
return
}

var descriptor = C.int(0)

// Создаем базовый компонент
errorCode = C.RI_SDK_CreateBasic(&descriptor, &errorTextC[0])
if errorCode != 0 {
// Возвращаем текст и код ошибки
errorText := C.GoString(&errorTextC[0])
err = fmt.Errorf("errorCode:%d - errorText:%s", errorCode, errorText)
return
}

// Выведем полученный дескриптор компонента
fmt.Printf("descriptor:%d--\n", descriptor)

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

./go_shared_client.bin

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

descriptor:1--
Success

Пример программы на Golang, использующий RI_SDK

Описание

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

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

. workspace/
--- > demo.go
--- > librisdk.h
--- > librisdk.so

Реализация

package main

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lrisdk
#include <librisdk.h>
*/
import "C"
import (
"fmt"
"time"
)

var (
body_start_pulse = C.int(1500) // стартовая позиция тела
arrowR_start_pulse = C.int(2000) // стартовая возиция правой стрелы
arrowL_start_pulse = C.int(1000) // стартовая позиция левой стрелы
claw_start_pulse = C.int(1000) // стартовая позиция клешни
claw_rotate_start_pulse = C.int(1500) // стартовая позиция поворота клешни

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

logLevel = C.int(2) // уровень логирования
speed = C.int(100) // скорость в градусах в секунду
)

// структура дескрипторов устройства
type device struct {
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 // дескриптор светодиода
}

// инициализация структуры устройства
var robohand device

type servo struct {
descriptor *C.int // дескриптор сервопривода
startPosition *C.int // стартовая позиция сервопривода
}

// массив дескрипторов сервоприводов
var servos = [5]servo{
{
descriptor: &robohand.body,
startPosition: &body_start_pulse,
},
{
descriptor: &robohand.claw,
startPosition: &claw_start_pulse,
},
{
descriptor: &robohand.arrowR,
startPosition: &arrowR_start_pulse,
},
{
descriptor: &robohand.arrowL,
startPosition: &arrowL_start_pulse,
},
{
descriptor: &robohand.clawRotate,
startPosition: &claw_rotate_start_pulse,
},
}

// initServos - создает сервоприводы и линкует их
func initServos() error {
var (
errorTextC [1000]C.char //текст ошибки. Передается как входной параметр,при возникновении ошибки в эту переменную будет записан текст ошибки
errCode C.int //код ошибки
)
//создаем 5 сервоприводов и линкуем их к пинам 0-4
for i := 0; i < 5; i++ {
// создаем компонент сервопривода с конкретной моделью как исполняемое устройство и получаем дескриптор сервопривода
errCode = C.RI_SDK_CreateModelComponent(C.CString("executor"), C.CString("servodrive"), C.CString("mg90s"), servos[i].descriptor, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//связываем сервопривод с ШИМ,передаем дескриптор сервопривода и ШИМ
errCode = C.RI_SDK_LinkServodriveToController(*servos[i].descriptor, robohand.pwm, C.int(i), &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
}

return nil
}

// initDevice - инициализация библиотеки и устройств
func initDevice() error {
var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)

// Инициализируем SDK
errCode = C.RI_SDK_InitSDK(logLevel, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
// создаем компонент ШИМ с конкретной моделью как соединитель и получаем дескриптор компонента
errCode = C.RI_SDK_CreateModelComponent(C.CString("connector"), C.CString("pwm"), C.CString("pca9685"), &robohand.pwm, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
// создаем компонент i2c адатера
// Здесь осуществлен примитивное определение подключенной модели адаптера
// Сначала пробуем создать i2c адаптер модели ch341 и связать с ним ШИМ
errCode = C.RI_SDK_CreateModelComponent(C.CString("connector"), C.CString("i2c_adapter"), C.CString("ch341"), &robohand.i2c, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//связываем i2c адаптер с ШИМ по адресу 0x40
errCode = C.RI_SDK_LinkPWMToController(robohand.pwm, robohand.i2c, 0x40, &errorTextC[0])
if errCode != 0 {
// Если не получается то пробуем создать i2c адаптер модели cp2112
errCode = C.RI_SDK_CreateModelComponent(C.CString("connector"), C.CString("i2c_adapter"), C.CString("cp2112"), &robohand.i2c, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//связываем i2c адаптер с ШИМ по адресу 0x40
errCode = C.RI_SDK_LinkPWMToController(robohand.pwm, robohand.i2c, 0x40, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
}
// создаем компонент светодиода с конкретной моделью (ky016) как исполняемое устройство и получаем дескриптор светодиода
errCode = C.RI_SDK_CreateModelComponent(C.CString("executor"), C.CString("led"), C.CString("ky016"), &robohand.led, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//связываем светодиод адаптер с ШИМ,передаем значения трех пинов к которым подключен светодиод
errCode = C.RI_SDK_LinkLedToController(robohand.led, robohand.pwm, 15, 14, 13, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}

//инициализируем сервоприводы
err := initServos()
if err != nil {
return err
}

return nil
}

// startPosition - переводит сервопривод в стартовое положение
func startPosition(s servo) error {
var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)
//выполняем поворот сервопривода в заданный угол,передаем дескриптор сервопривода,значение угла
errCode = C.RI_SDK_exec_ServoDrive_TurnByPulse(*s.descriptor, *s.startPosition, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}

//небольшая пауза для последовательного движения
time.Sleep(500 * time.Millisecond)
return nil
}

// startPositionAllServo - переводит все сервоприводы в стартовую позицию
func startPositionAllServo() error {
var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)

//выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errCode = C.RI_SDK_exec_RGB_LED_SinglePulse(robohand.led, 255, 0, 0, 0, true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}

//приводим сервоприводы в стартовое положение
for i := 0; i < 5; i++ {
err := startPosition(servos[i])
if err != nil {
return err
}
}

//выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errCode = C.RI_SDK_exec_RGB_LED_SinglePulse(robohand.led, 0, 255, 0, 0, true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//небольшая пауза для последовательного движения
time.Sleep(500 * time.Millisecond)
return nil
}

// rotateBody - вращение тела в указанный угол
func rotateBody(angle, speed C.int) error {

var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)
//выполняем мигание с заданной частотой,передаем дескриптор светодиода,3 параметра цвета(RGB),частоту,продолжительность и включаем асинхронный режим работы
errCode = C.RI_SDK_exec_RGB_LED_FlashingWithFrequency(robohand.led, 0, 255, 0, 5, 0, true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор тела,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.body, angle, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.clawRotate, C.int(45), speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.clawRotate, C.int(-45), speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
return nil
}

// get - берет кубик
func get() error {
var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)
//выполняем мерцание светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB),продолжительность,кол-во повторений и включаем асинхронный режим работы
errCode = C.RI_SDK_exec_RGB_LED_Flicker(robohand.led, C.int(0), C.int(0), C.int(255), C.int(500), C.int(0), true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowR, arrowR_over_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowL, arrowL_over_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.claw, claw_unclenched_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowR, (arrowR_cube_position - arrowR_over_cube_position), speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowL, (arrowL_cube_position - arrowL_over_cube_position), speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.claw, (-1)*claw_unclenched_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowR, (-1)*arrowR_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowL, (-1)*arrowL_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
return nil
}

// put - кладет кубик
func put() error {
var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)
//выполняем мерцание светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB),продолжительность,кол-во повторений и включаем асинхронный режим работы
errCode = C.RI_SDK_exec_RGB_LED_Flicker(robohand.led, C.int(0), C.int(0), C.int(255), C.int(500), C.int(0), true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowR, arrowR_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowL, arrowL_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.claw, claw_unclenched_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowR, (-1)*arrowR_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.arrowL, (-1)*arrowL_cube_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errCode = C.RI_SDK_exec_ServoDrive_Turn(robohand.claw, (-1)*claw_unclenched_position, speed, false, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}

return nil
}

// destructServos - уничтожает сервоприводы
func destructServos() error {
var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)
for i := 0; i < 5; i++ {
errCode = C.RI_SDK_DestroyComponent(*servos[i].descriptor, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
}

return nil
}

// destruct - уничтожает все компоненты и библиотеку
func destruct() error {

var (
errorTextC [1000]C.char //текст ошибки
errCode C.int //код ошибки
)

//выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errCode = C.RI_SDK_exec_RGB_LED_SinglePulse(robohand.led, C.int(255), C.int(0), C.int(0), C.int(0), true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//уничтожаем сервоприводы
err := destructServos()
if err != nil {
return err
}
//останавливаем свечение светодиода с определенным дескриптором
errCode = C.RI_SDK_exec_RGB_LED_Stop(robohand.led, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//удаляем компонент светодиода по дескриптору
errCode = C.RI_SDK_DestroyComponent(robohand.led, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//сбрасываем все порты на ШИМ
errCode = C.RI_SDK_sigmod_PWM_ResetAll(robohand.pwm, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//удаляем компонент ШИМ
errCode = C.RI_SDK_DestroyComponent(robohand.pwm, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//удаляем компонент i2c
errCode = C.RI_SDK_DestroyComponent(robohand.i2c, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
//удаляем sdk со всеми компонентами в реестре компонентов
errCode = C.RI_SDK_DestroySDK(true, &errorTextC[0])
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, C.GoString(&errorTextC[0]))
}
return nil
}

// start - запускает демо программу
func start() error {
// Инициализируем библиотеку и компоненты
err := initDevice()
if err != nil {
return err
}

// Приводим сервоприводы к стартовой позиции
err = startPositionAllServo()
if err != nil {
return err
}

// Двигаем тело к местонахождению кубика
err = rotateBody(45, speed)
if err != nil {
return err
}

// Берем кубик
err = get()
if err != nil {
return err
}

//Двигаем тело к новому местонахождению кубика
err = rotateBody(-90, speed)
if err != nil {
return err
}

//Кладем кубик
err = put()
if err != nil {
return err
}

// Возвращаем тело в стартовое положение
err = rotateBody(45, speed)
if err != nil {
return err
}

// Уничтожаем компоненты и библиотеку
err = destruct()
if err != nil {
return err
}
return nil
}

func main() {
//запускаем программу
err := start()
if err != nil {
fmt.Println(err.Error())
return
}

return
}

Подключение RI_SDK gRPC микросервиса к приложению на Golang

Создадим Golang файл и файл с для перечисления внешних зависимостей

type nul > grpc_client.go
type nul > go.mod

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

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

. workspace/
--- > grpc_client.go
--- > risdk.bin/.exe
--- > go.mod
--- > libusb-1.0.dll/.so

В файле go.mod укажем что мы будем использовать пакет go-risdk последней версии

module mod
go 1.17
require github.com/rbs-ri/go-risdk latest

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


package main

import (
"fmt"
"github.com/rbs-ri/go-risdk"
)

func main() {
//Открываем соединение для работы с API SDK по gRPC
client := risdk.GetClientRPC()
//Закрываем соединение с gRPC
defer client.Client.Kill()

// Инициализруем SDK
errorText, errorCode, err := client.RoboSdkApi.RI_SDK_InitSDK(2)
if errorCode != 0 || err != nil {
fmt.Printf("\n Не удалось инициализировать SDK. код ошибки:%d, описание:%s, ошибка:%s", errorCode, errorText, err)
return
}


// Создаем базовый компонент SDK
descriptor, errorText, errorCode, err := client.RoboSdkApi.RI_SDK_CreateBasic()
if errorCode != 0 || err != nil {
fmt.Printf("\n Не удалось создать базовый компонент. код ошибки:%d, описание:%s, ошибка:%s", errorCode, errorText, err)
return
}
fmt.Printf("Компонент с дескриптором:%d создан \n", descriptor)
}

Обновим зависимости внутри пакета

go mod tidy

Выполним компиляцию

go build -o grpc_client.bin grpc_client.go

Значение grpc_client.go указывает на файл, который необходимо собрать.
Значение -o grpc_client.bin указывает на путь к скомпиленному файлу.

Теперь запустим скрипт

./grpc_client.bin

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

Current path:  /home/mihail/Documents/projects_go/src/ri_sdk
2021-11-08T15:15:04.817+0400 [DEBUG] plugin: starting plugin: path=/home/mihail/Documents/projects_go/src/ri_sdk/risdk.bin args=[/home/mihail/Documents/projects_go/src/ri_sdk/risdk.bin]
2021-11-08T15:15:04.818+0400 [DEBUG] plugin: plugin started: path=/home/mihail/Documents/projects_go/src/ri_sdk/risdk.bin pid=9570
2021-11-08T15:15:04.818+0400 [DEBUG] plugin: waiting for RPC address: path=/home/mihail/Documents/projects_go/src/ri_sdk/risdk.bin
2021-11-08T15:15:04.823+0400 [DEBUG] plugin: using plugin: version=1
2021-11-08T15:15:04.823+0400 [DEBUG] plugin.risdk.bin: plugin address: address=/tmp/plugin1567377908 network=unix timestamp=2021-11-08T15:15:04.823+0400
2021-11-08T15:15:04.824+0400 [TRACE] plugin.stdio: waiting for stdio data
Компонент с дескриптором:1 создан
2021-11-08T15:15:04.827+0400 [DEBUG] plugin.stdio: received EOF, stopping recv loop: err="rpc error: code = Unavailable desc = transport is closing"
2021-11-08T15:15:04.827+0400 [DEBUG] plugin: plugin process exited: path=/home/mihail/Documents/projects_go/src/ri_sdk/risdk.bin pid=9570
2021-11-08T15:15:04.827+0400 [DEBUG] plugin: plugin exited

Пример программы на Golasng, использующий RI_SDK gRPC микросервис

Описание

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

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

. workspace/
--- > demo.go
--- > risdk.exe/.bin
--- > go.mod
--- > CH341DLL.DLL/ CH341DLLA64.DLL
--- > SLABHIDDevice.dll
--- > SLABHIDtoSMBus.dll
--- > libusb-1.0.dll/.so

Реализация

package main

import (
"fmt"
"time"

"github.com/rbs-ri/go-risdk"
)

var (
body_start_pulse int64 = 1500// стартовая позиция тела
arrowR_start_pulse int64 = 2000 // стартовая возиция правой стрелы
arrowL_start_pulse int64 = 1000 // стартовая позиция левой стрелы
claw_start_pulse int64 = 1000 // стартовая позиция клешни
claw_rotate_start_pulse int64 = 1500 // стартовая позиция поворота клешни

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

logLevel int64 = 2 // уровень логирования
speed int64 = 100 // скорость в градусах в секунду
client *risdk.ClientRPC // клиент
)

// структура дескрипторов устройства
type device struct {
i2c int64 // дескриптор i2c
pwm int64 // дескриптор pwm
body int64 // дескриптор сервопривода тела
claw int64 // дескриптор сервопривода клешни
arrowR int64 // дескриптор сервопривода правой стрелы
arrowL int64 // дескриптор сервопривода левой стрелы
clawRotate int64 // дескриптор сервопривода поворота клешни
led int64 // дескриптор светодиода
}

// инициализация структуры устройства
var robohand device

type servo struct {
descriptor *int64 // дескриптор сервопривода
startPosition *int64 // стартовая позиция сервопривода
}

// массив дескрипторов сервоприводов
var servos = [5]servo{
{
descriptor: &robohand.body,
startPosition: &body_start_pulse,
},
{
descriptor: &robohand.claw,
startPosition: &claw_start_pulse,
},
{
descriptor: &robohand.arrowR,
startPosition: &arrowR_start_pulse,
},
{
descriptor: &robohand.arrowL,
startPosition: &arrowL_start_pulse,
},
{
descriptor: &robohand.clawRotate,
startPosition: &claw_rotate_start_pulse,
},
}

// initServos - создает сервоприводы и линкует их
func initServos() error {
var (
errorText string // текст ошибки. Передается как входной параметр,при возникновении ошибки в эту переменную будет записан текст ошибки
errCode int64 // код ошибки
)
//создаем 5 сервоприводов и линкуем их к пинам 0-4
for i := 0; i < 5; i++ {
// создаем компонент сервопривода с конкретной моделью как исполняемое устройство и получаем дескриптор сервопривода
*servos[i].descriptor, errorText, errCode, _ = client.RoboSdkApi.RI_SDK_CreateModelComponent("executor", "servodrive", "mg90s")
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//связываем сервопривод с ШИМ,передаем дескрипторы сервопривода и ШИМ
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_LinkServodriveToController(*servos[i].descriptor, robohand.pwm, int64(i))
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
}

return nil
}

// initDevice - инициализация библиотеки и устройств
func initDevice() error {
var (
errorText string //текст ошибки
errCode int64 //код ошибки
err error //ошибка
)

// Инициализируем SDK
errorText, errCode, err = client.RoboSdkApi.RI_SDK_InitSDK(logLevel)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
// создаем компонент ШИМ с конкретной моделью как соединитель и получаем дескриптор компонента
robohand.pwm, errorText, errCode, err = client.RoboSdkApi.RI_SDK_CreateModelComponent("connector", "pwm", "pca9685")
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
// создаем компонент i2c адатера
// Здесь осуществлен примитивное определение подключенной модели адаптера
// Сначала пробуем создать i2c адаптер модели ch341 и связать с ним ШИМ
robohand.i2c, errorText, errCode, err = client.RoboSdkApi.RI_SDK_CreateModelComponent("connector", "i2c_adapter", "ch341")
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}

//связываем i2c адаптер с ШИМ по адресу 0x40
errorText, errCode, err = client.RoboSdkApi.RI_SDK_LinkPWMToController(robohand.pwm, robohand.i2c, 0x40)
if errCode != 0 {
// Если не получается то пробуем создать i2c адаптер модели cp2112
robohand.i2c, errorText, errCode, err = client.RoboSdkApi.RI_SDK_CreateModelComponent("connector", "i2c_adapter", "cp2112")
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}

//связываем i2c адаптер с ШИМ по адресу 0x40
errorText, errCode, err = client.RoboSdkApi.RI_SDK_LinkPWMToController(robohand.pwm, robohand.i2c, 0x40)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
}
// создаем компонент светодиода с конкретной моделью (ky016) как исполняемое устройство и получаем дескриптор светодиода
robohand.led, errorText, errCode, err = client.RoboSdkApi.RI_SDK_CreateModelComponent("executor", "led", "ky016")
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//связываем светодиод адаптер с ШИМ,передаем значения трех пинов к которым подключен светодиод
errorText, errCode, err = client.RoboSdkApi.RI_SDK_LinkLedToController(robohand.led, robohand.pwm, 15, 14, 13)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//инициализируем сервоприводы
err = initServos()
if err != nil {
return err
}

return nil
}

// startPosition - переводит сервопривод в стартовое положение
func startPosition(s servo) error {
var (
errorText string
errCode int64
)
//выполняем поворот сервопривода в заданный угол,передаем дескриптор сервопривода,значение угла
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_TurnByPulse(*s.descriptor, *s.startPosition)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}

time.Sleep(500 * time.Millisecond)
return nil
}

// startPositionAllServo - переводит все сервоприводы в стартовую позицию
func startPositionAllServo() error {
var (
errorText string //текст ошибки
errCode int64 //код ошибки
)
//выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_SinglePulse(robohand.led, 255, 0, 0, 0, true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//приводим сервоприводы в стартовое положение
for i := 0; i < 5; i++ {
err := startPosition(servos[i])
if err != nil {
return err
}
}
//выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_SinglePulse(robohand.led, 0, 255, 0, 0, true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//небольшая пауза для последовательного движения
time.Sleep(500 * time.Millisecond)
return nil
}

// rotateBody - вращение тела в указанный угол
func rotateBody(angle, speed int64) error {
var (
errorText string //текст ошибки
errCode int64 //код ошибки
)
//выполняем мигание с заданной частотой,передаем дескриптор светодиода,3 параметра цвета(RGB),частоту,продолжительность и включаем асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_FlashingWithFrequency(robohand.led, 0, 255, 0, 5, 0, true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор тела,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.body, angle, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.clawRotate, 45, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.clawRotate, -45, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
return nil
}

// get - берет кубик
func get() error {
var (
errorText string //текст ошибки
errCode int64 //код ошибки
)
//выполняем мерцание светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB),продолжительность,кол-во повторений и включаем асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_Flicker(robohand.led, 0, 0, 255, 500, 0, true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowR, arrowR_over_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowL, arrowL_over_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.claw, claw_unclenched_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowR, (arrowR_cube_position - arrowR_over_cube_position), speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowL, (arrowL_cube_position - arrowL_over_cube_position), speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.claw, (-1)*claw_unclenched_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowR, (-1)*arrowR_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowL, (-1)*arrowL_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}

return nil
}

// put - кладет кубик
func put() error {
var (
errorText string //текст ошибки
errCode int64 //код ошибки
)

//выполняем мерцание светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB),продолжительность,кол-во повторений и включаем асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_Flicker(robohand.led, 0, 0, 255, 500, 0, true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowR, arrowR_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowL, arrowL_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.claw, claw_unclenched_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowR, (-1)*arrowR_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор стрелы,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.arrowL, (-1)*arrowL_cube_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//выполняем поворот на заданный угол,передаем дескриптор клешни,угол,скорость и асинхронный режим работы
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_Exec_ServoDrive_Turn(robohand.claw, (-1)*claw_unclenched_position, speed, false)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}

return nil
}

// destructServos - уничтожает сервоприводы
func destructServos() error {
var (
errorText string //текст ошибки
errCode int64 //код ошибки
)

for i := 0; i < 5; i++ {
errorText, errCode, _ = client.RoboSdkApi.RI_SDK_DestroyComponent(*servos[i].descriptor)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
}

return nil
}

// destruct - уничтожает все компоненты и библиотеку
func destruct() error {

var (
errorText string //текст ошибки
errCode int64 //код ошибки
err error
)
//выполняем одиночное свечение светодиодом,передаем дескриптор светодиода,3 параметра цвета(RGB), и включаем асинхронный режим работы
errorText, errCode, err = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_SinglePulse(robohand.led, 255, 0, 0, 0, true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//уничтожаем сервоприводы
err = destructServos()
if err != nil {
return err
}
//останавливаем свечение светодиода с определенным дескриптором
errorText, errCode, err = client.RoboSdkApi.RI_SDK_Exec_RGB_LED_Stop(robohand.led)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//удаляем компонент светодиода по дескриптору
errorText, errCode, err = client.RoboSdkApi.RI_SDK_DestroyComponent(robohand.led)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//сбрасываем все порты на ШИМ
errorText, errCode, err = client.RoboSdkApi.RI_SDK_Sigmod_PWM_ResetAll(robohand.pwm)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//удаляем компонент ШИМ
errorText, errCode, err = client.RoboSdkApi.RI_SDK_DestroyComponent(robohand.pwm)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//удаляем компонент i2c
errorText, errCode, err = client.RoboSdkApi.RI_SDK_DestroyComponent(robohand.i2c)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}
//удаляем sdk со всеми компонентами в реестре компонентов
errorText, errCode, err = client.RoboSdkApi.RI_SDK_DestroySDK(true)
if errCode != 0 {
return fmt.Errorf("errorCode:%d - errorText:%s", errCode, errorText)
}

return nil
}

// start - запускает демо программу
func start() error {
// Инициализируем библиотеку и компоненты
err := initDevice()
if err != nil {
return err
}

// Приводим сервоприводы к стартовой позиции
err = startPositionAllServo()
if err != nil {
return err
}

// Двигаем тело к местонахождению кубика
err = rotateBody(45, speed)
if err != nil {
return err
}

// Берем кубик
err = get()
if err != nil {
return err
}

//Двигаем тело к новому местонахождению кубика
err = rotateBody(-90, speed)
if err != nil {
return err
}

//Кладем кубик
err = put()
if err != nil {
return err
}

// Возвращаем тело в стартовое положение
err = rotateBody(45, speed)
if err != nil {
return err
}

// Уничтожаем компоненты и библиотеку
err = destruct()
if err != nil {
return err
}
return nil
}

func main() {
//Открываем соединение для работы с API SDK по RPC
client = risdk.GetClientRPC()
//Закрываем соединение с RPC
defer client.Client.Kill()
//запускаем программу
err := start()
if err != nil {
fmt.Println(err.Error())
return
}

return
}