welcome: please sign in
location: genom3 / tutorial / two-modules

Tutorial: making the mobileloco and mobiledisp Modules

Needs

Check this instruction page to install GenoM3 and associated templates and tools.

demo-mobile-loco and demo-mobile-disp modules that will be used in this tutorial are available through git:

       git clone git://trac.laas.fr/git/robots/demo-mobile-loco
       git clone git://trac.laas.fr/git/robots/demo-mobile-disp

part 1: How to write your first module ?

This section will illustrate a concrete use of genom3. The mobile-loco module will control a virtual mobile that can move in a 2D world. Some of the services the module offers are:

To implement this, we first create a directory named mobile-loco.

mkdir mobile-loco
cd mobile-loco

Write .gen File

In that directory, we will write the description file mobile-loco.gen. The file mobile-loco.gen is made up of several parts, each of them being identified with a keyword:

The entire file will look like this:

#include "mobile-loco-struct.idl"
#include "mobile-loco-interface.gen"

/* -------------------------- MODULE DECLARATION --------------------------- */
component mobileloco {
 version  "1.0";
 email    "openrobots@laas.fr";
 lang     "c";
 provides mobilelocointerface;

/* ------------- DEFINITION OF THE MODULE’s INTERNAL DATABASE -------------- */
 ids {
  mobilelocointerface::position start_position;
  mobilelocointerface::position current_position;
  mobilelocointerface::position end_position;
 };

/* ------------------ TASK DEFINITION -------------------- */

task motion {
 period     mobileloco::task_period ms;
 priority   100;
 stack      4000;
 codel <start> InitMotionParameters(out ::ids, port out E_current_position) yield ether;
};

/* ------------------ SERVICES DEFINITION: The ATTRIBUTES -------------------- */

attribute SetSpeed(in current_speed=    :"Mobile speed")
{
 doc            "To increase speed";
 validate       controlSpeed (local in current_speed);
 throw          INVALID_SPEED;
};

attribute GetSpeed(out current_speed =  :"Mobile speed")
{
 doc            "To get current speed value";
};

/* ------------------ SERVICES DEFINITION: The Functions -------------------- */

function Stop()
{
 doc            "Stops motion and interrupts all motion requests";
 interrupts     GotoPosition;
};


/* ------------------ SERVICES DEFINITION: The activities -------------------- */

activity GotoPosition (in mobilelocointerface::position goto_position =  :"Goto position")
{
 doc                  "Move to the given position";
 validate             controlPosition (in goto_position);
 codel <start>        gotoposStart(in goto_position, inout ::ids) yield exec, ether;
 codel <exec>         gotoposExec(inout ::ids, port out E_current_position) yield exec, end, stop;
 codel <end,stop>     gotoposStop(inout ::ids) yield ether;
 interrupts           GotoPosition, Stop;
 task                 motion;
 throw                INVALID_POSITION;
};

};

Data Structure Definition

The #include "mobile-loco-struct.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. (The #include "mobile-loco-interface.gen" will be useful later when we would be able to link the module with another one). In this example, the file "mobile-loco-struct.idl" contains the definition of the position and the speed. This file is preferably located in the same directory as mobile-loco.gen, since it contributes to the definition of the module interface. rq: if you get demo-mobile-loco module through git, the idl definition is quite different and is moved to the mobile-loco-interface.gen file to interface with demo-mobile-disp

#ifndef IDL_MOBILE_LOCO_STRUCT
#define IDL_MOBILE_LOCO_STRUCT

module mobileloco {

 /* task period */
 const unsigned long task_period = 400;

 /* mobile position definition*/
 struct position {
 double x;
 double y;
 };

 /* speed definition */
 enum speed_enum {
 SLOW,
 MEDIUM,
 FAST
 };
 struct speed {
 speed_enum s;
 };
};
#endif

Module generation

Once your description file (.gen) ready, you need to generate your module:

gupta[mobile-loco] genom3 skeleton mobile-loco.gen
creating ./codels/mobileloco_motion_codels.c
creating ./codels/mobileloco_codels.c
creating ./libmobileloco_codels.pc.in
creating ./libmobileloco_codels-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[mobile-loco] ls
autoconf/      codels/      mobileloco-genom.pc.in                  Makefile.am      mobile-loco-struct.idl
bootstrap.sh  configure.ac  mobileloco-genom-uninstalled.pc.in  mobile-loco.gen  mobile-loco-interface.gen

GenoM3 created two new directories codels/ and autoconf/, and several new files.

Codels writing

Let's have a look in the codels directory.

