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-ку можно по ссылке:
http://robocraft.ru/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
  • 0
  • 15 марта 2011, 10:54
  • noonv

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.