Simulation of MagTrackingSensor application

Contents:


This document talks about the simulation of MagTrackingSensor application using Nido.

The real magnetometer

The magnetometer on the motes are 2-axis magnetometer sensor (Honeywell HMC1002). According to sources found on the web, this sensor senses the strength of magnetic fields and the direction relative to the mote by providing separate readings for x and y direction. In the MagTrackingSensor application the direction information is not used, instead the sum of the readings is returned as sensor reading.

Compilation of MagTrackingSensor for the simulator

In order to make the MagTrackingSensor application compile for a PC executable, at least the magnetometer components have to be replaced by some simulation of the magnetometer sensor. The original magnetometer component that is used by the MagTrackingSensor application is MagU16C.nc. It uses the MagSumXYM component, which accesses the actual hardware component getting the information from the magnetometer from the sensor board. In order to decouple the application from the hardware, we simply exchanged these two component by two "dummy" components MagU16SimC and MagSumXYMSim. In the latter component the sensor reading is replaced by some placeholder for now, which signals a "readDone" event immediately after it receives the request to read its value. For now, it returns a dummy value; we first want to make it compile; later we have to put some work here in order to simulate the magnetometer readings.

Problem with GuiMsg.h

Having replaced the magnetometer components, the "make pc" command still gives loads of error messages. Enough to consider giving up.... The error log contained a lot of "syntax errors" in some header files. After some analysis, we found out that the problem was that Berkeley is using a modified version of the central "AM.h" file; the file that defines things like TOS_MsgPtr etc.. The Nido executable includes AM.h in a file called "GuiMsg.h", which works fine, if it finds there the original AM.h in tos/system, but wasn't working with the customized AM.h version in ucb/routing/AM.h, because the latter uses definition contained in a file "Routing.h" in the same directory, so that the customized AM.h is no longer "stand-alone" in contrast to the original version of AM.h.

Fortunately, the solutation was very simple: instead of "AM.h" include "Routing.h" in GuiMsg.h, which we did in a copy of GuiMsg.h, which we placed in the routing directory. (This file is found prior to the original GuiMsg.h). With this change "make pc" compiled successfully.

Getting it to work...

Mote id's / Mote Positions by address

In Nido, you can specify mote id's consecutively; the id's always start from 0 upto the number of motes you have specified on the command line. This is a problem, because the MagTrackingSensor application uses the mote id's to encode the position of the motes, see MagTrackingDemo README file. In principle, there are two ways to get around this problem:

  1. Modify Nido to accept non-consecutive mote ids
  2. Modify the MagTracking application in a way that the built-in coordinates are assigned to mote ids from 0..n.
  3. Modify Nido to use only a restricted set of motes

First, we thought the first solution was better, at least it would be more elegant and at the same time it would extend Nido's functionality. After inspecting the Nido code in more detail, we figured out, that this solution is unpractibale, because Nido uses the mote id's directly as array indices for its internal representation of the collection of motes involved in a simulation. The Nido designers didn't consider cases like this, where non-consecutive mote id's are needed and didn't build in a suitable abstraction level for mote id's. So realizing solution 1) would mean changing the internals of Nido, which would not be impossible, but rather error-prone, because we don't know the internals well enough.

The second solution was the one we tried thereafter, but it turned out to be at least as complicated, because the dependency of the mote address and its position is hidden in several places in the code and it seems to be too risky to interfere with this. There are at least two places in the code, where the address is used to determine the position:

The latter was especially hard to find, because in general it is extemely difficult to follow the flow of control in a NesC application. In addition, Berkeley uses perl scripts that generate part of their code which makes it nearly impossible to comprehend the application structure by looking at the code.

Restricting mote ids in Nido

So, we have to modify Nido to only enable a certain set of mote id's and ignore the others. This is not the most elegant solution, but seems to be the least painful wrt. changes that need to be done.

The solution is working as long as the mote ids we are interested in are below 1000, which is the case for us; we are interested in mote ids 0x200 to 0x2ff hex, which is 512 to 767 decimal.

What needs to be modified for this? Fortunately, that is not very hard, basically we only need to prevent Nido from initializing and starting all motes we are not interested in. We therefore copied the original Nido.nc in tinyos-1.x/tos/platform/pc to the application directory in order to make the corresponding changes. When the application compiles, the local Nido.nc is found instead of the original one. Here's how the change works:

How to place the motes on the simulation area?

We need to have some way of specifying

  1. Which motes are involved in the simulation?
  2. Where shall they places on the simulation area?