gupta[codels] ls
Makefile.am  Makefile.in  mobileloco_codels.c  mobileloco_motion_codels.c

mobileloco_codels.c

In this file, we will found codels related to validation, e.g. controlSpeed (Validation codel of attribute SetSpeed) and controlPosition (Validation codel of activity GotoPosition).

rq: take care, code from git is quite different due to interface with mobile-disp but both works

At the beginning, the template will look like:

gupta[codels] more mobileloco_codels.c
#include "acmobileloco.h"

#include "mobileloco_c_types.h"


/* --- Attribute SetSpeed ----------------------------------------------- */

/** Validation codel controlSpeed of attribute SetSpeed.
 *
 * Returns ok.
 * Throws INVALID_SPEED.
 */
mobileloco_event
controlSpeed(const mobileloco_speed *current_speed)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_ok;
}


/* --- Activity GotoPosition -------------------------------------------- */

/** Validation codel controlPosition of activity GotoPosition.
 *
 * Returns ok.
 * Throws INVALID_POSITION.
 */
mobileloco_event
controlPosition(const mobileloco_position *goto_position)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_ok;
}


/* --- Activity Monitor ------------------------------------------------- */

/** Validation codel controlPosition of activity Monitor.
 *
 * Returns ok.
 * Throws .
 */
/* already defined in service GotoPosition validation */

Let's have a look on how we can write such functions:

controlSpeed

mobileloco_event
controlSpeed(const mobileloco_speed *current_speed)
{
  if((current_speed->s != mobileloco_SLOW) &&
     (current_speed->s != mobileloco_MEDIUM) &&
     (current_speed->s != mobileloco_FAST))
    return mobileloco_INVALID_SPEED;
  return mobileloco_ok;
}

controlPosition

mobileloco_event
controlPosition(const mobileloco_position *goto_position)
{
  if((goto_position->x > 100.0) ||
     (goto_position->x < -100.0) ||
     (goto_position->y > 100.0) ||
     (goto_position->y < -100.0))
    return mobileloco_INVALID_POSITION;
  return mobileloco_ok;
}

mobileloco_motion_codels.c

In this file, we will found functions attached to the motion task, such as :

gupta[codels] more mobileloco_motion_codels.c
#include "acmobileloco.h"

#include "mobileloco_c_types.h"


/* --- Task motion ------------------------------------------------------ */


/** Codel InitMotionParameters of task motion.
 *
 * Triggered by start.
 * Yields to ether.
 */
mobileloco_event
InitMotionParameters(mobileloco_ids *ids,
                     const mobileloco_E_current_position *E_current_position)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_ether;
}


/* --- Activity GotoPosition -------------------------------------------- */

/** Codel gotoposStart of activity GotoPosition.
 *
 * Triggered by start.
 * Yields to exec, ether.
 * Throws INVALID_POSITION.
 */
mobileloco_event
gotoposStart(const mobileloco_position *goto_position,
             mobileloco_ids *ids)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_exec;
}

/** Codel gotoposExec of activity GotoPosition.
 *
 * Triggered by exec.
 * Yields to exec, end, stop.
 * Throws INVALID_POSITION.
 */
mobileloco_event
gotoposExec(mobileloco_ids *ids,
            const mobileloco_E_current_position *E_current_position)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_exec;
}

/** Codel gotoposStop of activity GotoPosition.
 *
 * Triggered by end, stop.
 * Yields to ether.
 * Throws INVALID_POSITION.
 */
mobileloco_event
gotoposStop(mobileloco_ids *ids)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_ether;
}


/* --- Activity Monitor ------------------------------------------------- */

/** Codel monitStart of activity Monitor.
 *
 * Triggered by start.
 * Yields to start, stop.
 */
mobileloco_event
monitStart(const mobileloco_position *monitored_position,
           const mobileloco_ids *ids)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_start;
}

/** Codel monitStop of activity Monitor.
 *
 * Triggered by stop.
 * Yields to ether.
 */
mobileloco_event
monitStop(void)
{
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobileloco_ether;
}

Let's have a look on how we can write such functions:

gotoposExec

