Revision: 8931
          http://playerstage.svn.sourceforge.net/playerstage/?rev=8931&view=rev
Author:   jpgr87
Date:     2010-10-04 01:48:36 +0000 (Mon, 04 Oct 2010)

Log Message:
-----------
Re-enable "laserfeature" driver and update documentation section

Modified Paths:
--------------
    code/player/trunk/server/drivers/fiducial/CMakeLists.txt
    code/player/trunk/server/drivers/fiducial/laserfeature.cc

Modified: code/player/trunk/server/drivers/fiducial/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/fiducial/CMakeLists.txt    2010-10-01 
21:58:08 UTC (rev 8930)
+++ code/player/trunk/server/drivers/fiducial/CMakeLists.txt    2010-10-04 
01:48:36 UTC (rev 8931)
@@ -9,3 +9,6 @@
 
 PLAYERDRIVER_OPTION (laservisualbw build_laservisualbw OFF "Has not been 
updated to use dynamic message structures; will segfault.")
 PLAYERDRIVER_ADD_DRIVER (laservisualbw build_laservisualbw SOURCES 
laservisualbw.cc)
+
+PLAYERDRIVER_OPTION (laserfeature build_laserfeature ON)
+PLAYERDRIVER_ADD_DRIVER (laserfeature build_laserfeature SOURCES 
laserfeature.cc)
\ No newline at end of file

Modified: code/player/trunk/server/drivers/fiducial/laserfeature.cc
===================================================================
--- code/player/trunk/server/drivers/fiducial/laserfeature.cc   2010-10-01 
21:58:08 UTC (rev 8930)
+++ code/player/trunk/server/drivers/fiducial/laserfeature.cc   2010-10-04 
01:48:36 UTC (rev 8931)
@@ -26,7 +26,7 @@
 // CVS: $Id$
 //
 // Theory of operation - Uses an EKF to segment the scan into line
-// segments, the does a best-fit for each segment.  The EKF is based
+// segments, then does a best-fit for each segment.  The EKF is based
 // on the approach by Stergios Romelioutis.
 //
 // Requires - Laser device.
@@ -37,14 +37,84 @@
 /** @{ */
 /** @defgroup driver_laserfeature laserfeature
  * @brief Extract line/corner features from a laser scan.
- 
-...@todo This driver is currently disabled because it needs to be updated to
-the Player 2.0 API.
 
-...@todo Document this driver.
+The laserfeature driver extracts lines and corners from a laser data scan,
+and returns the 2-d positions of each line segment through the Fiducial
+interface.
 
-...@author Andrew Howard
-*/
+laserfeature uses an EKF to segment the scan into line
+segments, then does a best-fit for each segment.  The EKF is based
+on the approach by Stergios Romelioutis.
+
+...@par Compile-time dependencies
+
+- none
+
+...@par Provides
+
+- @ref interface_fiducal
+  - This interface returns a list of features extracted from the laser scan.
+
+...@par Configuration requests
+
+- fiducial interface
+  - PLAYER_POSITION2D_REQ_FIDUCAL_GEOM
+
+...@par Requires
+
+- @ref interface_laser
+  - Laser scan to find lines in
+
+...@par Configuration file options
+
+- model_range_noise (length)
+  - Default: 0.02 m
+  - Expected range noise in laser measurements
+
+- model_angle_noise (angle)
+  - Default: 10 degrees
+  - Expected angular noise in laser measurements
+
+- sensor_range_noise (length)
+  - Default: 0.05 m
+  - Expected range noise in laser sensor.
+
+- segment_range (length)
+  - Default: 0.05m
+
+- merge_angle (angle)
+  - Default: 10 degrees
+
+- discard_length (length)
+  - Default: 1.00 m
+  - Threshold for segment length (smaller segments are discarded)
+
+- min_segment_count (int)
+  - Default: 4
+  - Minimum amount of segments needed to publish Fiducial data
+
+...@par Example
+
+...@verbatim
+driver
+(
+  name "laserfeature"
+  provides ["fiducial:0"]
+  requires ["laser:0"]
+
+  model_range_noise 0.05
+  angle_range_noise 10
+  sensor_range_noise 0.05
+  segment_range 0.05
+  merge_angle 10
+  discard_length 1.00
+  min_segment_count 4
+
+)
+...@endverbatim
+
+...@author Andrew Howard, Rich Mattes
+ */
 /** @} */
 
 #include <errno.h>
@@ -57,399 +127,334 @@
 #include <libplayercore/playercore.h>
 
 // Driver for detecting features in laser scan.
-class LaserFeature : public Driver
+class LaserFeature : public ThreadedDriver
 {
-  // Constructor
-  public: LaserFeature( ConfigFile* cf, int section);
+public:
+       // Constructor
+       LaserFeature( ConfigFile* cf, int section);
 
-  // Setup/shutdown routines.
-  public: virtual int Setup();
-  public: virtual int Shutdown();
+       // Setup/shutdown routines.
+       virtual int MainSetup();
+       virtual void MainQuit();
 
-  // Client interface (this device has no thread).
-  public: virtual size_t GetData(void* client,unsigned char *dest, 
-                                 size_t maxsize, uint32_t* timestamp_sec, 
-                                 uint32_t* timestamp_usec);
+       virtual void Main();
 
-  // Client interface (this device has no thread).
-  public: virtual int PutConfig(player_device_id_t* device, void *client, 
-                                void *data, size_t len);
+       // Message Handling routine
+       virtual int ProcessMessage (QueuePointer &resp_queue, player_msghdr * 
hdr, void * data);
 
-  // Process laser data.  Returns non-zero if the laser data has been
-  // updated.
-  private: int UpdateLaser();
+private:
+       // Process laser data.  Returns non-zero if the laser data has been
+       // updated.
+       int UpdateLaser();
 
-  // Write laser data to a file (testing).
-  private: int WriteLaser();
+       // Write laser data to a file (testing).
+       int WriteLaser();
 
-  // Read laser data from a file (testing).
-  private: int ReadLaser();
+       // Read laser data from a file (testing).
+       int ReadLaser();
 
-  // Segment the scan into straight-line segments.
-  private: void SegmentLaser();
+       // Segment the scan into straight-line segments.
+       void SegmentLaser();
 
-  // Update the line filter.  Returns an error signal.
-  private: double UpdateFilter(double x[2], double P[2][2], double Q[2][2],
-                               double R, double z, double res);
+       // Update the line filter.  Returns an error signal.
+       double UpdateFilter(double x[2], double P[2][2], double Q[2][2],
+                       double R, double z, double res);
 
-  // Fit lines to the segments.
-  private: void FitSegments();
+       // Fit lines to the segments.
+       void FitSegments();
 
-  // Merge overlapping segments with similar properties.
-  private: void MergeSegments();
+       // Merge overlapping segments with similar properties.
+       void MergeSegments();
 
-  // Update the device data (the data going back to the client).
-  private: void UpdateData();
+       // Update the device data (the data going back to the client).
+       void PublishFiducial();
 
-  // Process requests.  Returns 1 if the configuration has changed.
-  private: int HandleRequests();
+       // Process requests.  Returns 1 if the configuration has changed.
+       int HandleRequests();
 
-  // Handle geometry requests.
-  private: void HandleGetGeom(void *client, void *req, int reqlen);
+       // Handle geometry requests.
+       void HandleGetGeom(void *client, void *req, int reqlen);
 
-  // Device pose relative to robot.
-  private: double pose[3];
-  
-  // Laser stuff.
-  private: int laser_index;
-  private: Driver *laser_device;
-  private: player_laser_data_t laser_data;
-  private: uint32_t laser_timesec, laser_timeusec;
+       // Device pose relative to robot.
+       double pose[3];
 
-  // Line filter settings.
-  private: double model_range_noise;
-  private: double model_angle_noise;
-  private: double sensor_range_noise;
+       // Laser stuff (the laser we require)
+       Device *laser_device;
+       player_laser_data_t laser_data;
+       player_devaddr laser_id;
+       bool have_new_scan;
 
-  // Threshold for segmentation
-  private: double segment_range;
+       // Fiducial stuff (the data we generate).
+       player_fiducial_data_t data;
+       player_devaddr_t fiducial_id;
+       uint32_t timesec, timeusec;
 
-  // Thresholds for merging.
-  private: double merge_angle;
+       // Line filter settings.
+       double model_range_noise;
+       double model_angle_noise;
+       double sensor_range_noise;
 
-  // Thresholds for discarding.
-  private: double discard_length;
+       // Threshold for segmentation
+       double segment_range;
 
-  // Segment mask.
-  private: int mask[PLAYER_LASER_MAX_SAMPLES];
+       // Thresholds for merging.
+       double merge_angle;
 
-  // Description for each extracted line segment.
-  private: struct segment_t
-  {
-    int first, last, count;
-    double pose[3];
-    double length;
-  };
+       // Thresholds for discarding.
+       double discard_length;
 
-  // List of extracted line segments.
-  private: int segment_count;
-  private: segment_t segments[PLAYER_LASER_MAX_SAMPLES];
+       // How many segments need to be found before any are reported
+       int min_segment_count;
 
-  // TESTING
-  private: FILE *laser_file;
+       // Segment mask.
+       int mask[4096];
 
-  // Fiducila stuff (the data we generate).
-  private: player_fiducial_data_t data;
-  private: uint32_t timesec, timeusec;
+       // Description for each extracted line segment.
+       struct segment_t
+       {
+               int first, last, count;
+               double pose[3];
+               double length;
+       };
+
+       // List of extracted line segments.
+       int segment_count;
+       segment_t segments[4096];
+
 };
 
 
 // Initialization function
 Driver* LaserFeature_Init( ConfigFile* cf, int section)
 {
-  if (strcmp( PLAYER_FIDUCIAL_STRING) != 0)
-  {
-    PLAYER_ERROR1("driver \"laserfeature\" does not support interface 
\"%s\"\n",
-                  interface);
-    return (NULL);
-  }
-  return ((Driver*) (new LaserFeature( cf, section)));
+       return reinterpret_cast <Driver*> (new LaserFeature (cf, section));
 }
 
-
-// a driver registration function
-void LaserFeature_Register(DriverTable* table)
+// Driver registration function
+void laserfeature_Register(DriverTable* table)
 {
-  table->AddDriver("laserfeature", LaserFeature_Init);
+       table->AddDriver("laserfeature", LaserFeature_Init);
 }
 
 
 
////////////////////////////////////////////////////////////////////////////////
 // Constructor
 LaserFeature::LaserFeature( ConfigFile* cf, int section)
-    : Driver(cf, section, 0, 0, 0, 1)
+: ThreadedDriver(cf, section)
 {
-  // Device pose relative to robot.
-  this->pose[0] = 0;
-  this->pose[1] = 0;
-  this->pose[2] = 0;
 
-  // If laser_index is not overridden by an argument here, then we'll
-  // use the device's own index, which we can get in Setup() below.
-  this->laser_index = cf->ReadInt(section, "laser", -1);
-  this->laser_driver = NULL;
-  this->laser_timesec = 0;
-  this->laser_timeusec = 0;
+       // Find the fiducial interface to provide
+       if(cf->ReadDeviceAddr(&(this->fiducial_id), section, "provides",
+                       PLAYER_FIDUCIAL_CODE, -1, NULL) == 0)
+       {
+               if(this->AddInterface(this->fiducial_id) != 0)
+               {
+                       PLAYER_ERROR("laserfeature: Error adding fidicual 
interface, please check config file.");
+                       this->SetError(-1);
+                       return;
+               }
+       }
+       else
+       {
+               PLAYER_ERROR("laserfeature: Must provide a fiducial interface, 
please check config file");
+       }
 
-  // Line filter settings.
-  this->model_range_noise = cf->ReadLength(section, "model_range_noise", 0.02);
-  this->model_angle_noise = cf->ReadAngle(section, "model_angle_noise", 10 * 
M_PI / 180);
-  this->sensor_range_noise = cf->ReadLength(section, "sensor_range_noise", 
0.05);
+       //Find a laser interface to subscribe to
+       if(cf->ReadDeviceAddr(&(this->laser_id), section, "requires",
+                       PLAYER_LASER_CODE, -1, NULL) != 0)
+       {
+               PLAYER_ERROR("laserfeature: Must require a laser interface, 
please check config file");
+               this->SetError(-1);
+       }
 
-  // Segmentation settings
-  this->segment_range = cf->ReadLength(section, "segment_range", 0.05);
+       // Device pose relative to robot.
+       this->pose[0] = 0;
+       this->pose[1] = 0;
+       this->pose[2] = 0;
 
-  // Segment merging settings.
-  this->merge_angle = cf->ReadAngle(section, "merge_angle", 10 * M_PI / 180);
 
-  // Post-processing
-  this->discard_length = cf->ReadLength(section, "discard_length", 1.00);
+       // Line filter settings.
+       this->model_range_noise = cf->ReadLength(section, "model_range_noise", 
0.02);
+       this->model_angle_noise = cf->ReadAngle(section, "model_angle_noise", 
10 * M_PI / 180);
+       this->sensor_range_noise = cf->ReadLength(section, 
"sensor_range_noise", 0.05);
 
-  // Initialise segment list.
-  this->segment_count = 0;
-  
-  // Fiducial data.
-  this->timesec = 0;
-  this->timeusec = 0;
-  memset(&this->data, 0, sizeof(this->data));
+       // Segmentation settings
+       this->segment_range = cf->ReadLength(section, "segment_range", 0.05);
 
-  return;
-}
+       // Segment merging settings.
+       this->merge_angle = cf->ReadAngle(section, "merge_angle", 10 * M_PI / 
180);
 
+       // Post-processing
+       this->discard_length = cf->ReadLength(section, "discard_length", 1.00);
 
-////////////////////////////////////////////////////////////////////////////////
-// Set up the device (called by server thread).
-int LaserFeature::Setup()
-{
-  /*
-  player_device_id_t id;
+       // Min Segments
+       this->min_segment_count = cf->ReadInt(section, "min_segment_count", 4);
 
-  // Subscribe to the laser.
-  id.code = PLAYER_LASER_CODE;
-  id.index = (this->laser_index >= 0 ? this->laser_index : 
this->device_id.index);
-  id.port = this->device_id.port;
-  this->laser_driver = deviceTable->GetDriver(id);
-  if (!this->laser_device)
-  {
-    PLAYER_ERROR("unable to locate suitable laser device");
-    return(-1);
-  }
-  if (this->laser_device->Subscribe(this) != 0)
-  {
-    PLAYER_ERROR("unable to subscribe to laser device");
-    return(-1);
-  }
-  */
+       // Initialise segment list.
+       this->segment_count = 0;
 
-  // Get the laser geometry.
-  // TODO: no support for this at the moment.
-  //this->pose[0] = 0.10;
-  //this->pose[1] = 0;
-  //this->pose[2] = 0;
+       // Fiducial data.
+       this->timesec = 0;
+       this->timeusec = 0;
+       memset(&this->data, 0, sizeof(this->data));
+       data.fiducials = NULL;
 
-  // TESTING
-  this->laser_file = fopen("laser02.log", "r");
-  assert(this->laser_file);
-  
-  while (this->ReadLaser() == 0)
-    this->SegmentLaser();
+       // Initialize new data flag
+       have_new_scan = false;
 
-  return 0;
+       return;
 }
 
 
 
////////////////////////////////////////////////////////////////////////////////
-// Shutdown the device (called by server thread).
-int LaserFeature::Shutdown()
+// Set up the device (called by server thread).
+int LaserFeature::MainSetup()
 {
-  // Unsubscribe from devices.
-  this->laser_device->Unsubscribe(this);
+       if(!(this->laser_device = deviceTable->GetDevice(this->laser_id)))
+       {
+               PLAYER_ERROR("laserfeature: Unable to get laser device");
+               return(-1);
+       }
+       if(this->laser_device->Subscribe(this->InQueue) != 0 )
+       {
+               PLAYER_ERROR("laserfeature: Unable to subscribe to laser 
device");
+               return(-1);
+       }
 
-  // TESTING
-  fclose(this->laser_file);
-  
-  return 0;
+       // Get the laser geometry.
+       // TODO: no support for this at the moment.
+       //this->pose[0] = 0.10;
+       //this->pose[1] = 0;
+       //this->pose[2] = 0;
+
+       // TESTING
+       //this->laser_file = fopen("laser02.log", "r");
+       //assert(this->laser_file);
+
+       return 0;
 }
 
 
 
////////////////////////////////////////////////////////////////////////////////
-// Get data from buffer (called by client thread)
-size_t LaserFeature::GetData(void* client,unsigned char *dest, size_t maxsize,
-                             uint32_t* timesec, uint32_t* timeusec)
+// Shutdown the device (called by server thread).
+void LaserFeature::MainQuit()
 {
-  // Get the current laser data.
-  this->laser_device->GetData((uint8_t*) &this->laser_data, 
sizeof(this->laser_data),
-                              &this->laser_timesec, &this->laser_timeusec);
-  
-  // If there is new laser data, update our data.  Otherwise, we will
-  // just reuse the existing data.
-  if (this->laser_timesec != this->timesec || this->laser_timeusec != 
this->timeusec)
-  {
-    this->UpdateLaser();
-    this->UpdateData();
-  }
-  
-  // Copy results
-  assert(maxsize >= sizeof(this->data));
-  memcpy(dest, &this->data, sizeof(this->data));
+       // Unsubscribe from devices.
+       this->laser_device->Unsubscribe(this->InQueue);
 
-  // Copy the laser timestamp
-  this->timesec = this->laser_timesec;
-  this->timeusec = this->laser_timeusec;
-  *timesec = this->timesec;
-  *timeusec = this->timeusec;
+       // TESTING
+       //fclose(this->laser_file);
 
-  return (sizeof(this->data));
+       return;
 }
 
-
 
////////////////////////////////////////////////////////////////////////////////
-// Process laser data.
-int LaserFeature::UpdateLaser()
+// MAIN DRIVER LOOP
+void LaserFeature::Main()
 {
-  int i;
-  
-  // Do some byte swapping on the laser data.
-  this->laser_data.resolution = ntohs(this->laser_data.resolution);
-  this->laser_data.min_angle = ntohs(this->laser_data.min_angle);
-  this->laser_data.max_angle = ntohs(this->laser_data.max_angle);
-  this->laser_data.range_count = ntohs(this->laser_data.range_count);
-  for (i = 0; i < this->laser_data.range_count; i++)
-    this->laser_data.ranges[i] = ntohs(this->laser_data.ranges[i]);
+       for(;;)
+       {
+               pthread_testcancel();
 
-  // TESTING
-  //this->WriteLaser();
-    
-  // Segment the scan into straight-line segments.
-  this->SegmentLaser();
+               ProcessMessages();
 
-  // Fit lines to the segments.
-  this->FitSegments();
+               if (this->have_new_scan)
+               {
+                       // Segment the scan into straight-line segments.
+                       this->SegmentLaser();
 
-  // Merge similar segments.
-  this->MergeSegments();
+                       // Fit lines to the segments.
+                       this->FitSegments();
 
-  // Re-do the fit for the merged segments.
-  this->FitSegments();
+                       // Merge similar segments.
+                       this->MergeSegments();
 
-  return 1;
-}
+                       // Re-do the fit for the merged segments.
+                       this->FitSegments();
 
+                       // Publish Fiducial data
+                       this->PublishFiducial();
 
-////////////////////////////////////////////////////////////////////////////////
-// Write laser data to a file (testing).
-int LaserFeature::WriteLaser()
-{
-  int i;
-  
-  fprintf(this->laser_file, "%d %d %d %d ",
-          this->laser_data.resolution,
-          this->laser_data.min_angle,
-          this->laser_data.max_angle,
-          this->laser_data.range_count);
-    
-  for (i = 0; i < this->laser_data.range_count; i++)
-    fprintf(this->laser_file, "%d ", this->laser_data.ranges[i]);
+                       // Don't process again until we get new data
+                       this->have_new_scan = false;
+               }
 
-  fprintf(this->laser_file, "\n");
-  
-  return 0;
+               // Sleep for a while
+               usleep(100000);
+
+       }
 }
 
-
 
////////////////////////////////////////////////////////////////////////////////
-// Read laser data from a file (testing).
-int LaserFeature::ReadLaser()
+// Segment the scan into straight-line segments.
+void LaserFeature::SegmentLaser()
 {
-  int i, n;
+       int i;
+       double r, b;
+       double res;
+       double x[2], P[2][2];
+       double Q[2][2], R;
+       double err;
+       int mask;
 
-  n = fscanf(this->laser_file, "%hd %hd %hd %hd ",
-         &this->laser_data.resolution,
-         &this->laser_data.min_angle,
-         &this->laser_data.max_angle,
-         &this->laser_data.range_count);
-  if (n < 0 || n == EOF)
-    return -1;
-    
-  for (i = 0; i < this->laser_data.range_count; i++)
-    fscanf(this->laser_file, "%hd ", &this->laser_data.ranges[i]);
+       // Angle between successive laser readings.
+       res = (double) (this->laser_data.resolution) / 100.0 * M_PI / 180;
 
-  fscanf(this->laser_file, "\n");
+       // System noise.
+       Q[0][0] = this->model_range_noise * this->model_range_noise;
+       Q[0][1] = 0;
+       Q[1][0] = 0;
+       Q[1][1] = this->model_angle_noise * this->model_angle_noise;
 
-  return 0;
-}
+       // Sensor noise.
+       R = this->sensor_range_noise * this->sensor_range_noise;
 
+       // Initial estimate and covariance.
+       x[0] = 1.0;
+       x[1] = M_PI / 2;
+       P[0][0] = 100;
+       P[0][1] = 0.0;
+       P[1][0] = 0.0;
+       P[1][1] = 100;
 
-////////////////////////////////////////////////////////////////////////////////
-// Segment the scan into straight-line segments.
-void LaserFeature::SegmentLaser()
-{
-  int i;
-  double r, b;
-  double res;
-  double x[2], P[2][2];
-  double Q[2][2], R;
-  double err;
-  int mask;
-  
-  // Angle between successive laser readings.
-  res = (double) (this->laser_data.resolution) / 100.0 * M_PI / 180;
+       // Initialise the segments.
+       this->segment_count = 0;
 
-  // System noise.
-  Q[0][0] = this->model_range_noise * this->model_range_noise;
-  Q[0][1] = 0;
-  Q[1][0] = 0;
-  Q[1][1] = this->model_angle_noise * this->model_angle_noise;
+       // Apply filter anti-clockwise.
+       mask = 0;
+       for (i = 0; i < this->laser_data.ranges_count; i++)
+       {
+               r = (double) (this->laser_data.ranges[i]);
+               b = (double) (this->laser_data.min_angle) * M_PI / 180 + i * 
res;
 
-  // Sensor noise.
-  R = this->sensor_range_noise * this->sensor_range_noise;
+               err = this->UpdateFilter(x, P, Q, R, r, res);
 
-  // Initial estimate and covariance.
-  x[0] = 1.0;
-  x[1] = M_PI / 2;
-  P[0][0] = 100;
-  P[0][1] = 0.0;
-  P[1][0] = 0.0;
-  P[1][1] = 100;
+               if (err < this->segment_range)
+               {
+                       if (mask == 0)
+                               this->segments[this->segment_count++].first = i;
+                       this->segments[this->segment_count - 1].last = i;
+                       mask = 1;
+               }
+               else
+                       mask = 0;
 
-  // Initialise the segments.
-  this->segment_count = 0;
-  
-  // Apply filter anti-clockwise.
-  mask = 0;
-  for (i = 0; i < this->laser_data.range_count; i++)
-  {
-    r = (double) (this->laser_data.ranges[i]) / 1000;
-    b = (double) (this->laser_data.min_angle) / 100.0 * M_PI / 180 + i * res;
-    
-    err = this->UpdateFilter(x, P, Q, R, r, res);
+               //fprintf(stderr, "%f %f ", r, b);
+               //fprintf(stderr, "%f %f %f ", x[0], x[1], err);
 
-    if (err < this->segment_range)
-    {
-      if (mask == 0)
-        this->segments[this->segment_count++].first = i;        
-      this->segments[this->segment_count - 1].last = i;
-      mask = 1;
-    }
-    else
-      mask = 0;
-      
-    //fprintf(stderr, "%f %f ", r, b);
-    //fprintf(stderr, "%f %f %f ", x[0], x[1], err);
-
-    /*
+               /*
     double psi = M_PI / 2 + b + x[1];
-    
+
     double px = x[0] * cos(b);
     double py = x[0] * sin(b);
-    
+
     double qx = px + 0.2 * cos(psi);
     double qy = py + 0.2 * sin(psi);
 
     fprintf(stderr, "%f %f\n%f %f\n\n", px, py, qx, qy);
-    */
+                */
 
-    /*
+               /*
     // TESTING
     double psi, px, py;
     px = r * cos(b);
@@ -458,92 +463,92 @@
     px += 0.5 * cos(psi);
     py += 0.5 * sin(psi);
     fprintf(stderr, "%f %f\n", sqrt(px * px + py * py), atan2(py, px));
-    */
-  }
-  //fprintf(stderr, "\n\n");
-  
-  // Apply filter clockwise.
-  mask = 0;
-  for (i = this->laser_data.range_count - 1; i >= 0; i--)
-  {
-    r = (double) (this->laser_data.ranges[i]) / 1000;
-    b = (double) (this->laser_data.min_angle) / 100.0 * M_PI / 180 + i * res;
-        
-    err = this->UpdateFilter(x, P, Q, R, r, -res);
+                */
+       }
+       //fprintf(stderr, "\n\n");
 
-    if (err < this->segment_range)
-    {
-      if (mask == 0)
-        this->segments[this->segment_count++].last = i;        
-      this->segments[this->segment_count - 1].first = i;
-      mask = 1;
-    }
-    else
-      mask = 0;
+       // Apply filter clockwise.
+       mask = 0;
+       for (i = this->laser_data.ranges_count - 1; i >= 0; i--)
+       {
+               r = (double) (this->laser_data.ranges[i]);
+               b = (double) (this->laser_data.min_angle) * M_PI / 180 + i * 
res;
 
-    //fprintf(stderr, "%f %f ", r, b);
-    //fprintf(stderr, "%f %f %f\n", x[0], x[1], err);
-  }
-  //fprintf(stderr, "\n\n");
+               err = this->UpdateFilter(x, P, Q, R, r, -res);
 
-  return;
+               if (err < this->segment_range)
+               {
+                       if (mask == 0)
+                               this->segments[this->segment_count++].last = i;
+                       this->segments[this->segment_count - 1].first = i;
+                       mask = 1;
+               }
+               else
+                       mask = 0;
+
+               //fprintf(stderr, "%f %f ", r, b);
+               //fprintf(stderr, "%f %f %f\n", x[0], x[1], err);
+       }
+       //fprintf(stderr, "\n\n");
+
+       return;
 }
 
 
 
////////////////////////////////////////////////////////////////////////////////
 // Update the line filter.  Returns an error signal.
 double LaserFeature::UpdateFilter(double x[2], double P[2][2], double Q[2][2],
-                                  double R, double z, double res)
+               double R, double z, double res)
 {
-  int i, j, k, l;
-  double x_[2], P_[2][2];
-  double F[2][2];
-  double r, S;
-  double K[2];
+       int i, j, k, l;
+       double x_[2], P_[2][2];
+       double F[2][2];
+       double r, S;
+       double K[2];
 
-  // A priori state estimate.
-  x_[0] = sin(x[1]) / sin(x[1] - res) * x[0];
-  x_[1] = x[1] - res;
+       // A priori state estimate.
+       x_[0] = sin(x[1]) / sin(x[1] - res) * x[0];
+       x_[1] = x[1] - res;
 
-  // Jacobian for the system function.
-  F[0][0] = sin(x[1]) / sin(x[1] - res);
-  F[0][1] = -sin(res) / (sin(x[1] - res) * sin(x[1] - res)) * x[0];
-  F[1][0] = 0;
-  F[1][1] = 1;
-  
-  // Covariance of a priori state estimate.
-  for (i = 0; i < 2; i++)
-  {
-    for (j = 0; j < 2; j++)
-    {
-      P_[i][j] = 0.0;
-      for (k = 0; k < 2; k++)
-        for (l = 0; l < 2; l++)
-          P_[i][j] += F[i][k] * P[k][l] * F[j][l];
-      P_[i][j] += Q[i][j];
-    }
-  }
+       // Jacobian for the system function.
+       F[0][0] = sin(x[1]) / sin(x[1] - res);
+       F[0][1] = -sin(res) / (sin(x[1] - res) * sin(x[1] - res)) * x[0];
+       F[1][0] = 0;
+       F[1][1] = 1;
 
-  // Residual (difference between prediction and measurement).
-  r = z - x_[0];
+       // Covariance of a priori state estimate.
+       for (i = 0; i < 2; i++)
+       {
+               for (j = 0; j < 2; j++)
+               {
+                       P_[i][j] = 0.0;
+                       for (k = 0; k < 2; k++)
+                               for (l = 0; l < 2; l++)
+                                       P_[i][j] += F[i][k] * P[k][l] * F[j][l];
+                       P_[i][j] += Q[i][j];
+               }
+       }
 
-  // Covariance of the residual.
-  S = P_[0][0] + R;
+       // Residual (difference between prediction and measurement).
+       r = z - x_[0];
 
-  // Kalman gain.
-  K[0] = P_[0][0] / S;
-  K[1] = P_[1][0] / S;
+       // Covariance of the residual.
+       S = P_[0][0] + R;
 
-  // Posterior state estimate.
-  x[0] = x_[0] + K[0] * r;
-  x[1] = x_[1] + K[1] * r;    
+       // Kalman gain.
+       K[0] = P_[0][0] / S;
+       K[1] = P_[1][0] / S;
 
-  // Posterior state covariance.
-  for (i = 0; i < 2; i++)
-    for (j = 0; j < 2; j++)
-      P[i][j] = P_[i][j] - K[i] * S * K[j];
+       // Posterior state estimate.
+       x[0] = x_[0] + K[0] * r;
+       x[1] = x_[1] + K[1] * r;
 
-  return fabs(r); //r * r / S;
+       // Posterior state covariance.
+       for (i = 0; i < 2; i++)
+               for (j = 0; j < 2; j++)
+                       P[i][j] = P_[i][j] - K[i] * S * K[j];
+
+       return fabs(r); //r * r / S;
 }
 
 
@@ -551,67 +556,67 @@
 // Fit lines to the extracted segments.
 void LaserFeature::FitSegments()
 {
-  int i, j;
-  segment_t *segment;
-  double r, b, x, y;
-  double n, sx, sy, sxx, sxy, syy;
-  double px, py, pa;
-  double ax, ay, bx, by, cx, cy;
-  
-  for (j = 0; j < this->segment_count; j++)
-  {
-    segment = this->segments + j;
+       int i, j;
+       segment_t *segment;
+       double r, b, x, y;
+       double n, sx, sy, sxx, sxy, syy;
+       double px, py, pa;
+       double ax, ay, bx, by, cx, cy;
 
-    n = sx = sy = sxx = syy = sxy = 0.0;
-    ax = ay = bx = by = 0.0;
-    
-    for (i = segment->first; i <= segment->last; i++)
-    {
-      r = (double) (this->laser_data.ranges[i]) / 1000;
-      b = (double) (this->laser_data.min_angle + i * 
this->laser_data.resolution)
-        / 100.0 * M_PI / 180;
-      x = r * cos(b);
-      y = r * sin(b);
+       for (j = 0; j < this->segment_count; j++)
+       {
+               segment = this->segments + j;
 
-      if (i == segment->first)
-      {
-        ax = x;
-        ay = y;
-      }
-      else if (i == segment->last)
-      {
-        bx = x;
-        by = y;
-      }
-      
-      n += 1;
-      sx += x;
-      sy += y;
-      sxx += x * x;
-      syy += y * y;
-      sxy += x * y;
-    }
+               n = sx = sy = sxx = syy = sxy = 0.0;
+               ax = ay = bx = by = 0.0;
 
-    px = sx / n;
-    py = sy / n;
-    pa = atan2((n * sxy  - sy * sx), (n * sxx - sx * sx));
+               for (i = segment->first; i <= segment->last; i++)
+               {
+                       r = (double) (this->laser_data.ranges[i]);
+                       b = (double) (this->laser_data.min_angle + i * 
this->laser_data.resolution)
+                                                                        * M_PI 
/ 180;
+                       x = r * cos(b);
+                       y = r * sin(b);
 
-    // Make sure the orientation is normal to surface.
-    pa += M_PI / 2;
-    if (fabs(NORMALIZE(pa - atan2(py, px))) < M_PI / 2)
-      pa += M_PI;
+                       if (i == segment->first)
+                       {
+                               ax = x;
+                               ay = y;
+                       }
+                       else if (i == segment->last)
+                       {
+                               bx = x;
+                               by = y;
+                       }
 
-    segment->count = (int) n;
-    segment->pose[0] = px;
-    segment->pose[1] = py;
-    segment->pose[2] = pa;
+                       n += 1;
+                       sx += x;
+                       sy += y;
+                       sxx += x * x;
+                       syy += y * y;
+                       sxy += x * y;
+               }
 
-    cx = bx - ax;
-    cy = by - ay;
-    segment->length = sqrt(cx * cx + cy * cy);
-  }
-                 
-  return;
+               px = sx / n;
+               py = sy / n;
+               pa = atan2((n * sxy  - sy * sx), (n * sxx - sx * sx));
+
+               // Make sure the orientation is normal to surface.
+               pa += M_PI / 2;
+               if (fabs(NORMALIZE(pa - atan2(py, px))) < M_PI / 2)
+                       pa += M_PI;
+
+               segment->count = (int) n;
+               segment->pose[0] = px;
+               segment->pose[1] = py;
+               segment->pose[2] = pa;
+
+               cx = bx - ax;
+               cy = by - ay;
+               segment->length = sqrt(cx * cx + cy * cy);
+       }
+
+       return;
 }
 
 
@@ -619,119 +624,112 @@
 // Merge overlapping segments with similar properties.
 void LaserFeature::MergeSegments()
 {
-  int i, j;
-  segment_t *sa, *sb;
-  double da;
-  
-  for (i = 0; i < this->segment_count; i++)
-  {
-    for (j = i + 1; j < this->segment_count; j++)
-    {
-      sa = this->segments + i;
-      sb = this->segments + j;
+       int i, j;
+       segment_t *sa, *sb;
+       double da;
 
-      // See if segments overlap...
-      if (sb->first <= sa->last && sa->first <= sb->last)
-      {
-        // See if the segments have the same orientation...
-        da = NORMALIZE(sb->pose[2] - sa->pose[2]);
-        if (fabs(da) < this->merge_angle)
-        {
-          sa->first = min(sa->first, sb->first);
-          sa->last = max(sa->last, sb->last);
-          sb->first = 0;
-          sb->last = -1;
-        }
-      }
-    }
-  }
-  return;
+       for (i = 0; i < this->segment_count; i++)
+       {
+               for (j = i + 1; j < this->segment_count; j++)
+               {
+                       sa = this->segments + i;
+                       sb = this->segments + j;
+
+                       // See if segments overlap...
+                       if (sb->first <= sa->last && sa->first <= sb->last)
+                       {
+                               // See if the segments have the same 
orientation...
+                               da = NORMALIZE(sb->pose[2] - sa->pose[2]);
+                               if (fabs(da) < this->merge_angle)
+                               {
+                                       sa->first = MIN(sa->first, sb->first);
+                                       sa->last = MAX(sa->last, sb->last);
+                                       sb->first = 0;
+                                       sb->last = -1;
+                               }
+                       }
+               }
+       }
+       return;
 }
 
 
 
////////////////////////////////////////////////////////////////////////////////
 // Update the device data (the data going back to the client).
-void LaserFeature::UpdateData()
+void LaserFeature::PublishFiducial()
 {
-  int i;
-  double px, py, pa;
-  double r, b, o;
-  segment_t *segment;
-  
-  this->data.count = 0;
+       int i;
+       double px, py, pa;
+       double r, b, o;
+       segment_t *segment;
 
-  for (i = 0; i < this->segment_count; i++)
-  {
-    segment = this->segments + i;
+       this->data.fiducials_count = 0;
 
-    if (segment->count >= 4 && segment->length >= this->discard_length)
-    {
-      px = segment->pose[0];
-      py = segment->pose[1];
-      pa = segment->pose[2];
-      
-      r = sqrt(px * px + py * py);
-      b = atan2(py, px);
-      o = pa;
+       if (this->data.fiducials)
+       {
+               delete[] this->data.fiducials;
+       }
+       this->data.fiducials = new player_fiducial_item_t[this->segment_count];
 
-      this->data.fiducials[this->data.count].id = 0;
-      this->data.fiducials[this->data.count].pose[0] = htons(((int16_t) (1000 
* r)));
-      this->data.fiducials[this->data.count].pose[1] = htons(((int16_t) (180 * 
b / M_PI)));
-      this->data.fiducials[this->data.count].pose[2] = htons(((int16_t) (180 * 
o / M_PI)));
-      this->data.count++;
-    }
-  }
-  
-  this->data.count = htons(this->data.count);
-  
-  return;
-}
 
+       for (i = 0; i < this->segment_count; i++)
+       {
+               segment = this->segments + i;
 
-////////////////////////////////////////////////////////////////////////////////
-// Put configuration in buffer (called by client thread)
-int LaserFeature::PutConfig(player_device_id_t* device, void *client, void 
*data, size_t len) 
-{
-  uint8_t subtype;
+               if (segment->count >= this->min_segment_count && 
segment->length >= this->discard_length)
+               {
+                       px = segment->pose[0];
+                       py = segment->pose[1];
+                       pa = segment->pose[2];
 
-  subtype = ((uint8_t*) data)[0];
-  
-  switch (subtype)
-  {
-    case PLAYER_FIDUCIAL_REQ_GET_GEOM:
-      HandleGetGeom(client, data, len);
-      break;
-    default:
-      if (PutReply(client, PLAYER_MSGTYPE_RESP_NACK) != 0)
-        PLAYER_ERROR("PutReply() failed");
-      break;
-  }
-  return 0;
-}
+                       r = sqrt(px * px + py * py);
+                       b = atan2(py, px);
+                       o = pa;
 
+                       this->data.fiducials[this->data.fiducials_count].id = 0;
+                       
this->data.fiducials[this->data.fiducials_count].pose.px = r;
+                       
this->data.fiducials[this->data.fiducials_count].pose.py = b;
+                       
this->data.fiducials[this->data.fiducials_count].pose.pz = 0;
+                       
this->data.fiducials[this->data.fiducials_count].pose.proll = 0;
+                       
this->data.fiducials[this->data.fiducials_count].pose.ppitch = 0;
+                       
this->data.fiducials[this->data.fiducials_count].pose.pyaw = o;
 
+                       this->data.fiducials_count++;
+               }
+       }
+       Publish(this->fiducial_id, PLAYER_MSGTYPE_DATA, 
PLAYER_FIDUCIAL_DATA_SCAN, (void*)&this->data, sizeof(this->data), NULL);
+
+       return;
+}
+
 
////////////////////////////////////////////////////////////////////////////////
-// Handle geometry requests.
-void LaserFeature::HandleGetGeom(void *client, void *request, int len)
+// Handle all incoming messages
+int LaserFeature::ProcessMessage (QueuePointer &resp_queue, player_msghdr * 
hdr, void * data)
 {
-  player_fiducial_geom_t geom;
+       if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, 
PLAYER_FIDUCIAL_REQ_GET_GEOM, this->fiducial_id))
+       {
+               player_fiducial_geom_t geom;
+               memset(&geom, 0, sizeof(player_fiducial_geom_t));
 
-  if (len != 1)
-  {
-    PLAYER_ERROR2("geometry request len is invalid (%d != %d)", len, 1);
-    if (PutReply(client, PLAYER_MSGTYPE_RESP_NACK) != 0)
-      PLAYER_ERROR("PutReply() failed");
-    return;
-  }
+               geom.pose.px = this->pose[0];
+               geom.pose.py = this->pose[1];
+               geom.pose.pyaw = this->pose[2];
 
-  geom.pose[0] = htons((short) (this->pose[0] * 1000));
-  geom.pose[1] = htons((short) (this->pose[1] * 1000));
-  geom.pose[2] = htons((short) (this->pose[2] * 180/M_PI));
+               Publish(this->fiducial_id, PLAYER_MSGTYPE_RESP_ACK, 
PLAYER_FIDUCIAL_REQ_GET_GEOM, &geom, sizeof(geom), NULL);
 
-  if (PutReply(client, PLAYER_MSGTYPE_RESP_ACK, NULL, &geom, sizeof(geom)) != 
0)
-    PLAYER_ERROR("PutReply() failed");
+               return 0;
 
-  return;
+       }
+       else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_DATA, 
PLAYER_LASER_DATA_SCAN, this->laser_id))
+       {
+               this->laser_data = *(player_laser_data_t*) data;
+
+               have_new_scan = true;
+               return 0;
+       }
+       else
+       {
+               return -1;
+       }
 }
 
-


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Virtualization is moving to the mainstream and overtaking non-virtualized
environment for deploying applications. Does it make network security 
easier or more difficult to achieve? Read this whitepaper to separate the 
two and get a better understanding.
http://p.sf.net/sfu/hp-phase2-d2d
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit

Reply via email to