The first item could be answered in simply enumerating the motes following the scheme of mote ids for the tracking example, that means if we want to have a 3x3 array of motes, we would have to specify
0x200 0x210 0x220
0x201 0x211 0x221
0x202 0x212 0x222
as mote ids. This could be done, but is extremely tedious, because the above mentioned "check_moteid" would have to be changed each time we change the number of motes we want to take part in the simulation. Therefore, we introduced 2 global constants "mote_layout_xmax" and "mote_layout_ymax", which can be set to the number of motes we want to have in x-direction and the number of motes we want to have in y-direction. The above implementation of check_moteid uses these constants to filter out those mote id, that are not part of the mote array of the specified size.

Although the mote position is determined using the mote id, we still need some "real" simulation constants in order to, for instance, visualize the motes (and the target), and to determine the distance between a mote and the simulated target (which we will explain below).

Using this parameters, the valid mote ids are determined (see above code for "check_moteid") and the positions of the mote are calculated; they are distributed equidistantly (in each direction) over the hatched area.

This parameter are contained in the above mentioned MoteLayout.h file. The implementation of the check_moteid() function is also contained in that file, as well as some other items that will be mentioned later.

Where does the estimation go to?

In the original configuration, the estimation is sent to the camera pointer mote, which has a pre-defined mote-id (0x300) and which controls the camera to point to the estimated position. In the simulation, there is a problem with that, because we can only run identical NesC code on all motes involved in the simulation; we cannot load different code on different motes in the simulations. So, where should the target estimation that is sent by the tracking motes go to?

A possible answer is, that it is simply send as a debug message and the gui then evaluates it to display the estimated target position. In order to realize that, we must look for the place in the MagTrackingSensor code, where the estimation is sent to the camera mote. This is done in component EstimationCommM,task forwarder(). We therefore simply inserted a "sendToGui" call instead of the SendCameraPointer.send call. The simulation gui will receives the estimation position in the same way as the simulation coordinates of the motes: using debug messages (more details see below).

What values are returned by the magnetometer sensor?

In order to implement a realistic simulation for the magnetometer, we had to set up an experiment to print out the values that are returned with the signaling of the magnetometer's readDone() event. In the original implementation these values are determined in the MagSumXYM component in the event handler BottomMagSensor.readDone() which handles events from lower level hardware components. As one can see there, the values for the x- and y-direction are added and the sum is returned. This value is propagated to the higher-level components by signaling a U16Sensor.readDone event. This event is then handled in the MagEstimationM component and processed to determine a target estimate.

In order to figure out, what values are returned there, we simply inserted code that sends this value to the PC using the tinyos module "IntToRfm". We then took the toy car and put it aside the mote with the magnetometer sensor. These experiments had the following result:

What about the simulated target?

So far, so good. But no target tracking without a target, even in simulated target tracking... So we have to implement a simulated target.

In terms of the simulator, the moving target is simply an object with at least one attribute: its current position, which can be queried from inside the simulator in order to simulate, e.g. magnetometer readings. So the most simple interface a target has to provide is a function "get_target_position()", which we have implemented in C-files sim_target.h and sim_target.c.

The header file shows the interface; as shown there, a file "target_positions.h" is included which contains the actual positions of the target as an array of doubles: target_positions. Each two elements of that array define a position of the target; the first and the last point should not be farther apart than other two intermediate points, because the target_position array is re-iterated again and again as long the simulation runs.

The values in the target_position array are interpreted as relative positions in the above described simulation area. That means that they should range between 0 and 1; where 0 for an x-coordinate means the very left edge of the motes area; and 1 the very right edge. For y-ccordinate 0 means top edge and 1 bottom edge. Using this relative coordinates makes the positioning of the target much more flexible, because if the simulation area parameters are changed in MoteLayout.h, the path of the target is adjusted accordingly.

Example:

double target_positions[] = {
   0,  0,    // top-left corner
   0.5,0,    // middle of the top edge
   1,  0,    // top-right corner
   1  ,0.5,  // middle of right edge
   1  ,1,    // bottom-right corner
   0.5,1,    // middle of bottom edge
   0,  1,    // bottom-left corner
   0,0.5     // middle of left edge
};

How does the target move?

The movement of the simulated target is triggered by calling "move_target" in sim_target.c. This function simply sets the current target position stored in the variable "target_coords" to the next (x,y) pair found in the target_positions array and increments the "tpos_index" counter by 2, because that's the begin index of the next x,y pair in the target_positions array. If the tpos_index gets bigger than the length of the target_positions array (which must be set in the variable target_positions_length) then it's simply set back to 0 meaning that the target goes back to its initial position and starts the same path again.

The question is now: who calls "move_target()" in order to let the simulated target change its position?
It must be connected with the time used in the simulator in order to achieve a realistic speed of the target. So the easiest thing to do is to used the simulated timer of the motes to move the target periodically. By that, we can be sure, that the speed of the target is appropiate, because we can specify the frequency, how often the target is moved per second.

In order to realize that, we simply introduce a new interface "TargetTimer" in the toplevel component MagEstimation.nc and connect it to the "TimerC" component. In the StdControl.start command of MagEstimationM the target timer is initialized and the move_targer() function is called from the event handler TargetTimer.fired(). In that event handler, we have hard-coded, that mote with id 0x200 is "responsible" for moving the target. Any other (active) mote could have been chosen.

There is a small utility called "target-route-from-tgif" in $TOSROOT/kestrel-tinyos/bin that generates an appropiate target_positions.h file from an input file generated by the unix drawing program "tgif". The tgif file must contain just one "Freeform" object, the coordinates of which are translated into the appropiate form.

"Calibration" of the simulated magnetometer

Let's have a closer look at the code simulating the magnetometer. It has to resemble the behaviour of the real magnetometer, which is sketched above and it must return values that are suitable for the simulation area model described here. The code of the U16Sensor.read() command in the (new) MagSumXYMSim component contains the code for the simulated magnetometer. It is called, whenever a mote requests a value from its magnetometer sensor, which is periodically several times per second. Informally, the following steps are carried out:

The above mentioned threshold can be configured in the MoteLayout.h file as "magnetometerDistanceThreshold"; its "calibrated" value is 120, but this can be changed if it proves not to be appropiate.

"Returning a sensor reading" actually means that after a built-in delay of a few msec the "readDone()" event is signaled, which causes the connected event handlers to be executed and react on the new magnetometer value.

The simulated target tracking at work

With all these extensions and modifications, we were now starting to make experiments with the running simulation in order to find out whether the target estimates really follow the movement of the target. The way to find out about it is via debug messages inserted into the code. There are messages showing information about the following things:

Furthermore, more for debugging purposes, messages are issued containing information about Running the simulator in terminal mode shows, that messages of each kind are generated, especially the target estimates, which shows that at least something's working.

Simulation Gui

For having more relieable results, we had to use some kind of graphical visualization of the tracking. First we were planning to extend TinyViz to interpret the several debug messages and display appropiate things in addition to the mote positions which are already shown in that tool. Unfortunately, TinyViz proved to be way too slow for displaying the target tracking simulation: a debug message that would appear after a few seconds in the terminal version didn't show up when running with the TinyViz gui connected after a minute; the simulated target didn't even start to move after 2 minutes. One of the reasons for this is, that TinyViz doesn't know about or restricted set of motes and there is no way of telling it to only use certain motes other than making them invisible.

After that experience we decided to use the Tcl-based visualization interface that we have used in 2002's PI-meetings when we demoed the motes. This tool is very light-weighted compared to the TinyViz Java elephant, has a very slim interface, and can be connected via stdin/stdout. The basic commands are very simple: adding a node, adding an edge, moving a node. Because that's all what we need, this seemed to be appropiate.

The connection between the simulator and the Tcl-Gui is done with a very simple perl-script which starts the simulator as an output process and the Tcl-Gui as an input process. The script then scans the messages send from the simulator and turns them into appropiate commands for adding nodes, edges, moving nodes etc. for the Gui. The script is named "simulate_tt" and can be found in the MagTrackingSensor directory.

It shows the simulation area with 9 motes on a 3x3 grid; the mote id's correspond to the above mentioned address-to-position scheme. The orange circle labeled "T" is the simulated target; the white spot is centered at the previously issued target estimation coordinates; it resembles the area where the camera would focus to. The dashed arrows represent secondary information about the connectivity of the motes graph. (The screenshot is taken right at the beginning of the run, the connectivity will increase.) The arrow from mote 0x212 to 0x200 displays the sending of a target estimate message.

Building and Running the simulation

The simulation of MagTrackingSensor application build using the

    make pc
call in the $TOSROOT/kestrel-tinyos/apps/ucb/MagTrackingSensor directory. The simulation including the graphical gui is started by calling
    ./simulate_tt
on the command line in that directory.

If, for some reason, the terminal application has to be started alone, then use the command

   run-simulation 999
which just calls the generated Nido executable build/pc/main.exe. This would normally start Nido with 999 nodes, but because of our filter mechanism of mote id, only the ones specified by the parameters in MoteLayout.h are used in the simulation.
Last modified: Thu May 22 15:06:53 PDT 2003