Взяв за основу код примера 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