Copyright © 2006 Gostai
This document is released under the Attribution-NonCommercial-NoDerivs 2.0 Creative Commons licence (http://creativecommons.org/licenses/by-nc-nd/2.0/deed.en).
Table of Contents
Liburbi-c++ est une librairie conçue pour encapsuler une connection URBI. Elle gère la connection TCP avec le serveur URBI, et la répartition des messages qu'il envoi. La librairie est thread-safe et réentrante.
La librairie est constituée de deux classes C++, UClient et
USyncClient, et quelques fonctions utiles.
Nous supposons que le lecteur est un peu au courant de la syntaxe d'URBI.
Pour se connecter à un serveur URBI, il suffit simplement de créer une nouvelle instance UClient
(ou USyncClient si vous voulez utiliser les fonctions de synchronisation décrites plus bas),
en passant comme premier paramètre le nom ou l'adresse du serveur, et en option le port comme deuxième paramètre:
UClient * client = new UClient("myrobot.ensta.fr");
//a wrapper is also available in the urbi namespace:
UClient * client = urbi::connect("myrobot.ensta.fr");
Le créateur démarrera un thread indépendant qui sera à l'écoute de messages provenant du serveur URBI.
Vous pouvez vérifier si la connection a été établie avec succès en appellant la fonction error,
qui retourne la valeur zero en cas de succès, ou un code erreur nonzero en cas de défaut.
La méthode send est la manière la plus simple d'envoyer
une commande au serveur URBI. Elle accepte une syntaxe similaire à la fonction printf.
Pour envoyer une séquence de commandes sans risque d'avoir un autre thread qui envoi des commandes en même temps,
vous pouvez utiliser les méthodes lockSend et unlockSend pour verrouiller
puis déverrouiller le buffer (tampon) d'envoi.
int sleeptime = 50;
client->send("motoron;");
client->lockSend(); //send() appelé par d'autres threads sera bloqué
//à ce point point jusqu'au prochain appel de unlockSend
for (float val=0; val<=1; val+=0.05)
client->send("neck.val = %f;wait (%d);", val, sleeptime);
client->unlockSend();
Alternativement, la classe UClient hérite de l'ostreaam, aussi vous pouvez utiliser l'opérateur <<:
client << "headPan.val = " <<12 << urbi::comma;
Les constantes 'comma', 'semicolon', 'pipe' et 'parallel' sont définis respectivement par ',', ';', '|' and '&' dans le namespace d'urbi.
Une troisième voie possible est d'utiliser la macro URBI, qui utilise la connection par défaut
(la première connection créée avec votre programme):
URBI((
headPan.val = 12 ,
echo "coucou" | speaker.play("test.wav") & leds.val = 1
));
//notez l'absence des doubles quotes pour délimiter le code URBI
//les double-parenthèses sont requises
URBI() << "headPan.val = " << 12 << urbi::semicolon;
La fonction urbi::setDefaultClientUClient *cl) peut être utilisée pour changer le client par défaut.
Pour envoyer des données binaires au robot, la méthode sendBin doit être utilisée.
Elle prend comme paramètres le buffer d'envoi et sa taille, et en option une en-tête.
client->sendBin(soundData, soundDataSize,"speaker.val = BIN %d raw 2 16000 16 1;", soundDataSize);
De même vous pouvez utiliser sendBin pour faire jouer un son au robot,
une méthode spécifique et efficace a été écrite pour cette utilisation: sendSound.
client->sendSound(sound, "endsound");
Le premier paramètre est une structure USound décrivant le son a envoyer. Le second est un tag qui sera utilisé
par le serveur pour signifier un message sytème "stop" quand le son aura fini d'être joué. La fonction convert
peut être utilisée pour convertir entre différents formats de sons.
Il n'y a pas de limite à la taille du buffer de son, celui-ci étant automatiquement découpé en petits tronçons par la librairie. les données sont copiées par la librairie: le paramètre USound et ses données associées peuvent être sans risque libérées dés le retour de la fonction .
La plupart des messages reçus du serveur URBI sont le résultat d'une commande précédement envoyée.
Le mécanisme des tags URBI autorise de lier un message à sa réponse: à chaque commande est associée un tag,
et ce tag est répété dans le message de réponse. Les class UClient gèrent la réception
de ces messages dans le thread indépendant créé par le créateur, les analyses et remplis une structure UMessage.
Les retours de fonctions avec un tag associé peuvent être enregistrés avec la méthode
registerCallback: chaque fois qu'un message avec ce tag est envoyé par le serveur,
la fonction callback sera appelée avec une structure UMessage comme paramètre. Les deux formes de base de
registerCallback sont:
typedef UCallbackAction (*UCallback) (const UMessage &msg); typedef UCallbackAction (*UCustomCallback) (void * callbackData, const UMessage &msg); UCallbackID setCallback (UCallback cb, const char *tag) UCallbackID setCallback (UCustomCallback cb, void *callbackData, const char *tag)
le premier paramètre est toujours un pointeur vers la fonction à appeler. callbackData est un pointeur qui sera retourné à la fonction callback chaque fois quelle est appelée. La fonction callback doit retourner URBI_CONTINUE, ou URBI_REMOVE, dans ce cas la fonction ne sera pas enregistrée.
Quelques exemples:
UCallbackAction onImage(const UMessage &msg) {
//Test si quelqu'un a utilisé votre tag ou si un message d'erreur a été reçu
if (msg.type != MESSAGE_DATA || ((UImage)msg).imageFormat == IMAGE_UNKNOWN)
return URBI_CONTINUE;
UImage img = (UImage)msg;
msg.client.printf("Image of size (%d,%d) received from server at %d\n",img.width, img.height, msg.timestamp);
unsigned char *image = new unsigned char[img.width*img.height*3];
int sz = img.width*img.height*3;
if (img.imageFormat == IMAGE_JPEG)
convertJPEGtoRGB((const byte *) img.data, img.size, (byte *) image, sz); //provided by liburbi
if (img.imageFormat == IMAGE_YCbCr)
convertYCrCbtoRGB((const byte *) img.data, img.size, (byte *) image); //provided by liburbi
myDisplayRGBImage(image, img.width, img.height);
delete image;
return URBI_CONTINUE;
}
UCallbackAction onSound(const UMessage &msg) {
if (msg.type != MESSAGE_DATA || USound(msg).soundFormat == SOUND_UNKNOWN)
return URBI_CONTINUE;
//convert the sound to a wav 16KHz 16bit.
USound snd;
snd.soundFormat = SOUND_WAV;
snd.rate = 16000;
snd.sampleSize = 16;
snd.sampleFormat = SAMPLE_SIGNED;
snd.channels = 0; //take the value from source
snd.data = 0;
snd.size = 0;
convert((USound)msg, snd); //Cette fonction est fournie par liburbi
myPlayWAV(snd.data, snd.size);
return URBI_CONTINUE;
}
UCallbackAction onJoint(const UMessage &msg) {
if (msg.type != MESSAGE_DATA || ((UValue)msg).type != DATA_DOUBLE)
return URBI_CONTINUE;
msg.client.printf("The joint value si %lf\n", UValue(msg).val);
return URBI_CONTINUE;
}
int main(int argc, const char * argv[]) {
UClient * cl = new UClient(argv[1]);
if (cl->error()) urbi::exit(1); //portability call explaned below
cl->setCallback(&onImage, "img");
cl->setCallback(&onSound, "snd");
cl->setCallback(&onJoint, "joint");
cl->send("img: camera.val;");
cl->send("loop snd: micro.val,");
cl->send("joint: headPan.val;");
urbi::execute(); //portability call explaned below
}
The UMessage structure is capable of storing the informations contained in any kind of URBI message by using a "type" field and an UValue (union of type-dependant structures). These two structures are defined as follows:
Les versions template de registerCallback sont définies aussi.
Elles permettent de régler callbacks sur les fonctions des membres, avec des paramètres
personnels de 0 à 4 de tout types (incluant pointeurs et références). La seule contrainte
sur la signature de fonction est quelle doit renvoyer un UCallbackAction,
et prendre une const UMessage& comme dernier paramètre. Quelques exemples:
class Test {
public:
UCallbackAction onJoint(int value, const UMessage &msg);
}:
UCallbackAction Test::onJoint(int value, const UMessage &msg) {
msg.client.printf("got a message at %d with tag %s, our int is %d\n",msg.timestamp, msg.tag, value);
return URBI_REMOVE; //unregister ourself
}
int main(int argc, const char * argv[]) {
Test *a = new Test();
UClient * cl= new UClient(argv[1]);
if (cl->error()) urbi::exit(1);
cl->setCallback(*a, &Test::onJoint, 12, "tag");
cl->send("tag: headPan.val;");
urbi::execute();
}
Table of Contents
La classe dérivée USyncClient implemente des méthodes pour
récupérer de façon synchrone le résultat des commandes URBI. Vous devez être prévenu
que ces fonctions sont moins efficaces, et quelles sont moins facilement portable.
Pour lire la valeur d'un périphérique, vous pouvez utiliser la méthode syncGetDevice ou
syncGetNormalizedDevice. Le premier paramètre est le nom du périphérique (par exemple, "neck"),
le second est un double qui doit être remplit avec la valeur reçue. La différence entre les deux méthodes est que
syncGetDevice retrouve la valeur avec une commande "val",
en considérant que syncGetNormalizedDevice utilise "valn" (voir
urbidoc.html pour plus de détails à propos de "val" et "valn").
double neckVal;
syncClient->syncGetDevice("neck",neckVal):
Vous pouvez utiliser la méthode syncGetImage pour récupérer une image de façon synchrone.
La méthode enverra la commande appropriée, et attendra le résultat, donc elle bloquera votre thread en attendant que
l'image soit reçue.
client->send("camera.resolution = 0;camera.gain = 2;");
int width, height;
client->syncGetImage("camera", myBuffer, myBufferSize, IMAGE_JPEG, URBI_TRANSMIT_JPEG, width, height);
Le premier paramètre est le nom de la camera. Le second est le buffer (void*) qui sera rempli avec les données de l'image. Le troisième devra être une variable nombre entier égale à la taille du buffer. La fonction règlera cette variable à la taille des données. Si le buffer est trop petit, les données seront tronçonnées.
Le quatrième paramètre est le format dans lequel vous voulez recevoir les données de l'image. Les valeurs possibles sont IMAGE_RGB pour une image raw RGB 24 bit par pixel, IMAGE_PPM pour une PPM file, IMAGE_YCbCr pour raw YCbCr data, et IMAGE_JPEG pour un fichier jpeg-compressed.
Le cinquième paramètre peut être l'un ou l'autre URBI_TRANSMIT_JPEG ou URBI_TRANSMIT_YCbCR et spécifier comment l'image doit être transmise entre le robot et le client. Transmettre des images JPEG augmente le frame rate et devra être utilisé pour de meilleurs performances.
Finalement les paramètres de largeur et de hauteur sont remplit avec la largeur et la hauteur de l'image en retour.
La méthode syncGetSound peut être utilisée pour recevoir des données sonores de toute longueur venant du serveur.
client->syncGetSound("micro", duration, sound);
Le premier paramètre est le nom du périphérique duquel on obtient le son, la seconde est la durée demandée, en millisecondes. Sound est une structure USound qui sera remplit avec le son enregistré sur la sortie.
Nous avons aussi inclus quelques fonctions de conversion pour différents formats d'images et de sons. L'utilisation des fonctions de conversion d'image est trés claire:
int convertRGBtoYCrCb(const byte* source, int sourcelen, byte* dest); int convertYCrCbtoRGB(const byte* source, int sourcelen, byte* dest); int convertJPEGtoYCrCb(const byte* source, int sourcelen, byte* dest, int &size); int convertJPEGtoRGB(const byte* source, int sourcelen, byte* dest, int &size);
Le paramètre size devra être réglé à la taille du buffer d'arrivée. En retour, il sera réglé
à la taille du son en sortie.
Pour convertir des sons de différents formats, la fonction convert peut être utilisée.
Elle prend deux structures USound comme paramètres. Les deux formats audio supportés sont SOUND_RAW
et SOUND_WAV, mais la compatibilité avec des formats de sons compressés comme Ogg Vorbis et MP3 est prévue.
Si chacun des champs est mis à zero dans la structure d'arrivée, les valeurs correspondantes du son de départ seront utilisées.
Jetez un oeil aux exemples, Dans les répertoires "example" ou "utils" donnés avec liburbi. vous pouvez trouver:
urbiimage: Affiche les images prises par la caméra en temps réel, ou sauve un instantané dans un fichier.
urbisound: Joue le son venant du microphone du robot sur le haut-parleur de l'ordinateur, ou l'enregistre dans un fichier.
urbisendsound: Joue un fichier wav venant de l'ordinateur, sur le robot, en le convertissant si nécessaire.
urbiping: Envoie la commande URBI 'ping' à intervalles réguliers pour mesurer la latence.
urbibandwidth: Mesure la largeur de bande (bandwidth.) effective.
urbisend: Envoie un ensemble de commandes contenues dans un fichier au robot.
urbirecord: Enregistre tous les mouvements d'un robot dans un fichier.
urbiplay: Joue un fichier enregistré avec urbirecord, ou le met sous une forme lisible.
urbimirror: Copie les mouvements d'un robot dans un autre robot. Comme en reliant urbirecord à urbiplay, mais avec moins de latence.
urbiscale: Change la vitesse d'un fichier enregistré avec urbirecord.
urbireverse: Inverse un fichier enregistré avec urbirecord.
urbicycle: Detecte et extrait les cycles dans un fichier enregistré avec urbirecord.
urbiballtrackinghead: Portage de l'exemple OPEN-R ballTrackingHead vers URBI.
Chaque programme s'il est lancé sans option affichera sa ligne de commande et des informations additionnelles si besoin.
Sauf si ce que vous faites est insignifiant, essayez de ne pas utiliser les fonctions sync*. Elles sont moins efficaces que les asynchrones.
les retours de fonctions devront se faire le plus rapidement possible, les retours dépendant tous du même thread. Si vous avez des opérations gourmandes en temps, vous devriez créer un nouveau thread et utiliser des mécanismes de synchronisation comme des sémaphores ou des mutexes.
Quand d'autres version de liburbi seront disponibles, (en particulier une version avec OPEN-R qui l'autorisera à tourner sur le robot), il sera posible de compiler le même code pour les deux librairies, si quelques règles sont respectées:
N'utilisez pas USyncClient.
Utilisez la méthode de UClient printf au lieu de la version standard.
Utilisez la méthode de UClient getCurrentTime au lieu des fonctions de stdlib.
Utilisez la fonction urbi::exit (dans le "urbi" namespace) au lieu d'exit.
A la fin de votre main, appellez urbi::execute.
N'utilisez pas de thread, ou toute autre fonction qui n'est pas implémentée dans la version OPEN-R de stdlib.
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE
TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR
"LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE
LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE
OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS
YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF
SUCH TERMS AND CONDITIONS.
1. Definitions
1. "Collective Work" means a work, such as a periodical issue,
anthology or encyclopedia, in which the Work in its entirety in
unmodified form, along with a number of other contributions,
constituting separate and independent works in themselves, are
assembled into a collective whole. A work that constitutes a
Collective Work will not be considered a Derivative Work (as
defined below) for the purposes of this License. 2. "Derivative
Work" means a work based upon the Work or upon the Work and other
pre-existing works, such as a translation, musical arrangement,
dramatization, fictionalization, motion picture version, sound
recording, art reproduction, abridgment, condensation, or any other
form in which the Work may be recast, transformed, or adapted,
except that a work that constitutes a Collective Work will not be
considered a Derivative Work for the purpose of this License. For
the avoidance of doubt, where the Work is a musical composition or
sound recording, the synchronization of the Work in timed-relation
with a moving image ("synching") will be considered a Derivative
Work for the purpose of this License. 3. "Licensor" means the
individual or entity that offers the Work under the terms of this
License. 4. "Original Author" means the individual or entity who
created the Work. 5. "Work" means the copyrightable work of
authorship offered under the terms of this License. 6. "You" means
an individual or entity exercising rights under this License who
has not previously violated the terms of this License with respect
to the Work, or who has received express permission from the
Licensor to exercise rights under this License despite a previous
violation.
2. Fair Use Rights. Nothing in this license is intended to reduce,
limit, or restrict any rights arising from fair use, first sale or
other limitations on the exclusive rights of the copyright owner under
copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License,
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
perpetual (for the duration of the applicable copyright) license to
exercise the rights in the Work as stated below:
1. to reproduce the Work, to incorporate the Work into one or more
Collective Works, and to reproduce the Work as incorporated in the
Collective Works; 2. to distribute copies or phonorecords of,
display publicly, perform publicly, and perform publicly by means
of a digital audio transmission the Work including as incorporated
in Collective Works;
The above rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right to make
such modifications as are technically necessary to exercise the rights
in other media and formats, but otherwise you have no rights to make
Derivative Works. All rights not expressly granted by Licensor are
hereby reserved, including but not limited to the rights set forth in
Sections 4(d) and 4(e).
4. Restrictions.The license granted in Section 3 above is expressly
made subject to and limited by the following restrictions:
1. You may distribute, publicly display, publicly perform, or
publicly digitally perform the Work only under the terms of this
License, and You must include a copy of, or the Uniform Resource
Identifier for, this License with every copy or phonorecord of the
Work You distribute, publicly display, publicly perform, or
publicly digitally perform. You may not offer or impose any terms
on the Work that alter or restrict the terms of this License or the
recipients' exercise of the rights granted hereunder. You may not
sublicense the Work. You must keep intact all notices that refer to
this License and to the disclaimer of warranties. You may not
distribute, publicly display, publicly perform, or publicly
digitally perform the Work with any technological measures that
control access or use of the Work in a manner inconsistent with the
terms of this License Agreement. The above applies to the Work as
incorporated in a Collective Work, but this does not require the
Collective Work apart from the Work itself to be made subject to
the terms of this License. If You create a Collective Work, upon
notice from any Licensor You must, to the extent practicable,
remove from the Collective Work any reference to such Licensor or
the Original Author, as requested. 2. You may not exercise any of
the rights granted to You in Section 3 above in any manner that is
primarily intended for or directed toward commercial advantage or
private monetary compensation. The exchange of the Work for other
copyrighted works by means of digital file-sharing or otherwise
shall not be considered to be intended for or directed toward
commercial advantage or private monetary compensation, provided
there is no payment of any monetary compensation in connection with
the exchange of copyrighted works. 3. If you distribute, publicly
display, publicly perform, or publicly digitally perform the Work,
You must keep intact all copyright notices for the Work and give
the Original Author credit reasonable to the medium or means You
are utilizing by conveying the name (or pseudonym if applicable) of
the Original Author if supplied; the title of the Work if supplied;
and to the extent reasonably practicable, the Uniform Resource
Identifier, if any, that Licensor specifies to be associated with
the Work, unless such URI does not refer to the copyright notice or
licensing information for the Work. Such credit may be implemented
in any reasonable manner; provided, however, that in the case of a
Collective Work, at a minimum such credit will appear where any
other comparable authorship credit appears and in a manner at least
as prominent as such other comparable authorship credit. 4.
For the avoidance of doubt, where the Work is a musical
composition: 1. Performance Royalties Under Blanket
Licenses. Licensor reserves the exclusive right to collect,
whether individually or via a performance rights society
(e.g. ASCAP, BMI, SESAC), royalties for the public
performance or public digital performance (e.g. webcast) of
the Work if that performance is primarily intended for or
directed toward commercial advantage or private monetary
compensation. 2. Mechanical Rights and Statutory
Royalties. Licensor reserves the exclusive right to collect,
whether individually or via a music rights agency or
designated agent (e.g. Harry Fox Agency), royalties for any
phonorecord You create from the Work ("cover version") and
distribute, subject to the compulsory license created by 17
USC Section 115 of the US Copyright Act (or the equivalent in
other jurisdictions), if Your distribution of such cover
version is primarily intended for or directed toward
commercial advantage or private monetary compensation.
5. Webcasting Rights and Statutory Royalties. For the
avoidance of doubt, where the Work is a sound recording,
Licensor reserves the exclusive right to collect, whether
individually or via a performance-rights society
(e.g. SoundExchange), royalties for the public digital
performance (e.g. webcast) of the Work, subject to the
compulsory license created by 17 USC Section 114 of the US
Copyright Act (or the equivalent in other jurisdictions), if
Your public digital performance is primarily intended for or
directed toward commercial advantage or private monetary
compensation.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR
OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE,
MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR
THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF
ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO
NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY
NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY
APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY
LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR
EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,
EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
1. This License and the rights granted hereunder will terminate
automatically upon any breach by You of the terms of this
License. Individuals or entities who have received Collective Works
from You under this License, however, will not have their licenses
terminated provided such individuals or entities remain in full
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
survive any termination of this License. 2. Subject to the above
terms and conditions, the license granted here is perpetual (for
the duration of the applicable copyright in the
Work). Notwithstanding the above, Licensor reserves the right to
release the Work under different license terms or to stop
distributing the Work at any time; provided, however that any such
election will not serve to withdraw this License (or any other
license that has been, or is required to be, granted under the
terms of this License), and this License will continue in full
force and effect unless terminated as stated above.
8. Miscellaneous
1. Each time You distribute or publicly digitally perform the Work
or a Collective Work, the Licensor offers to the recipient a
license to the Work on the same terms and conditions as the license
granted to You under this License. 2. If any provision of this
License is invalid or unenforceable under applicable law, it shall
not affect the validity or enforceability of the remainder of the
terms of this License, and without further action by the parties to
this agreement, such provision shall be reformed to the minimum
extent necessary to make such provision valid and enforceable.
3. No term or provision of this License shall be deemed waived and
no breach consented to unless such waiver or consent shall be in
writing and signed by the party to be charged with such waiver or
consent. 4. This License constitutes the entire agreement between
the parties with respect to the Work licensed here. There are no
understandings, agreements or representations with respect to the
Work not specified here. Licensor shall not be bound by any
additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written
agreement of the Licensor and You.