mobileloco_event
gotoposExec(mobileloco_ids *ids,
            const mobileloco_E_current_position *E_current_position)
{
  double step;
  int end_x = 0;
  int end_y =0 ;

  switch(ids->current_speed.s){
  case mobileloco_SLOW:
    step=0.1;
    break;
  case mobileloco_MEDIUM:
    step=0.5;
    break;
  case mobileloco_FAST:
    step=1.0;
    break;
  }

  if(x_direction==FORWARD) {
    if(ids->end_position.x > (ids->current_position.x + step)){
      ids->current_position.x = ids->current_position.x + step;
    } else {
      ids->current_position.x = ids->end_position.x;
      end_x = 1;
    }
  } else {
    if(ids->end_position.x < (ids->current_position.x - step)){
      ids->current_position.x = ids->current_position.x - step;
    } else {
      ids->current_position.x = ids->end_position.x;
      end_x = 1;
    }
  }

  if(y_direction==FORWARD) {
    if(ids->end_position.y > (ids->current_position.y + step)){
      ids->current_position.y = ids->current_position.y + step;
    } else {
      ids->current_position.y = ids->end_position.y;
      end_y = 1;
    }
  } else {
    if(ids->end_position.y < (ids->current_position.y - step)){
      ids->current_position.y = ids->current_position.y - step;
    } else {
      ids->current_position.y = ids->end_position.y;
      end_y = 1;
    }
  }

  E_current_position->data()->x= ids->current_position.x;
  E_current_position->data()->y= ids->current_position.y;
  E_current_position->write();

  if ((end_x == 1) && (end_y==1)) {
    return mobileloco_end;
  } else {
    return mobileloco_exec;
  }
}

gotoposStop

mobileloco_event
gotoposStop(mobileloco_ids *ids)
{
  ids->start_position.x=ids->current_position.x;
  ids->start_position.y=ids->current_position.y;
  return mobileloco_ether;
}

Module compilation

There are two steps in compilation of the module:

Bootstrap

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[mobile-loco] mkdir build
gupta[mobile-loco] 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:

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 mobileloco-c-client.pc
config.status: creating mobileloco-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.

gupta[build] make
Making all in codels
make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels'
make  all-am
make[2]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels'
make[2]: Nothing to be done for `all-am'.
...
...
...
lib/genom/client/c mobileloco_la-mobileloco_plugin.lo
libtool: link: gcc -shared  .libs/mobileloco_la-mobileloco_plugin.o   -Wl,-rpath -Wl,/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c/.libs -Wl,-rpath -Wl,/home/aclodic/Work/01_Demo/INSTALL/lib ./.libs/libmobileloco-c-client.so  -pthread   -pthread -Wl,-soname -Wl,mobileloco-1.0.so -o .libs/mobileloco-1.0.so
libtool: link: (cd ".libs" && rm -f "mobileloco.so" && ln -s "mobileloco-1.0.so" "mobileloco.so")
libtool: link: ar cru .libs/mobileloco.a  mobileloco_la-mobileloco_plugin.o
libtool: link: ranlib .libs/mobileloco.a
libtool: link: ( cd ".libs" && rm -f "mobileloco.la" && ln -s "../mobileloco.la" "mobileloco.la" )
make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c'
make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build'
make[1]: Nothing to be done for `all-am'.
make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build'

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.

gupta[build] make install
Making install in codels
make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels'
make  install-am
make[2]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels'
make[3]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels'
test -z "/home/aclodic/Work/01_Demo/INSTALL/lib" || /bin/mkdir -p "/home/aclodic/Work/01_Demo/INSTALL/lib"
 /bin/bash ../libtool   --mode=install /usr/bin/install -c   libmobileloco_codels.la '/home/aclodic/Work/01_Demo/INSTALL/lib'
libtool: install: /usr/bin/install -c .libs/libmobileloco_codels-1.0.so /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels-1.0.so
libtool: install: (cd /home/aclodic/Work/01_Demo/INSTALL/lib && { ln -s -f libmobileloco_codels-1.0.so libmobileloco_codels.so || { rm -f libmobileloco_codels.so && ln -s libmobileloco_codels-1.0.so libmobileloco_codels.so; }; })
libtool: install: /usr/bin/install -c .libs/libmobileloco_codels.lai /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.la
libtool: install: /usr/bin/install -c .libs/libmobileloco_codels.a /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.a
libtool: install: chmod 644 /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.a
libtool: install: ranlib /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.a
libtool: finish: PATH="/home/aclodic/Work/01_Demo/INSTALL:/home/aclodic/Work/01_Demo/INSTALL/bin:/home/aclodic/Work/01_Demo/INSTALL/sbin:/home/aclodic/bin:/usr/local/bin:/home/aclodic/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:.:/sbin" ldconfig -n /home/aclodic/Work/01_Demo/INSTALL/lib
...
...
...
test -z "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig" || /bin/mkdir -p "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig"
 /usr/bin/install -c -m 644 mobileloco-c-client.pc '/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig'
make[2]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c'
make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c'
make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build'
make[2]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build'
make[2]: Nothing to be done for `install-exec-am'.
test -z "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig" || /bin/mkdir -p "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig"
 /usr/bin/install -c -m 644 libmobileloco_codels.pc '/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig'
make[2]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build'
make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build'

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 mobileloco-pocolibs executable and if you use ros template, we will have mobileloco-ros.

pocolibs

tcl

h2 init &
mobileloco-pocolibs &
genomixd &
eltclsh
eltclsh > package require genomix
1.0
eltclsh > genomix::connect
genomix1
eltclsh > genomix1 load mobileloco
pocolibs execution environment version 2.12.99
Copyright (c) 1999-2011 CNRS-LAAS
mobileloco
eltclsh > mobileloco::
::mobileloco::E_current_position ::mobileloco::GotoPosition       ::mobileloco::SetSpeed           ::mobileloco::abort_activity     ::mobileloco::connect_remote
::mobileloco::GetSpeed           ::mobileloco::Monitor            ::mobileloco::Stop               ::mobileloco::connect_port       ::mobileloco::genom_state
eltclsh > ::mobileloco::GetSpeed
current_speed {s ::mobileloco::SLOW}

pkill mobileloco-pocolibs
pkill genomix
h2 end

ros

tcl

ros-core &
mobileloco-ros &
genomixd &
eltclsh
eltclsh > package require genomix
1.0
eltclsh > genomix::connect
genomix1
eltclsh > genomix1 load mobileloco
pocolibs execution environment version 2.12.99
Copyright (c) 1999-2011 CNRS-LAAS
mobileloco
eltclsh > mobileloco::
::mobileloco::E_current_position ::mobileloco::GotoPosition       ::mobileloco::SetSpeed           ::mobileloco::abort_activity     ::mobileloco::connect_remote
::mobileloco::GetSpeed           ::mobileloco::Monitor            ::mobileloco::Stop               ::mobileloco::connect_port       ::mobileloco::genom_state
eltclsh > ::mobileloco::GetSpeed
current_speed {s ::mobileloco::SLOW}

pkill mobileloco-pocolibs
pkill genomix
h2 end

ros

Launch

ros-core &
mobileloco-ros &

Get info on your module:

export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$INSTALLDIR/build/ros/server/genom_mobileloco
export PYTHONPATH=/opt/ros/fuerte/lib/python2.6/dist-packages:$INSTALLDIR/lib/python2.6/site-packages
rosnode -info mobileloco

Send a command:

/opt/ros/electric/stacks/common/actionlib/tools/axclient.py /mobileloco/GotoPosition genom_mobileloco/GotoPosition
...

part2: Let's two modules play together

In this part, we will build a new module: mobile-disp, that will be able to display the result of the mobile-loco module (basically the mobile position in a graphical window). That will help us to learn, among other things, to write an asynchronous codels and to use an information coming from another module.

mobile-disp Module

mobile-disp.gen

We define two tasks:

#include "../mobile-loco/mobile-loco-struct.idl"
#include "../mobile-loco/mobile-loco-interface.gen"
#include "mobile-disp-struct.idl"

component mobiledisp {
version   "1.0";
email     "openrobots@laas.fr";
lang      "c";
uses      mobilelocointerface;
native dispInfo;
ids {
  dispInfo info;
};
task dispWindow {
     codel <start>      start_dispWindow(out info) yield waittill, stop;
     async codel <waittill>   waittill_dispWindow(inout info, port in E_current_position) yield waittill, cleanwin, up, down, stop;
     codel <cleanwin>   cleanwin_dispWindow(inout info) yield waittill;
     codel <up>         up_dispWindow(in SetSpeed, in GetSpeed) yield waittill;
     codel <down>       down_dispWindow(in SetSpeed, in GetSpeed) yield waittill;
     codel <stop>       stop_dispWindow() yield ether;
     throw memory_error, cannot_open_display;
};

task dispPosition {
     period 100ms;
     codel <start>      start_dispPosition(inout info) yield display, stop;
     codel <display>    display_dispPosition(in info, port in E_current_position) yield display, stop;
     codel <stop>       stop_dispPosition() yield ether;
     };

};

.configure.ac edition

PKG_CHECK_MODULES([X11],[x11])

codels/makefile.am edition

libxaff_codels_la_CPPFLAGS=     $(genom3_CFLAGS) $(X11_CFLAGS)
libxaff_codels_la_LDFLAGS=      -release $(PACKAGE_VERSION) $(X11_LIBS)

mobiledisp.h

Since it is not possible to use, e.g. Window type directly in idl. We have to define a dedicated structure in .h file:

#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>

struct mobiledisp_dispInfo{
  Window win;
  Display *dpy;
  Display *dpy2;
  GC gc;
  GC gc2;
  double x_orig;
  double y_orig;
};

That enable us to define in the .gen file:

native dispInfo;
ids {
  dispInfo info;
};

that we can use as codel parameter, e.g.:

codel <start>   start_dispWindow(out info) yield waittill, stop;

Inter-Module Communication

Interface Definition

We first need to share common data structures, that's why we import header files in the .gen files.

#include "../mobile-loco/mobile-loco-struct.idl"
#include "../mobile-loco/mobile-loco-interface.gen"

As we already seen, mobile-loco-struct.idl contains basic mobile-loco structure definition. Let's have a look on the mobile-loco-interface.gen file.

gupta[mobile-loco] more mobile-loco-interface.gen

interface mobilelocointerface {
port out mobileloco::position E_current_position;

ids{
 mobileloco::speed current_speed;
};
attribute SetSpeed(in current_speed=    :"Mobile speed");
attribute GetSpeed(out current_speed =  :"Mobile speed");
};

In this file, we define the interface that the mobile-loco module offers to the other ones. If you want to share data, you should define an output port: port out mobileloco::position E_current_position; If you want to share a service (this is only possible for attributes), you should define:

ids{
 mobileloco::speed current_speed;
};
attribute SetSpeed(in current_speed=    :"Mobile speed");
attribute GetSpeed(out current_speed =  :"Mobile speed");
};

To be able to use this interface, we first need to include the file and then declare in .gen file that we want to use it uses          mobilelocointerface;.

Data sharing

If you want to access to an output port. In the dispPosition task, we will use information coming from mobile-loco module to display the mobile position in the window. That is the purpose of the display codel in the task which will take as input the port offered by the mobile-loco module: codel <display>    display_dispPosition(in info, port in E_current_position) yield display, stop;

Then to use the data in your code, there is two steps:

E.g. in the following codel:

gupta[codels] more mobiledisp_dispPosition_codels.c
(...)

/** Codel display_dispPosition of task dispPosition.
 *
 * Triggered by display.
 * Yields to display, stop.
 */
mobiledisp_event
display_dispPosition(const mobiledisp_dispInfo *info,
                     const mobiledisp_E_current_position *E_current_position)
{
  int x, y ;
  E_current_position->read();
  if(E_current_position->data()!=NULL){
    x=info->x_orig + E_current_position->data()->x;
    y=info->y_orig - E_current_position->data()->y;
    XDrawPoint(info->dpy2, info->win, info->gc2, x, y);
    XSync(info->dpy2, True);
  }
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobiledisp_display;
}
(...)

You need to connect the two modules before being able to use this functionality, e.g. in our case in tcl

eltclsh> mobiledisp::connect_port E_current_position mobileloco/E_current_position

Service sharing

If you want to access to a service of another module. N.B In general case, it is not recommended to do so and it is anyway reserved to attribute function.

In the dispWindow task

     codel <up>         up_dispWindow(in SetSpeed, in GetSpeed) yield waittill;
     codel <down>       down_dispWindow(in SetSpeed, in GetSpeed) yield waittill;

Then to use the service in your code:

gupta[codels] more mobiledisp_dispWindow_codels.c
(...)
/** Codel down_dispWindow of task dispWindow.
 *
 * Triggered by down.
 * Yields to waittill.
 * Throws memory_error, cannot_open_display.
 */
mobiledisp_event
down_dispWindow(const mobiledisp_SetSpeed *SetSpeed,
                const mobiledisp_GetSpeed *GetSpeed)
{
  mobileloco_speed current_speed;
  printf("down_dispwin\n");
  GetSpeed->call(&current_speed);

  (... you can modify current speed in your code there...)

  SetSpeed->call(&current_speed);
  return mobiledisp_waittill;
}
(...)

You need to connect the two modules before being able to use this functionality, e.g. in our case in tcl

eltclsh> mobiledisp::connect_remote SetSpeed mobileloco/SetSpeed
eltclsh> mobiledisp::connect_remote GetSpeed mobileloco/GetSpeed

Running an OpenPRS supervisor controlling these 2 modules

You can build an OpenPRS supervisor to control the two modules (mobileloco and mobiledisp) following this tutorial.

OpenrobotsWiki: genom3/tutorial/two-modules (last edited 2013-10-14 03:54:43 by felix)