Update of /cvsroot/playerstage/code/player/server/drivers/mixed/mricp/src
In directory
sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6130/server/drivers/mixed/mricp/src
Added Files:
lasermodel.cpp geometry2D.cpp map.cpp mricp_driver.cpp icp.cpp
nn.cpp Timer.cpp
Log Message:
added mricp driver, thanks to Tarek Taha
--- NEW FILE: nn.cpp ---
/* K-nearest-neighbours for 2D point-sets.
* Tim Bailey 2004.
*/
#include "nn.h"
#include "geometry2D.h"
#include <algorithm>
#include <cmath>
#include <cassert>
using namespace Geom2D;
using namespace std;
SweepSearch::SweepSearch(const vector<Point> &p, double lim) : limit(lim)
// Input: set of points, p, and maximum search distance, lim.
// Function: create data structure for nearest-neighbour search.
{
// store points and their order
dataset.reserve(p.size());
for (int i=0; i < (int)p.size(); ++i)
dataset.push_back(PointIdx(p[i], i));
// sort points
sort(dataset.begin(), dataset.end(), yorder);
}
int SweepSearch::query(const Point& q) const
// Input: query point.
// Output: index of nearest-neighbour.
{
double d2min = sqr(limit);
int idxmin = NOT_FOUND;
// get upper bound
PointIdx qi(q, 0);
vector<PointIdx>::const_iterator upper =
upper_bound(dataset.begin(), dataset.end(), qi, yorder);
vector<PointIdx>::const_iterator i;
// search backwards
double min_y = q.y - limit;
for (i = upper-1; i >= dataset.begin() && i->p.y > min_y; --i)
if (is_nearer(d2min, idxmin, q, *i))
min_y = q.y - sqrt(d2min);
// search forward
double max_y = q.y+sqrt(d2min);
for (i = upper; i < dataset.end() && i->p.y < max_y; ++i)
if (is_nearer(d2min, idxmin, q, *i))
max_y = q.y+sqrt(d2min);
return idxmin;
}
inline
bool SweepSearch::is_nearer(double &d2min, int &idxmin, const Point &q, const
PointIdx &pi) const
// Check whether new point is closer than previous points. If so, update d2min
and idxmin.
{
double d2 = dist_sqr(q, pi.p);
if (d2 < d2min) {
d2min = d2;
idxmin = pi.i;
return true;
}
return false;
}
std::vector<double>& SweepSearch::query(const Point &q, std::vector<int> &idx)
// Input: query point and vector<int> of size k (number of neighbours)
// Output: vector<int> indices of nearest-neighbours.
// Returns: set of distances to k nn's.
{
// can't have more nn's than reference
points
assert(idx.size() > 0);
int size = idx.size();
if ((int)dataset.size() < size) {
size = dataset.size();
idx.resize(size);
}
if ((int)nndists.size() != size)
nndists.resize(size);
// initialise set
for (int j=0; j<size; ++j) {
idx[j] = NOT_FOUND;
nndists[j] = sqr(limit);
}
// get upper bound
PointIdx qi(q, 0);
vector<PointIdx>::const_iterator di =
upper_bound(dataset.begin(), dataset.end(), qi, yorder);
vector<PointIdx>::const_iterator i;
// sweep forwards
double max_y = q.y + limit;
for (i = di; i < dataset.end() && i->p.y < max_y; ++i)
if (insert_neighbour(q, *i, nndists, idx))
max_y = q.y + sqrt(nndists[size-1]);
// sweep backwards
double min_y = q.y - sqrt(nndists[size-1]);
for (i = di-1; i >= dataset.begin() && i->p.y > min_y; --i)
if (insert_neighbour(q, *i, nndists, idx))
min_y = q.y - sqrt(nndists[size-1]);
// convert square distances to distances
{ for (int i=0; i<size; ++i)
nndists[i] = sqrt(nndists[i]);
}
return nndists;
}
bool SweepSearch::insert_neighbour(const Point &q, const PointIdx &pi,
std::vector<double> &nndists, std::vector<int> &idx)
// Check if new point is closer than any of the existing near-neighbours. If so,
// place the new point into near-neighbour set (in ascending order).
{
const int size = nndists.size();
double d2 = dist_sqr(q, pi.p);
if (d2 >= nndists[size-1]) // no improvement possible
return false;
int i;
for (i=0; d2 >= nndists[i]; ++i) // find location for new neighbour
;
for (int j = size-1; j > i; --j) { // shuffle in order
nndists[j] = nndists[j-1];
idx[j] = idx[j-1];
}
nndists[i] = d2;
idx[i] = pi.i;
return true;
}
--- NEW FILE: geometry2D.cpp ---
/* Simple 2D geometric operations with points, poses, and lines.
* Tim Bailey 2004.
*/
#include "geometry2D.h"
#include <cmath>
#include <cassert>
using namespace std;
namespace Geom2D {
#if 0
double pi_to_pi(double angle)
// An alternative implementation that uses fmod() rather than while-loops.
{
angle = fmod(angle, 2.*PI);
if (angle < -PI)
angle += 2.*PI;
else if (angle > PI)
angle -= 2.*PI;
return angle;
}
#endif
double dist(const Point& p, const Point& q)
// Distance between two points.
{
return sqrt(dist_sqr(p,q));
}
Pose compute_relative_pose(const vector<Point>& a, const vector<Point>& b)
// Determine the relative Pose that best aligns two point-sets.
// INPUTS: a, b are two equal-length sets of points, such that a[i] aligns with
b[i].
// OUTPUT: Best-fit alignment.
//
// Closed-form algorithm from Appendix C of:
// F. Lu and E. Milios. Robot pose estimation in unknown environments by
matching
// 2D range scans. Journal of Intelligent and Robotic Systems, 18:249�275,
1997.
{
assert(a.size() == b.size() && a.size() != 0);
int n= a.size();
double x1,x2,y1,y2,xx,yy,xy,yx;
x1=x2=y1=y2=xx=yy=xy=yx=0.0;
for (int i=0; i<n; ++i) { // calculate sums
const Point& p1 = a[i];
const Point& p2 = b[i];
x1 += p1.x;
x2 += p2.x;
y1 += p1.y;
y2 += p2.y;
xx += p1.x*p2.x;
yy += p1.y*p2.y;
xy += p1.x*p2.y;
yx += p1.y*p2.x;
}
double N = static_cast<double>(n);
double Sxx = xx - x1*x2/N; // calculate S
double Syy = yy - y1*y2/N;
double Sxy = xy - x1*y2/N;
double Syx = yx - y1*x2/N;
double xm1 = x1/N; // calculate means
double xm2 = x2/N;
double ym1 = y1/N;
double ym2 = y2/N;
double phi = atan2(Sxy-Syx, Sxx+Syy);
Pose pse; // calculate pose
pse.p.x = xm2 - (xm1*cos(phi) - ym1*sin(phi));
pse.p.y = ym2 - (xm1*sin(phi) + ym1*cos(phi));
pse.phi = phi;
return pse;
}
Transform2D::Transform2D(const Pose& ref) : base(ref)
{
c = cos(ref.phi);
s = sin(ref.phi);
}
bool intersection_line_line (Point& p, const Line& l, const Line& m)
// Compute the intersection point of two lines.
// Returns false for parallel lines.
{
double gl, gm, bl, bm;
bool lVert = true, mVert = true;
// calculate gradients
if ((gl = l.second.x - l.first.x) != 0.0) {
gl = (l.second.y - l.first.y)/gl;
lVert = false;
}
if ((gm = m.second.x - m.first.x) != 0.0) {
gm = (m.second.y - m.first.y)/gm;
mVert = false;
}
if (lVert == mVert) { // check for parallelism
if (gl == gm)
return false;
}
bl = l.first.y - gl*l.first.x; // calculate y intercepts
bm = m.first.y - gm*m.first.x;
if (lVert) { // calculate intersection
p.x = l.first.x;
p.y = gm*p.x + bm;
}
else if (mVert) {
p.x = m.first.x;
p.y = gl*p.x + bl;
}
else {
p.x = (bm - bl)/(gl - gm);
p.y = gm*p.x + bm;
}
return true;
}
double distance_line_point (const Line& lne, const Point& p)
// Note: distance is -ve if point is on left of line and +ve if it is on
// the right (when looking from first to second).
{
Point v;
v.x= lne.second.x - lne.first.x;
v.y= lne.second.y - lne.first.y;
return ((lne.second.y - p.y)*v.x
- (lne.second.x - p.x)*v.y)
/ sqrt(v.x*v.x + v.y*v.y);
}
void intersection_line_point(Point& p, const Line& l, const Point& q)
// Compute the perpendicular intersection from a point to a line
{
Line m; // create line through q perpendicular to l
m.first = q;
m.second.x = q.x + (l.second.y - l.first.y);
m.second.y = q.y - (l.second.x - l.first.x);
bool not_parallel = intersection_line_line(p, l, m);
//assert(not_parallel);
if (not_parallel == 0)
printf("\n Lines are parallel !!!");
}
} // namespace Geom2D
--- NEW FILE: map.cpp ---
/***************************************************************************
* Copyright (C) 2005 by Tarek Taha *
* [EMAIL PROTECTED] *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "map.h"
#include <math.h>
#include <cassert>
#include <iostream>
using namespace std;
MAP::MAP(char * Mapname, double pixel_size, double map_size)
{
this->Mapname = Mapname;
this->pixel_size = pixel_size;
this->negate = TRUE;
this->occ_grid = NULL;
this->pixbuf = NULL;
this->size_x = (int)ceil(map_size/pixel_size); // Square MAP
this->size_y = this->size_x + 1;
}
void MAP::ResetProb()
{
if (!this->occ_grid)
{
cout<<"\n Occupancy Grid not Allocated Yet!!!";
return;
}
for (int i=0; i < this->size_x; i++)
for(int j =0; j < this->size_y;j++)
{
occ_grid[i][j].prob_occ = occ_grid[i][j].prob_free =
double(1)/3;
occ_grid[i][j].added =false;
}
}
GdkPixbuf * MAP::CreateMap()
{
g_type_init();// Initialize glib
if (this->occ_grid)
{
for (int i=0; i < this->size_x; i++)
delete [] this->occ_grid[i];
delete [] this->occ_grid;
}
if (!this->pixbuf)
{
cout<<"\n --->>> Creating Image Pixel
Buffer:"<<this->Mapname;
fflush(stdout);
if(!(this->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
8, this->size_x,this->size_y))) // Read the image
{
printf("\nfailed to Create Map Buffer %s",
this->Mapname);
return(NULL);
}
gdk_pixbuf_fill (pixbuf, 0x7f7f7f00);
}
assert(this->size_x == gdk_pixbuf_get_width(this->pixbuf));
assert(this->size_y == gdk_pixbuf_get_height(this->pixbuf));
if (!(this->occ_grid= new mapgrid * [size_x]))
perror("\nCould not allocated the requested memory space");
for(int m=0;m<size_x;m++)
{
if(!(this->occ_grid[m] = new mapgrid [size_y]))
perror("\nCould not allocated the requested memory
space");
}
ClearData();
printf("\n --->>> MAP Created with Height=%d Width=%d
Resolution=%.3f <<<---",this->size_y, this->size_x, this->pixel_size);
fflush(stdout);
return this->pixbuf;
}
void MAP::ClearData()
{
for (int i=0; i < this->size_x; i++)
for(int j =0; j < this->size_y;j++)
{
this->occ_grid[i][j].prob_occ = this->occ_grid[i][j].prob_free
= 1/3;
}
if(pixbuf)
gdk_pixbuf_fill (pixbuf, 0x7f7f7f00);
}
MAP::~ MAP()
{
for (int i=0; i < this->size_x; i++)
delete [] this->occ_grid[i];
delete [] this->occ_grid;
if(this->pixbuf)
gdk_pixbuf_unref(this->pixbuf);
cout <<"\n <<<--- IMAGE DATA FREED <<<---";
fflush(stdout);
};
MapInfo MAP::GetMapInfo()
{
MapInfo mapinfo;
if(this->occ_grid == NULL)
{
mapinfo.pixel_size=-1;
return mapinfo;
}
mapinfo.width = this->size_x;
mapinfo.height =this->size_y;
mapinfo.pixel_size=this->pixel_size;
return mapinfo;
};
void MAP::DrawPixel (int red,int green,int blue,int i,int j)
{
int rowstride=0, n_channels, bps;
guchar *pixels;
guchar * p;
rowstride = gdk_pixbuf_get_rowstride(this->pixbuf);
bps = gdk_pixbuf_get_bits_per_sample(this->pixbuf)/8;
n_channels = gdk_pixbuf_get_n_channels(this->pixbuf);
pixels = gdk_pixbuf_get_pixels(this->pixbuf);
if(gdk_pixbuf_get_has_alpha(this->pixbuf))
n_channels++;
p= pixels +j*rowstride + i*n_channels;
p[0]=red;
p[1]=green;
p[2]=blue;
//p[3]=;
return;
}
void MAP::SavePixelBufferToFile()
{
char command[40],filename[40];
struct stat stat_buf;
if(!this->pixbuf)
{
cout<<" --->>> Nothing To SAVE Buffer Empty !!! ";
return;
}
sprintf(filename,"%s%s",this->Mapname,".png");
// Delete the file if it exists
if (stat(filename,&stat_buf) != 0 || (stat_buf.st_mode & S_IFMT) ==
S_IFREG)
{
sprintf(command,"%s%s","rm -f -r ",filename);
if(system(command)==-1)
{
perror("\nError Happened while trying to Delete
Existing File");
exit(1);
}
else
cout<<"\n --->>> Map already existed with the
same name : Deleted Successfully";
}
cout<<"\n --->>> Saving the map into: "<<filename; fflush(stdout);
// Save the file
gdk_pixbuf_save(this->pixbuf,filename,"png",NULL,NULL);
cout<<"\n --->>> PIXEL BUFFER SAVED <<<--- ";
fflush(stdout);
};
// Save as PGM format
int MAP::SavePgm()
{
char filename[40];
int i, j;
signed char c;
unsigned char d;
FILE *file;
sprintf(filename,"%s%s",this->Mapname,".pgm");
file = fopen(filename, "w+");
if (file == NULL)
{
fprintf(stderr, "error writing to %s ", filename);
return -1;
}
fprintf(file, "P5 %d %d 255\n",this->size_x , this->size_y -1);
for (j = 0; j < this->size_y-1; j++)
{
for (i = 0; i < this->size_x; i++)
{
c = (int)(occ_grid[i][j].prob_occ * 255.0);
d = (unsigned char) (255 - c);
fwrite(&d, 1, 1, file);
}
}
cout<<"\n --->>> Pgm Map Saved <<<--- "; fflush(stdout);
fclose(file);
return 0;
};
--- NEW FILE: Timer.cpp ---
#include "Timer.h"
Timer::Timer()
{
gettimeofday(&start_time,NULL);
}
double Timer::TimeElapsed() // return in usec
{
gettimeofday(&end_time,NULL);
time_diff = ((double) end_time.tv_sec*1e6 + (double)end_time.tv_usec)
-
((double) start_time.tv_sec*1e6 +
(double)start_time.tv_usec);
return time_diff;
}
Timer::~Timer()
{
}
void Timer::Reset()
{
gettimeofday(&start_time,NULL);
}
void Timer::Synch(double period)
{
double time_elapsed = this->TimeElapsed();
if( time_elapsed < period*1e3)
usleep((int)(period*1e3 -time_elapsed));
}
--- NEW FILE: mricp_driver.cpp ---
/*
* Player - One Hell of a Robot Server
* Copyright (C) 2000-2003
* Andras Szekely, Aaron Skelsey, Kent Williams
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
[...1392 lines suppressed...]
// Perform the ICP on Next Laser Scan
laser_set_1 = laser_set_2;
if(this->position_device) pose_1 = pose_2;
};
void MrIcpDriver::ConnectPatches()
{
int patch_number=0;
gchar * patch;
patch = g_strdup_printf("%sMAP_PATCH%d.png",map_path,patch_number++);
while(is_file(patch))
{
cout<<patch<<endl; fflush(stdout);
patch =
g_strdup_printf("%sMAP_PATCH%d.png",map_path,patch_number++);
}
}
--- NEW FILE: icp.cpp ---
/* Iterated closest point (ICP) algorithm.
* Tim Bailey 2004.
*/
#include "icp.h"
#include <cassert>
#include <iostream>
using namespace std;
namespace Geom2D
{
ICP::ICP()
{
index.push_back(0);
index.push_back(0);
};
ICP::~ICP()
{
a.clear();
b.clear();
index.clear();
ref.clear();
}
Pose ICP::align(vector<Point> reference, vector<Point> obs,Pose init, double
gate, int nits, bool interp)
{
ref = reference;
nn = new SweepSearch(reference, gate);
Pose pse = init;
double gate_sqr = sqr(gate);
int size_obs = obs.size();
// used if interp == true
while (nits-- > 0)
{
Transform2D tr(pse);
a.clear();
b.clear();
// For each point in obs, find its NN in ref
for (int i = 0; i < size_obs; ++i)
{
Point p = obs[i];
tr.transform_to_global(p); // transform obs[i] to
estimated ref coord-frame
Point q;
// simple ICP
if (interp == false)
{
int idx = nn->query(p);
if (idx == SweepSearch::NOT_FOUND)
continue;
q = ref[idx];
}
// ICP with interpolation between 2 nearest points in
ref
else
{
(void) nn->query(p, index);
assert(index.size() == 2);
if (index[1] == SweepSearch::NOT_FOUND)
continue;
Line lne;
lne.first = ref[index[0]];
lne.second = ref[index[1]];
intersection_line_point(q, lne, p);
}
if (dist_sqr(p,q) < gate_sqr) // check if NN is close
enough
{
a.push_back(obs[i]);
b.push_back(q);
}
}
//cout<<"\nObs size:"<<obs.size()<<" Ref:"<<ref.size()<<"
Paired set size:"<<a.size();
//If Less than half of the Observation is paired => not good
alignment
if( a.size() < obs.size()/2.0)
{
cout<<"\n Detected Possible misalignment --- Skipping
this Laser Set! Gate is:"<<gate;;
pse.p.x = -1 ; pse.p.y=-1 ; pse.phi = -1;
break;
}
if (a.size() > 2)
pse = compute_relative_pose(a, b); // new iteration
result
}
delete nn;
return pse;
}
} // namespace Geom2D
--- NEW FILE: lasermodel.cpp ---
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "map.h"
#include "lasermodel.h"
#define LASER_MAX_RANGES 401
// Create an sensor model
LaserModel::LaserModel()
{
//Empty Constructor
};
LaserModel::LaserModel(mapgrid * * map)
{
this->map = map;
this->range_cov = 0.10 * 0.10;
this->range_bad = 0.50;
PreCompute();
this->range_count = 0;
this->ranges = (laser_range_t *)calloc(LASER_MAX_RANGES,
sizeof(laser_range_t));
};
// Free an sensor model
LaserModel::~LaserModel()
{
if(this->lut_probs)
free(this->lut_probs);
if(this->ranges)
free(this->ranges);
return;
}
// Clear all existing range readings
void LaserModel::ClearRanges()
{
this->range_count = 0;
return;
}
// Set the laser range readings that will be used.
void LaserModel::AddRange(double range, double bearing)
{
laser_range_t *beam;
assert(this->range_count < LASER_MAX_RANGES);
beam = this->ranges + this->range_count++;
beam->range = range;
beam->bearing = bearing;
return;
}
// Pre-compute the range sensor probabilities.
// We use a two-dimensional array over the O.G
void LaserModel::PreCompute()
{
double max;
double c, z, p;
double mrange, orange;
int i, j;
// Laser max range and resolution
max = 8.00;
this->lut_res = 0.01;
this->lut_size = (int) ceil(max / this->lut_res);
this->lut_probs = (double *)malloc(this->lut_size * this->lut_size *
sizeof(this->lut_probs[0]));
for (i = 0; i < this->lut_size; i++)
{
mrange = i * this->lut_res;
for (j = 0; j < this->lut_size; j++)
{
orange = j * this->lut_res;
// TODO: proper sensor model (using Kolmagorov?)
// Simple gaussian model
c = this->range_cov;
z = orange - mrange;
p = this->range_bad + (1 - this->range_bad) * exp(-(z * z) / (2
* c));
//printf("%f %f %f\n", orange, mrange, p);
//assert(p >= 0 && p <= 1.0);
this->lut_probs[i + j * this->lut_size] = p;
}
//printf("\n");
}
return;
}
// Determine the probability for the given range reading
double LaserModel::RangeProb(double obs_range, double map_range)
{
int i, j;
double p;
i = (int) (map_range / this->lut_res + 0.5);
j = (int) (obs_range / this->lut_res + 0.5);
assert(i >= 0);
if (i >= this->lut_size)
i = this->lut_size - 1;
assert(j >= 0);
if (j >= this->lut_size)
j = this->lut_size - 1;
p = this->lut_probs[i + j * this->lut_size];
//assert(p >= 0 && p <= 1.0);
return p;
}
// Determine the probability for the given pose
double LaserModel::PoseProb()
{
int i;
double p;
double map_range;
laser_range_t *obs;
p = 1.0;
for (i = 0; i < this->range_count; i++)
{
obs = this->ranges + i;
map_range = 1; //TODO
if (obs->range >= 8.0 && map_range >= 8.0)
p *= 1.0;
else if (obs->range >= 8.0 && map_range < 8.0)
p *= this->range_bad;
else if (obs->range < 8.0 && map_range >= 8.0)
p *= this->range_bad;
else
p *= RangeProb(obs->range, map_range);
}
//printf("%e\n", p);
assert(p >= 0);
return p;
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit