To get you started on MOOS-IvP, let's take a step-by-step approach to making complex vehicles. Valentino Braitenberg in his book Vehicles, Experiments in synthetic psychology builds complex robotic behaviors from very simple sensor to actuator link.
In this first chapter of MOOS-IvP tutorials, the first vehicle described will be built.
Vehicle 1 is a very simple vehicle that has only one sensor and one actuator. The output of the sensor is directly linked to the input of the actuator.
Let's consider the sensor a light sensor, and the actuator a motor mounted on a wheel. To simulate such a system, three applications are required:
- a source generator,
- a sensor interface, and
- a motor controller/vehicle simulator.
The source application will only indicate the coordinates of the source and it's intensity.
The application to simulate the light source will be named uLightSource and configured using:
- the intensity
I, - the position of the source set by
SOURCE_XandSOURCE_Y.
The sensor interface is simulates and computes the intensity received by the light sensor.
The application to simulates the sensor will be named uLightSensor and configured using:
- the sensitivity
S.
The first vehicle that will be simulated is extremely simple.
It only goes forward and it's speed is proportional to the intensity given by the light sensor.
Therefore it is possible in the application uSimVehicle1 to configure:
- the ratio
Kbetween the intensity given by the vehicle and the output of the motor, - the
MAX_SPEEDof the vehicle, - the initial position of the vehicle set by
START_X,START_Y, andSTART_HEADING.
Vehicle 1 experiment is very easy to implement as the system is particularly simple.
This git repository contains the following branches:
masterbranch contains the skeleton and the instructions on how to build the applications01-uLightSource-finalcontains a proposed solution of theuLightSourceapplication.02-uLightSensor-finalcontains a proposed solution for theuLightSensorapplication.03-uSimVehicle1-finalcontains a proposed solution for theuSimVehicle1application.04-final-projectcontains a complete simulation of the system described above.
Once done with each of the following steps, one can checkout the corresponding branch and see the difference between the proposed solution and what was proposed.
The light source is the simplest MOOS application one can imagine.
Once the application is connected to the MOOSDB, it needs to publish the value of the intensity of the source.
First, let's download the repository and make sure we are on the master branch:
git clone https://github.com/moos-tutorials/01-getting-around-vehicle-1.git
cd 01-getting-around-vehicle-1
git checkout masterLet's call the GenMOOSAppTutorial.sh script to create the skeleton of our uLightSource app:
bash ./GenMOOSAppTutorial.sh LightSource u "Your Name Here"A new folder src has now appeared with a CMakeLists.txt file and a uLightSource directory.
Let's add the local attributes of this class called m_intensity, m_x, and m_y to the LightSource in LightSource.h file.
private: // Configuration variables
double m_intensity;
double m_x, m_y;And it should be given a default value of 0.0 at the constructor in the LightSource.cpp:
LightSource::LightSource(): m_intensity(0.0),
m_x(0.0), m_y(0.0)
{
}The value of the intensity can be setup at the configuration as a variable I, as of START_X and START_Y.
This can be done in the OnStartUp() method call (the examples FOO and BAR have been removed) :
if(param == "I") {
m_intensity = atof(line.c_str());
handled = true;
} else if(param == "START_X") {
m_x = atof(line.c_str());
handled = true;
} else if(param == "START_Y") {
m_y = atof(line.c_str());
handled = true;
}A good practice is to keep the *_Info.* file up-to-date with the development of the current application.
In the uLightSource_Info.cpp add the relevant information in the showExampleConfigAndExit() function.
Next, the application should publish the intensity at each iteration for instance.
In the Iterate() method, let's add the following call that will publish the value of the intensity to the MOOSDB:
Notify("ULSOURCE_INTENSITY", m_intensity);
Notify("ULSOURCE_POS_X", m_x);
Notify("ULSOURCE_POS_Y", m_y);This MOOS function call will publish a variable ULSOURCE_INTENSITY with the corresponding value of m_intensity immediately.
The MOOSDB will also be notified by the position of the source the same way.
It would be helpful to change the value of the intensity dynamically without having to launch the app.
To do so, let the app subscribe to a variable 'ULSOURCE_SET_INTENSITY' in the registerVariables() method:
Register("ULSOURCE_SET_INTENSITY");And the new value is to be processed in the OnNewMail() method:
if(key == "ULSOURCE_SET_INTENSITY")
m_intensity = msg.GetDouble();AppCasting is the capacity of an app to broadcast relevant information that a human can easily parse.
We will not get into the detail of AppCasting here, but our app would give us more information if we can easily acces a report about it's configuration and current status:
bool LightSource::buildReport()
{
m_msgs << "Configutation \n";
m_msgs << "============================================ \n";
ACTable actab(3);
actab << "Position X | Position Y | Intensity";
actab.addHeaderLines();
actab << m_x << m_y << m_intensity;
m_msgs << actab.getFormattedString();
return(true);
}Once the uLightSource_Info.cpp file has been updated too, it is time to build the project using the provided build.sh script.
bash ./build.shA solution is provided in the bran 01-uLightSource-final.
To check your code against the provided solution, a proposed way is to stash the changes and see the difference when the branch has been checked out:
git stash
git checkout 01-uLightSource-final
git stash pop
git diffThe commands below will print out the differences between your modifications and the ones proposed.
There's multiple ways you can write software and MOOS is no exception.
Moreover, git will make sure that everything is exactly the same, even the number of space.
You can either overwrite the proposed solution with yours or continue with the solution by stashing back your code (git stash).
The light sensor is also not very complicated. The app must subscribe to :
ULSOURCE_INTENSITY, to read the value of the intensityULSOURCE_POS_XandULSOURCE_POS_Yto compute the intensity of illumination atNAV_X,NAV_Ythe vehicle's position,ULSENSOR_SET_SENSITIVITYto set dynamically the sensitivity.
The app should also publish the:
ULSENSOR_READINGthat can be computed via this equation:
ULSENSOR_READING = S/(sqr(NAV_X-ULSOURCE_POS_X)+sqr(NAV_Y-ULSOURCE_POS_Y))Finally, the app should accept a configuration variable:
- the sensitivity
S.
When done programming the uLightSensor application, please cross check your solution with the provided solution in 02-uLightSensor-final
For the vehicle itself it just needs to read the following configutation variables:
Kthe factor betweenULSENSOR_READINGthe vehicle'sNAV_SPEED.MAX_SPEEDof the vehicle,- the initial position
START_X,START_Y, andSTART_HEADING.
It is supposed to subscribe to
ULSENSOR_READING.
And it is also supposed to publish the location from a simple Euler integration schema:
NAV_X,NAV_YandNAV_HEADING,NAV_SPEED.
To compute the NAV_X and NAV_Y:
NAV_X = NAV_X + h*cos(headingToRadians(NAV_HEADING))*NAV_SPEED
NAV_Y = NAV_Y + h*sin(headingToRadians(NAV_HEADING))*NAV_SPEEDNOTE: NAV_HEADING is in degrees and zeroed at North.
It is mandatory to use the headingToRadians() functions that is part of the geometry MOOS-IvP library and including the header file AngleUtils.h
When done coding the uSimVehicle1 application, please cross check your solution with the provided solution in 03-uSimVehicle1-final.