Difference between revisions of "Architecture Tutorial: Retrieve laser scans"

From The BABEL Development Site
(Overview)
(Calling getObservations)
Line 15: Line 15:
 
=== Calling ''getObservations'' ===
 
=== Calling ''getObservations'' ===
  
At the point in your module where you need to request the laser scans, this service from BS_RangeSensors must be invoked:
+
At the point in your module where you need to request the laser scans, the service "getObservations" from "BS_RangeSensors" must be invoked. This is the definition of that service, just to know how it looks like:
  
<cpp>
+
<center>
::getObservations(
+
[[Image:tut-scans_service.jpg]]
out SeqOfBytes SF,
+
</center>
out boolean error
+
 
)
+
 
</cpp>
+
To call that service, '''you must use the aracne-atom "request-synchronous&blocking"'''. It can be inserted in your code from the BABEL_MD menu.
 +
A dialog will appear asking you which module and service you want to call. Write this information by hand or by using the button "From ICE..." as in the image:
 +
 
 +
<center>
 +
[[Image:tut-scans_wizard1.jpg]]
 +
</center>
 +
 
 +
Accept and a wizard will appear asking you for the arguments of the service. Fill it out as in the figure:
 +
 
 +
<center>
 +
[[Image:tut-scans_wizard2.jpg]]
 +
</center>
 +
 
 +
 
 +
Now, this aracne atom must have some preparatory C++ code '''before''' it, and some C++ code '''after''' it to process the results.
  
For doing so, use the following fragment of code, explained in the comments.  
+
You can use the following fragments of code, self-explained in its comments.  
Pay attention to the label "YOUR CODE HERE" for the place where to process the laser scan.
+
'''Pay attention to''':
 +
* The label "YOUR CODE HERE" for the place where to process the laser scan.
 +
* The point "ARACNE_ATOM_HERE" at which the aracne atom "request-synchronous&blocking" must be inserted.  
  
 
Also, note that the macro #JMS-INCLUDE()#, if not inserted through the BABEL menu will NOT automatically add the dependency to your module, so it is recommended to either add the dependency on "BS_RangeSensors::getObservations" manually (first BABEL_MD tab, "Deps" button) or to insert the JMS macro from the menu and fill the parameters by hand (see the correct order of the parameters in the code below).
 
Also, note that the macro #JMS-INCLUDE()#, if not inserted through the BABEL menu will NOT automatically add the dependency to your module, so it is recommended to either add the dependency on "BS_RangeSensors::getObservations" manually (first BABEL_MD tab, "Deps" button) or to insert the JMS macro from the menu and fill the parameters by hand (see the correct order of the parameters in the code below).
Line 41: Line 57:
 
bool err_var;                              // BABEL communication error?
 
bool err_var;                              // BABEL communication error?
  
#JMS-INCLUDE(INC_request-synchronous&blocking,"getObservations","BS_RangeSensors","getObservations","REMOTE_BS_RangeSensors_var","SF,sensorError","err_var","0","INF","","","")#
+
/** ARACNE_ATOM_HERE  **/
  
 
// Error? Propagate it:
 
// Error? Propagate it:
 
if (err_var)
 
if (err_var)
 
{
 
{
std::cerr << "[OnNewRangeData] *** ERROR querying the module *** " << std::endl;
+
// process error
 
}
 
}
  
Line 69: Line 85:
 
catch(std::exception &e)
 
catch(std::exception &e)
 
{
 
{
std::cerr << "Exception parsing binary object: " << std::endl << e.what() << std::endl;
+
// Process ERROR, message in e.what()
 
}
 
}
 
}
 
}
Line 89: Line 105:
 
// Access to the object data members to get the scan data.
 
// Access to the object data members to get the scan data.
 
// Refer to: http://babel.isa.uma.es/mrpt/reference/svn/classmrpt_1_1slam_1_1_c_observation2_d_range_scan.html
 
// Refer to: http://babel.isa.uma.es/mrpt/reference/svn/classmrpt_1_1slam_1_1_c_observation2_d_range_scan.html
// Example:
+
// Examples:
cout << "Scan size: " << laserScan->scan.size() << endl;
+
//  Scan size: laserScan->scan.size()
cout << "Scan point[0]: " << laserScan->scan[0] << endl;
+
//  Scan point[0]: laserScan->scan[0]
cout << "Scan point[0] is valid: " << laserScan->validRange[0]!=0 ? "Yes" : "No" << endl;
+
//  Scan point[0] is valid: laserScan->validRange[0]!=0
 
}
 
}
 
else
 
else

Revision as of 09:18, 23 July 2009

Overview

Following the Robotic Architecture proposed here, laser scans from either a simulated or a real robot should be accessible from a single module, named BS_RangeSensors.

The interface of this module is described in this section and this tutorial explains how to write a client module to query the latest laser scans from BS_RangeSensors.


Notice that this tutorial only covers the specific case of implementing a module with the C/C++ language.



Steps

Calling getObservations

At the point in your module where you need to request the laser scans, the service "getObservations" from "BS_RangeSensors" must be invoked. This is the definition of that service, just to know how it looks like:

Tut-scans service.jpg


To call that service, you must use the aracne-atom "request-synchronous&blocking". It can be inserted in your code from the BABEL_MD menu. A dialog will appear asking you which module and service you want to call. Write this information by hand or by using the button "From ICE..." as in the image:

Tut-scans wizard1.jpg

Accept and a wizard will appear asking you for the arguments of the service. Fill it out as in the figure:

Tut-scans wizard2.jpg


Now, this aracne atom must have some preparatory C++ code before it, and some C++ code after it to process the results.

You can use the following fragments of code, self-explained in its comments. Pay attention to:

  • The label "YOUR CODE HERE" for the place where to process the laser scan.
  • The point "ARACNE_ATOM_HERE" at which the aracne atom "request-synchronous&blocking" must be inserted.

Also, note that the macro #JMS-INCLUDE()#, if not inserted through the BABEL menu will NOT automatically add the dependency to your module, so it is recommended to either add the dependency on "BS_RangeSensors::getObservations" manually (first BABEL_MD tab, "Deps" button) or to insert the JMS macro from the menu and fill the parameters by hand (see the correct order of the parameters in the code below).


<cpp> using namespace mrpt; using namespace mrpt::utils; using namespace mrpt::slam;

// Retrieve the latest laser scan // ----------------------------------------------------- BABEL::BS_RangeSensors::SeqOfBytes *SF; // The sequence of bytes sent by the server module BABEL::Boolean sensorError; // Sensor error? bool err_var; // BABEL communication error?

/** ARACNE_ATOM_HERE **/

// Error? Propagate it: if (err_var) { // process error }


CObservation2DRangeScanPtr laserScan; // A smart-pointer to the laser scan (read below)

if (!err_var && !sensorError) { try { // De-serialize the object: mrpt::utils::CSerializablePtr obj = SeqOfBytes2MRPTObject(SF);

// Assure it's a valid observation: ASSERT_(obj) ASSERT_( IS_CLASS(obj,CSensoryFrame) )

CSensoryFramePtr theSF = CSensoryFramePtr(obj);

laserScan = theSF->getObservationByClass<CObservation2DRangeScan>(); // Get the first scan, if any. } catch(std::exception &e) { // Process ERROR, message in e.what() } }

// Free memory of the Sequence if (!err_var) { delete SF; SF = NULL; }


// Now, we have the latest scan laser in the variable "laserScan", which // is a smart pointer to a mrpt::slam::CObservation2DRangeScan // ------------------------------------------------------------------------- if (laserScan) { // ******* YOUR CODE HERE ************** // Access to the object data members to get the scan data. // Refer to: http://babel.isa.uma.es/mrpt/reference/svn/classmrpt_1_1slam_1_1_c_observation2_d_range_scan.html // Examples: // Scan size: laserScan->scan.size() // Scan point[0]: laserScan->scan[0] // Scan point[0] is valid: laserScan->validRange[0]!=0 } else { // For some reason (comms error, hardware error, etc...) there is no laser scan. }

</cpp>

Auxiliary code

Add the following auxiliary function to your module "Auxiliary logic" section, since this function is used in the code above:

<cpp> // SeqOfBytes2MRPTObject: Convert a BABEL sequence of bytes into a MRPT object. // IMPORTANT: "T of seqofbytes" must be a POINTER to a BABEL sequence, not a reference to it. template <typename T> mrpt::utils::CSerializablePtr SeqOfBytes2MRPTObject(const T &seqofbytes) { if (seqofbytes->length()==0) return mrpt::utils::CSerializablePtr(); mrpt::utils::CMemoryStream memBlock;

	memBlock.assignMemoryNotOwn(&(*seqofbytes)[0], seqofbytes->length() );

return memBlock.ReadObject(); } </cpp>

Non-deportabilities of the module

If your module didn't use MRPT before adding these code fragments, it must be inserted by:

  • Selecting the tab "Non-deportabilities" in BABEL_MD.
  • Select "Execution".
  • Add "mrpt-core" from the list below.
  • Save the module.

You'll need MRPT installed as explained here.