URBI — UObject — пишем Urbi-драйвер для управления сервомашинкой через Arduino



Взяв за основу код примера MyAdder напишем код класса ArServo, для управления сервомашинкой, подключённой к Arduino.
Управление осуществляется через последовательный порт, по протоколу Firmata.

//
// пример объекта Urbi
//
#include <urbi/uobject.hh>

#include "serial/serial.h"

class ArServo: public urbi::UObject
{
public:
	// конструктор
	ArServo(const std::string& str);
	~ArServo();
	int init();

	// переменные 
	urbi::UVar val; 
	urbi::UVar pin;

	Serial sg;

	// методы
	int port(int port, int rate);
	double set(int angle); 
};


// конструктор - определяем достпные из Urbi переменные и функции
ArServo::ArServo(const std::string& s)
: urbi::UObject(s)  // required 
{
	// доступ к пременным
	UBindVar (ArServo, val); 
	UBindVar (ArServo, pin);

	//  доступ к функциям
	UBindFunction (ArServo, port);
	UBindFunction (ArServo, set); 

	UBindFunction(ArServo, init);
};

ArServo::~ArServo()
{
	if(sg.IsConnected()){
		sg.Close();
	}
};

int ArServo::init()
{
	pin=0;
	return 0;
};
// открываем порт
int ArServo::port(int port, int rate=9600)
{
	bool b = sg.Open(port, rate);
	if(!b){
		printf("[!] Error: cant open COM-port!\n");
		return 1;
	}
	printf("[i] ok\n");
	return 0;
};
// пакет Firmata
double 
ArServo::set (int angle) 
{
	if(!sg.IsConnected()){
		printf("[!] Error: open COM-port first!\n");
		return 0;
	}
	char buf[3];
	buf[0] = 0xE0 | (int)pin;
	buf[1] = angle & 0x7F;
	buf[2] = (angle >> 7) & 0x7F;
	sg.Send(buf, 3);
	Sleep(100);
	val=angle;
	return angle; 
};
// загружаем объект
UStart(ArServo);

Скачать исходный код примера и готовую dll-ку можно по ссылке:
/files/urbi/uobject1-arservo.zip

Т.е. нужно открыть последовательный порт ардуины, затем указать пин, к которому подключена серва и можно будет рулить сервой через функцию set().

подгрузим получившуюся библиотеку:

С:\Program Files\Gostai Engine Runtime\bin\urbi-launch.exe -r "G:\Documents and Settings\ArServo.dll"

а теперь попробуем поуправлять:

=> var servo = ArServo.new;
#[0000029433] object_10
=> servo.localSlotNames;
#[0000035572] ["init", "set", "port", "pin_quote_n", "pin", "val_quote_n", "val", "__uobjectName", "isRemote", "updateTask", "remoteEventMap", "handle", "timerTask", "asobject_10", "type", "lobby", "notifies", "clone", "load", "load_quote_n", "getProperty", "__has_uvar", "update"]
=> servo.port(1);
#[0000044614:error] !!! 1.490-502: Remote bound function: expected 2 arguments, given 1
#[0000044614:error] !!! called from: 1.490-502: port
=> servo.port(1, 9600);
#[0000051745] 0
=> servo.pin=7;
#[0000061164] 7
=> servo.set(0);
#[0000069594] 0
=> servo.set(45);
#[0000076267] 45
=> servo.set(90);
#[0000080437] 90

А вот какой скетч нужно загрузить в Arduino/CraftDuino (фактически — это немного модифицированный пример, поставляемый с библиотекой Firmata).
Данный скетч позволяет по протоколу Firmata управлять двумя сервомашинками, подключёнными к 7 и 8 цифровым портам контроллера Arduino/CraftDuino.

#include <Firmata.h>
#include <Servo.h>

Servo servo7; // объекты класса Servo 
Servo servo8; // для работы с сервомашинками

// функция обрабатывающая аналоговые сообщения Firmata
void analogWriteCallback(byte pin, int value)
{
    if(pin == 7)
      servo7.write(value); // поворачиваем серву на угол value
    if(pin == 8)
      servo8.write(value);
}

void setup() 
{
    // устанавливаем версию протокола
    Firmata.setFirmwareVersion(0, 2);
    // задание функции-обработчика аналоговых сообщений
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

    servo7.attach(7); // указываем порт подключения сервы 
    servo8.attach(8);
   
    Firmata.begin(9600); // инициализация библиотеки Firmata
}

void loop() 
{
    while(Firmata.available())  // если есть сообщения
        Firmata.processInput(); // запускаем функции-обработчики
}

Однако, произодить инициализацию можно и нужно через конструктор.
В urbiScript такую роль выполняет функция init().

т.е. задав функцию инициализации в виде:

int init(int port, int rate);

можем написать:

int ArFirmata::init(int port, int rate)
{
	pin=0;
	return open(port, rate);
};
// открываем порт
int ArFirmata::open(int port, int rate=9600)
{
	bool b = sg.Open(port, rate);
	if(!b){
		printf("[!] Error: cant open COM-port %d with rate %d!\n", port, rate);
		return 1;
	}
	printf("[i] ok\n");
	return 0;
};

и тогда порт будет открываться при создании нового объекта:

var firmata = ArFirmata.new(1, 9600);

Далее: обёртка UObject


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение