Tutorial: Writing the demo Module
This page aims to describe how to write and then run the demo module with GenoM3 either for ros and pocolibs.
Needs
Check this instruction page to install GenoM3 and associated templates and tools.
Demo module with pocolibs
The final result of this tutorial module can be obtained from here. But this tutorial will walk you thru getting your own copy! Still, you can grab it if you want avoiding typing all the code.
git clone git://trac.laas.fr/robots/demo-genom demo-genom-final cd demo-genom-final git checkout genom3
part 1: How to write your first module ?
This section will illustrate a concrete use of genom3. The demo module will control a virtual mobile that can move in a 1D world. Some of the services the module offers are:
- read and set the current speed at any moment
- move the mobile to a given position
- move the mobile of a given distance (from its current position)
- monitor when the mobile passes a given position
- stop the motion
Moreover, the demo module export a port with the current state of the mobile (position and speed).
To implement this, we first create a directory named demo-genom.
mkdir demo-genom cd demo-genom
Write .gen File
In that directory, we will write the description file demo.gen. The file demo.gen is made up of several parts, each of them being identified with a keyword:
component module declaration
ids
port
exception
task
attribute
function
activity
The entire file will look like this:
/* The special / * / marker will copy the associated comment block (here, the * license) in the generated files. */ /*/ * Copyright (c) 1996-2013 CNRS/LAAS * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "demoStruct.idl" /* ---- component declaration ---- */ component demo { version "1.1"; email "openrobots@laas.fr"; lang "c"; require "genom3 >= 2.99.20"; /* ---- Data structures and IDS ---- */ ids { demo::state state; /* Current state */ demo::speed speedRef; /* Speed reference */ double posRef; }; /* ---- Port declaration ---- */ port out demo::state Mobile; /* ---- exception declaration ---- */ exception TOO_FAR_AWAY {double overshoot;}; exception INVALID_SPEED; /* ---- Execution task declaration ---- */ task motion { period demo::task_period ms; priority 100; stack 4000; codel <start> InitDemoSDI(out ::ids, port out Mobile) yield ether; }; /* ---- Services declarations ---- */ attribute SetSpeed(in speedRef = demo::SLOW :"Mobile speed") { doc "To change speed"; validate controlSpeed (local in speedRef); throw INVALID_SPEED; }; attribute GetSpeed(out speedRef = :"Mobile speed") { doc "To get current speed value"; }; function Stop() { doc "Stops motion and interrupts all motion requests"; interrupts MoveDistance, GotoPosition; }; activity MoveDistance(in double distRef = 0 :"Distance in m") { doc "Move of the given distance"; validate controlDistance(in distRef, in state.position); codel <start> mdStartEngine(in distRef, in state.position, out posRef) yield exec, ether; codel <exec> mdGotoPosition(in speedRef, in posRef, inout state, port out Mobile) yield exec, end; codel <end, stop> mdStopEngine() yield ether; interrupts MoveDistance, GotoPosition; task motion; throw TOO_FAR_AWAY; }; activity GotoPosition (in double posRef = 0 :"Goto position in m") { doc "Move to the given position"; validate controlPosition (local in posRef); codel <start> gpStartEngine() yield exec, ether; codel <exec> gpGotoPosition(local in posRef, inout ::ids, port out Mobile) yield exec, end; codel <end, stop> gpStopEngine() yield ether; interrupts MoveDistance, GotoPosition; task motion; throw TOO_FAR_AWAY; }; activity Monitor (in double monitor = 0 :"Monitored absolute position in m", out double position) { doc "Monitor the passage on the given position"; validate controlPosition (in monitor); codel <start> monitor(in monitor, in ::ids) yield start, stop; codel <stop> monitorStop(in ::ids, out position) yield ether; task motion; throw TOO_FAR_AWAY; }; };
Data Structure Definition
The #include "demoStruct.idl" statement works as a header file in C and includes idl data structure. This file contains all the necessary declarations for the definition of the internal database. These structures are then used in the .gen file. In this example, the file "demoStruct.idl" contains the definition of the position and the speed. This file is preferably located in the same directory as demo.gen, since it contributes to the definition of the module interface.
/* * Copyright (c) 1996-2013 CNRS/LAAS * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef IDL_DEMO_STRUCT #define IDL_DEMO_STRUCT module demo { const unsigned long task_period = 400; const double millisecond = 0.001; struct state { double position; /* current position (m) */ double speed; /* current speed (m/s) */ }; enum speed { SLOW, FAST }; }; #endif /* IDL_DEMO_STRUCT */
Module generation
Once your description file (.gen and .idl) are ready, you need to generate your module:
gupta[demo-genom] genom3 skeleton demo.gen creating ./codels/demo_motion_codels.c creating ./codels/demo_codels.c creating ./demo-genom3.pc.in creating ./demo-genom3-uninstalled.pc.in creating ./bootstrap.sh creating ./autoconf/ag_templates.m4 creating ./configure.ac creating ./Makefile.am creating ./codels/Makefile.am
From now on, the module is ready to be compiled and run, but let's look at the result of the execution of the command:
gupta[demo-genom] ls autoconf configure.ac demo-genom3-uninstalled.pc.in bootstrap.sh demo.gen demoStruct.idl codels demo-genom3.pc.in Makefile.am
GenoM3 created two new directories codels/ and autoconf/, and several new files.
Algorithms (or a part of them) are grouped in the directory codels/. The files in that directory give you template to start from, and also let GenoM3 produce a module even if you still do not have written a single line of code.
- The Makefile.am and configure.ac files are also under your control. These are the main files which are used for the compilation of the module.
Codels writing
Let's have a look in the codels directory.
gupta[codels] ls demo_codels.c demo_motion_codels.c Makefile.am
demo_codels.c
In this file, we will found codels executed by the control task such as the validateones , e.g. controlSpeed (Validation codel of attribute SetSpeed), controlPosition (Validation codel of activity GotoPosition) and controlDistance (Validation codel of activity MoveDistance)..
At the beginning, the template will look like:
gupta[codels] more demo_codels.c /* * Copyright (c) 1996-2013 CNRS/LAAS * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "acdemo.h" #include "demo_c_types.h" /* --- Attribute SetSpeed ----------------------------------------------- */ /** Validation codel controlSpeed of attribute SetSpeed. * * Returns genom_ok. * Throws demo_INVALID_SPEED. */ genom_event controlSpeed(demo_speed speedRef) { /* skeleton sample: insert your code */ /* skeleton sample */ return genom_ok; } /* --- Activity MoveDistance -------------------------------------------- */ /** Validation codel controlDistance of activity MoveDistance. * * Returns genom_ok. * Throws demo_TOO_FAR_AWAY. */ genom_event controlDistance(double distRef, double position) { /* skeleton sample: insert your code */ /* skeleton sample */ return genom_ok; } /* --- Activity GotoPosition -------------------------------------------- */ /** Validation codel controlPosition of activity GotoPosition. * * Returns genom_ok. * Throws demo_TOO_FAR_AWAY. */ genom_event controlPosition(double posRef) { /* skeleton sample: insert your code */ /* skeleton sample */ return genom_ok; } /* --- Activity Monitor ------------------------------------------------- */ /** Validation codel controlPosition of activity Monitor. * * Returns genom_ok. * Throws demo_TOO_FAR_AWAY. */ /* already defined in service GotoPosition validation */
You notice that all the codels are empty and return genom_ok. Still the parameters are the corect ones. Here are possible code to include in these functions:
controlSpeed
genom_event controlSpeed(demo_speed speedRef) { /* insert your code */ if(speedRef != demo_SLOW && speedRef != demo_FAST) return demo_INVALID_SPEED(); return genom_ok; }
controlDistance
genom_event controlDistance(double distRef, double position) { double lposRef; demo_TOO_FAR_AWAY_detail tfa; lposRef = position + distRef; if (lposRef > DEMO_MACHINE_LENGTH/2 || lposRef < -DEMO_MACHINE_LENGTH/2) { tfa.overshoot = fabs(lposRef) - fabs(DEMO_MACHINE_LENGTH/2); return demo_TOO_FAR_AWAY(&tfa); } return genom_ok; }
controlPosition
genom_event controlPosition(double posRef) { demo_TOO_FAR_AWAY_detail tfa; if (posRef > DEMO_MACHINE_LENGTH/2 || posRef < -DEMO_MACHINE_LENGTH/2) { tfa.overshoot = fabs(posRef) - fabs(DEMO_MACHINE_LENGTH/2); return demo_TOO_FAR_AWAY(&tfa); } return genom_ok; }
Note the exception TOO_FAR_WAY for which we return the length we overshoot the maximum/minimum distance acceptable. Such information can be retrieve by the client/supervisor to take appropriate corrective actions.
demo_motion_codels.c
In this file, we will found codels attached to the motion task, such as :
InitDemoSDI: which is the <start> codel of the task
gpStartEngine, gpGotoPosition, gpStopEngine: which are <start>, <exec> and <stop> codels of the GotoPosition activity
- etc
gupta[codels] more demo_motion_codels.c /* * Copyright (c) 1996-2013 CNRS/LAAS * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "acdemo.h" #include "demo_c_types.h" /* --- Task motion ------------------------------------------------------ */ /** Codel InitDemoSDI of task motion. * * Triggered by demo_start. * Yields to demo_ether. */ genom_event InitDemoSDI(demo_ids *ids, const demo_Mobile *Mobile) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_ether; } /* --- Activity MoveDistance -------------------------------------------- */ /** Codel mdStartEngine of activity MoveDistance. * * Triggered by demo_start. * Yields to demo_exec, demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event mdStartEngine(double distRef, double position, double *posRef) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_exec; } /** Codel mdGotoPosition of activity MoveDistance. * * Triggered by demo_exec. * Yields to demo_exec, demo_end. * Throws demo_TOO_FAR_AWAY. */ genom_event mdGotoPosition(demo_speed speedRef, double posRef, demo_state *state, const demo_Mobile *Mobile) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_exec; } /** Codel mdStopEngine of activity MoveDistance. * * Triggered by demo_end, demo_stop. * Yields to demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event mdStopEngine(void) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_ether; } /* --- Activity GotoPosition -------------------------------------------- */ /** Codel gpStartEngine of activity GotoPosition. * * Triggered by demo_start. * Yields to demo_exec, demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event gpStartEngine(void) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_exec; } /** Codel gpGotoPosition of activity GotoPosition. * * Triggered by demo_exec. * Yields to demo_exec, demo_end. * Throws demo_TOO_FAR_AWAY. */ genom_event gpGotoPosition(double posRef, demo_ids *ids, const demo_Mobile *Mobile) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_exec; } /** Codel gpStopEngine of activity GotoPosition. * * Triggered by demo_end, demo_stop. * Yields to demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event gpStopEngine(void) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_ether; } /* --- Activity Monitor ------------------------------------------------- */ /** Codel monitor of activity Monitor. * * Triggered by demo_start. * Yields to demo_start, demo_stop. * Throws demo_TOO_FAR_AWAY. */ genom_event monitor(double monitor, const demo_ids *ids) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_start; } /** Codel monitorStop of activity Monitor. * * Triggered by demo_stop. * Yields to demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event monitorStop(const demo_ids *ids, double *position) { /* skeleton sample: insert your code */ /* skeleton sample */ return demo_ether; }
Let's have a look on how we can write such functions:
/* * Copyright (c) 1996-2013 CNRS/LAAS * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "acdemo.h" #include <stdio.h> #include <math.h> #include "demoConst.h" #include "demo_c_types.h" #define SIGN(x) ((x)<0.?-1.0:1.0) /* --- Task motion ------------------------------------------------------ */ /** Codel InitDemoSDI of task motion. * * Triggered by demo_start. * Yields to demo_ether. */ genom_event InitDemoSDI(demo_ids *ids, const demo_Mobile *Mobile) { ids->state.position = 0.0; ids->state.speed = 0; Mobile->data()->position = ids->state.position; Mobile->data()->speed = ids->state.speed; Mobile->write(); /* write the poster. */ ids->speedRef = demo_SLOW; printf ("InitDemoSDI done.\n"); return demo_ether; } /* --- Activity MoveDistance -------------------------------------------- */ /** Codel mdStartEngine of activity MoveDistance. * * Triggered by demo_start. * Yields to demo_exec, demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event mdStartEngine(double distRef, double position, double *posRef) { *posRef = position + distRef; printf("starting engine\n"); return demo_exec; } /** Codel mdGotoPosition of activity MoveDistance. * * Triggered by demo_exec. * Yields to demo_exec, demo_end. * Throws demo_TOO_FAR_AWAY. */ genom_event mdGotoPosition(demo_speed speedRef, double posRef, demo_state *state, const demo_Mobile *Mobile) { double distRemain; double dDist; double v; distRemain = posRef - state->position; v = (speedRef == demo_SLOW) ? DEMO_DEFAULT_MAX_SPEED/4. : DEMO_DEFAULT_MAX_SPEED; dDist = v * demo_task_period * demo_millisecond* SIGN(distRemain); if (fabs(distRemain) < fabs(dDist)) { Mobile->data()->position = state->position = posRef; Mobile->data()->speed = state->speed = 0; Mobile->write(); /* write the poster. */ return demo_end; } Mobile->data()->position = state->position += dDist; Mobile->data()->speed = state->speed = v; Mobile->write(); /* write the poster. */ #ifdef VERBOSE printf ("speed %g m/s pos %g m\n", v, state->position); #endif return demo_exec; } /** Codel mdStopEngine of activity MoveDistance. * * Triggered by demo_end, demo_stop. * Yields to demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event mdStopEngine(void) { printf ("stop engine\n"); return demo_ether; } /* --- Activity GotoPosition -------------------------------------------- */ /** Codel gpStartEngine of activity GotoPosition. * * Triggered by demo_start. * Yields to demo_exec, demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event gpStartEngine(void) { printf("starting engine\n"); return demo_exec; } /** Codel gpGotoPosition of activity GotoPosition. * * Triggered by demo_exec. * Yields to demo_exec, demo_end. * Throws demo_TOO_FAR_AWAY. */ genom_event gpGotoPosition(double posRef, demo_ids *ids, const demo_Mobile *Mobile) { return mdGotoPosition(ids->speedRef, posRef, &ids->state, Mobile); } /** Codel gpStopEngine of activity GotoPosition. * * Triggered by demo_end, demo_stop. * Yields to demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event gpStopEngine(void) { return mdStopEngine(); } /* --- Activity Monitor ------------------------------------------------- */ /** Codel monitor of activity Monitor. * * Triggered by demo_start. * Yields to demo_start, demo_stop. * Throws demo_TOO_FAR_AWAY. */ genom_event monitor(double monitor, const demo_ids *ids) { double dDist; dDist = ids->state.speed * demo_task_period * demo_millisecond; if (fabs (monitor - ids->state.position) < dDist) { printf ("dist %f mon %f pos %f\n", dDist, monitor, ids->state.position); return demo_stop; } return demo_start; } /** Codel monitorStop of activity Monitor. * * Triggered by demo_stop. * Yields to demo_ether. * Throws demo_TOO_FAR_AWAY. */ genom_event monitorStop(const demo_ids *ids, double *position) { *position = ids->state.position; return demo_ether; }
Note that we include a demoConst.h file which you should also create in the same directory than the codels and containing:
#ifndef DEMO_CONST_H #define DEMO_CONST_H #define DEMO_MACHINE_LENGTH 2.0 /* m */ #define DEMO_DEFAULT_MAX_SPEED 0.5 /* m/s */ #define VERBOSE #endif
Module compilation
We are now ready to compile the module. Note that you could have done it with the empty codels just after generating the skeleton. The result would have been a valid GenoM3 module, runnable, but not doing anyhing of course.
There are two steps in compilation of the module:
configuration of the module by running the configure script
compilation itself, controlled by the Makefile generated in the previous step.
Bootstrap
- bootstrap the autotools build system
gupta[demo-genom] ./bootstrap.sh autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal -I autoconf autoreconf: configure.ac: tracing autoreconf: running: libtoolize --install --copy libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `autoconf'. libtoolize: copying file `autoconf/config.guess' libtoolize: copying file `autoconf/config.sub' libtoolize: copying file `autoconf/install-sh' libtoolize: copying file `autoconf/ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `autoconf'. libtoolize: copying file `autoconf/libtool.m4' libtoolize: copying file `autoconf/ltoptions.m4' libtoolize: copying file `autoconf/ltsugar.m4' libtoolize: copying file `autoconf/ltversion.m4' libtoolize: copying file `autoconf/lt~obsolete.m4' autoreconf: running: /usr/bin/autoconf autoreconf: running: /usr/bin/autoheader autoreconf: running: automake --add-missing --copy --no-force configure.ac:24: installing `autoconf/missing' codels/Makefile.am: installing `autoconf/depcomp' autoreconf: Leaving directory `.'
Build directory
In order to keep objects files separated from the sources, for instance when you want to generate the module for several different architectures, or just in order to have a simple mean to clean up everything that was produced during the building phase, it is strongly recommended to create a separate build directory and run every command from there.
gupta[demo-genom] mkdir build gupta[demo-genom] cd build
Configuration
All the OpenRobots software and tools are generally installed in a specific directory (for instance ${HOME}/openrobots). This is the main information that needs to be specified to the configure script. Don't forget to run configure from the build directory. Then, the options will be different given the templates you want to generate, you have several possibilities:
- pocolibs ($TEMPLATES=pocolibs/server,pocolibs/client/c)
- pocolibs/server is the genom pocolibs module itself
- pocolibs/client/c is the pocolibs C client library
- ros ($TEMPLATES=ros/server,ros/client/c,ros/client/ros)
- ros/server is the genom ros module itself
- ros/client/c is the ros C client library
- openprs ($TEMPLATES=openprs/client), you can mix openprs template with the others (e.g.: $TEMPLATES=pocolibs/server,pocolibs/client/c,openprs/client)
e.g. here, if we set $TEMPLATES=pocolibs/server,pocolibs/client/c
gupta[build] ../configure --prefix=$INSTALL_DIR --with-templates=$TEMPLATES checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu ... ... ... checking for pocolibs... yes checking for genom3_pocolibs... yes checking for genom3... yes configure: creating ./config.status config.status: creating Makefile config.status: creating demo-c-client.pc config.status: creating demo-c-client-uninstalled.pc config.status: creating autoconf/acheader.h config.status: executing depfiles commands config.status: executing libtool commands configure: done configuring for pocolibs/client/c
Compilation
To compile the module, just run make from the build directory. The GNU make utility is required, but this is the standard make on linux systems.
make
Installation
The built binaries and libraries (and some associated files) need to be copied to their final locations. This is achieved by executing make install. Depending of the {$INSTALL_PATH} you used, this may require root privilege.
make install
Module execution
Once compiled, the module is ready to be executed. The module is located in the bin subdirectory of the directory specified as prefix in the configuration step. This is an executable whose name will depend of the $TEMPLATE you choose. E.g., in our case, if we use pocolibs template, we will have demo-pocolibs executable and if you use ros template, we will have demo-ros.
pocolibs
You need to initialise pocolibs, to do so type:
h2 init Initializing pocolibs devices: OK
at this point, you can start the module:
demo-pocolibs -b pocolibs execution environment version 2.13 Copyright (c) 1999-2011 CNRS-LAAS demo: created outport demo/genom_state demo: created outport demo/genom_metadata demo: created outport demo/Mobile InitDemoSDI done. demo: spawned motion exec task demo: spawned control task demo: setup and running
the -b argument is to start the module in background. -h will indicate the other options available.
Now that your module is running, you need to control it, to send request, get report, read the port, etc.
For this you need a client, let's start with a tcl client.
tcl
To control the module with tcl, you need to start the genomixd program, then launch eltclsh which is an interactive tcl shell.
genomixd & eltclsh eltclsh1.14 - Copyright (C) 2001-2012 LAAS-CNRS eltclsh > package require genomix 1.2 eltclsh > genomix::connect genomix1 eltclsh > genomix1 load demo pocolibs execution environment version 2.13 Copyright (c) 1999-2011 CNRS-LAAS demo
You can use completion (tab) at any point to get help on the available commands. Exemple:
eltclsh > demo<tab><tab> ::demo::GetSpeed ::demo::MoveDistance ::demo::connect_port ::demo::GotoPosition ::demo::SetSpeed ::demo::connect_remote ::demo::Mobile ::demo::Stop ::demo::genom_state ::demo::Monitor ::demo::abort_activity ::demo::kill
Note that all the services, port and some default services are provided. You can now play with your module. If you have started the module in the same window, you will see the following results.
eltclsh > ::demo::GetSpeed speedRef ::demo::SLOW eltclsh > ::demo::GotoPosition -h Usage: demo::GotoPosition [-id var] [-s|-send] [-a|-ack] [-t|-timeout milli] [-f|-flat] [-h] [--] input [& ?script?] Input dictionary: double posRef: Goto position in m (0) eltclsh > ::demo::GotoPosition 1 starting engine speed 0.125 m/s pos 0.05 m speed 0.125 m/s pos 0.1 m speed 0.125 m/s pos 0.15 m speed 0.125 m/s pos 0.2 m speed 0.125 m/s pos 0.25 m speed 0.125 m/s pos 0.3 m speed 0.125 m/s pos 0.35 m speed 0.125 m/s pos 0.4 m speed 0.125 m/s pos 0.45 m speed 0.125 m/s pos 0.5 m speed 0.125 m/s pos 0.55 m speed 0.125 m/s pos 0.6 m speed 0.125 m/s pos 0.65 m speed 0.125 m/s pos 0.7 m speed 0.125 m/s pos 0.75 m speed 0.125 m/s pos 0.8 m speed 0.125 m/s pos 0.85 m speed 0.125 m/s pos 0.9 m speed 0.125 m/s pos 0.95 m stop engine eltclsh > ::demo::SetSpeed enum speedRef: Mobile speed (::demo::SLOW) > ::demo::FAST eltclsh > ::demo::Monitor 0 & demo::0 eltclsh > ::demo::GotoPosition double posRef: Goto position in m (0) > -1 starting engine speed 0.5 m/s pos 0.8 m speed 0.5 m/s pos 0.6 m speed 0.5 m/s pos 0.4 m speed 0.5 m/s pos 0.2 m speed 0.5 m/s pos 5.55112e-17 m dist 0.200000 mon 0.000000 pos 0.000000 speed 0.5 m/s pos -0.2 m speed 0.5 m/s pos -0.4 m speed 0.5 m/s pos -0.6 m speed 0.5 m/s pos -0.8 m stop engine
Note the monitor which reported when the mobile passes in 0.
You can also read the port Mobile:
eltclsh > ::demo::Mobile Mobile {position -1 speed 0} eltclsh >
To kill the module:
eltclsh > ::demo::kill demo: terminating on Terminated signal request eltclsh > demo: shutting down motion exec task demo: shutting down control task demo: destroyed outport genom_state demo: destroyed outport genom_metadata demo: destroyed outport Mobile demo: shutdown complete eltclsh >
You can also kill genomixd, and clean up h2.
pkill genomixd h2 end
ros
NB: If you want to run the ros version, you need to have configure your system with ros Templates.
If you have already configure with another template, you need to restart at the configure command. It is probably better to erase the build directory or make another one:
mkdir build-ros cd build-ros ../configure --prefix=$INSTALL_DIR --with-templates=ros/server,ros/client/c make install
If you have not configure yet your module, you should follow Module Compilation instruction from the beginning.
If you have configure your module with ros template:
You will need to start roscore.
roscore &
The ros module has a different name.
demo-ros -b demo: advertising ports demo: initialized outport genom_state demo: motion task initialized and running demo: advertising services demo: control task initialized and running
From now on, you can control this module exactly the same way you did with the pocolibs version.
You can also see that your ROS based demo module can be seen as a regular ROS node, with its topics, services and actions.
rosnode info demo -------------------------------------------------------------------------------- Node [/demo] Publications: * /demo/GotoPosition/status [actionlib_msgs/GoalStatusArray] * /demo/MoveDistance/result [demo/MoveDistanceActionResult] * /demo/Mobile [demo/demo_state] * /rosout [rosgraph_msgs/Log] * /demo/genom_state [demo/genom_state_component] * /demo/Monitor/feedback [demo/MonitorActionFeedback] * /demo/MoveDistance/feedback [demo/MoveDistanceActionFeedback] * /demo/MoveDistance/status [actionlib_msgs/GoalStatusArray] * /demo/GotoPosition/feedback [demo/GotoPositionActionFeedback] * /demo/Monitor/result [demo/MonitorActionResult] * /demo/GotoPosition/result [demo/GotoPositionActionResult] * /demo/Monitor/status [actionlib_msgs/GoalStatusArray] Subscriptions: * /demo/Monitor/cancel [actionlib_msgs/GoalID] * /demo/GotoPosition/goal [demo/GotoPositionActionGoal] * /demo/MoveDistance/goal [demo/MoveDistanceActionGoal] * /demo/MoveDistance/cancel [actionlib_msgs/GoalID] * /demo/GotoPosition/cancel [actionlib_msgs/GoalID] * /demo/Monitor/goal [demo/MonitorActionGoal] Services: * /demo/connect_port * /demo/kill * /demo/GetSpeed * /demo/get_loggers * /demo/abort_activity * /demo/set_logger_level * /demo/Stop * /demo/SetSpeed * /demo/connect_remote ... ... ...
Demo module with openprs
If you want to control this module with openprs, you will need to install transgen3, and follow this tutorial to create it.