00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef OPENRAVE_ROSBASELASER_H
00016 #define OPENRAVE_ROSBASELASER_H
00017
00018 #include "plugindefs.h"
00019
00020 #include <sensor_msgs/LaserScan.h>
00021
00023 class ROSLaser2D : public SensorBase
00024 {
00025 protected:
00026 class BaseLaser2DXMLReader : public BaseXMLReader
00027 {
00028 public:
00029 BaseLaser2DXMLReader(boost::shared_ptr<ROSLaser2D> psensor) : _psensor(psensor) {}
00030 virtual ~BaseLaser2DXMLReader() {}
00031
00032 virtual ProcessElement startElement(const std::string& name, const std::list<std::pair<std::string,std::string> >& atts)
00033 {
00034 if( !!_pcurreader ) {
00035 if( _pcurreader->startElement(name,atts) == PE_Support )
00036 return PE_Support;
00037 return PE_Ignore;
00038 }
00039
00040 ss.str("");
00041 return (name != "sensor" && name != "scantopic" && name != "show" && name != "color") ? PE_Support : PE_Pass;
00042 }
00043
00044 virtual bool endElement(const std::string& name)
00045 {
00046 if( !!_pcurreader ) {
00047 if( _pcurreader->endElement(name) )
00048 _pcurreader.reset();
00049 return false;
00050 }
00051 else if( name == "sensor" )
00052 return true;
00053 else if( name == "scantopic" )
00054 ss >> _psensor->scantopic;
00055 else if( name == "show" )
00056 ss >> _psensor->_bRenderData;
00057 else if( name == "color" ) {
00058 ss >> _psensor->_vColor.x >> _psensor->_vColor.y >> _psensor->_vColor.z;
00059
00060 if( !ss )
00061 ss.clear();
00062 }
00063 else
00064 RAVELOG_WARNA(str(boost::format("bad tag: %s")%name));
00065
00066 if( !ss )
00067 RAVELOG_WARNA(str(boost::format("error parsing %s\n")%name));
00068
00069 return false;
00070 }
00071
00072 virtual void characters(const std::string& ch)
00073 {
00074 if( !!_pcurreader )
00075 _pcurreader->characters(ch);
00076 else {
00077 ss.clear();
00078 ss << ch;
00079 }
00080 }
00081
00082 protected:
00083 boost::shared_ptr<ROSLaser2D> _psensor;
00084 BaseXMLReaderPtr _pcurreader;
00085 stringstream ss;
00086 };
00087
00088 public:
00089 static BaseXMLReaderPtr CreateXMLReader(InterfaceBasePtr ptr, const std::list<std::pair<std::string,std::string> >& atts)
00090 {
00091 return BaseXMLReaderPtr(new BaseLaser2DXMLReader(boost::dynamic_pointer_cast<ROSLaser2D>(ptr)));
00092 }
00093
00094 ROSLaser2D(EnvironmentBasePtr penv) : SensorBase(penv)
00095 {
00096 __description = ":Interface Author: Rosen Diankov\n\nConnects to a ROS LaserScan message that receives laser data in real-time and provides that information to the OpenRAVE environment";
00097 _pgeom.reset(new LaserGeomData());
00098 _pdata.reset(new LaserSensorData());
00099
00100 _bDestroyThread = true;
00101 _bRenderData = false;
00102 _bRenderGeometry = true;
00103 _bPower = true;
00104 _bUpdatePlot = true;
00105 scantopic = "/scan";
00106 _vColor = RaveVector<float>(0.5f,0.5f,1,1);
00107 _pgeom->min_angle[0] = _pgeom->min_angle[1] = 0;
00108 _pgeom->max_angle[0] = _pgeom->max_angle[1] = 0;
00109 _pgeom->resolution[0] = _pgeom->resolution[1] = 0;
00110 _pgeom->max_range = 0;
00111 }
00112 virtual ~ROSLaser2D()
00113 {
00114 _Reset();
00115 }
00116
00117 virtual int Configure(ConfigureCommand command, bool blocking)
00118 {
00119 switch(command) {
00120 case CC_PowerOn:
00121 _bPower = true;
00122 return _bPower;
00123 case CC_PowerOff:
00124 _bPower = false;
00125 _Reset();
00126 return _bPower;
00127 case CC_PowerCheck:
00128 return _bPower;
00129 case CC_RenderDataOn:
00130 _bRenderData = true;
00131 _Reset();
00132 startsubscriptions();
00133 return _bRenderData;
00134 case CC_RenderDataOff: {
00135 boost::mutex::scoped_lock lock(_mutexdata);
00136 _listGraphicsHandles.clear();
00137 _bRenderData = false;
00138 return _bRenderData;
00139 }
00140 case CC_RenderDataCheck:
00141 return _bRenderData;
00142 case CC_RenderGeometryOn:
00143 _bRenderGeometry = true;
00144 _RenderGeometry();
00145 return _bRenderData;
00146 case CC_RenderGeometryOff: {
00147 boost::mutex::scoped_lock lock(_mutexdata);
00148 _graphgeometry.reset();
00149 _bRenderGeometry = false;
00150 return _bRenderData;
00151 }
00152 case CC_RenderGeometryCheck:
00153 return _bRenderGeometry;
00154 }
00155 throw openrave_exception(str(boost::format("SensorBase::Configure: unknown command 0x%x")%command));
00156 }
00157
00158 virtual void startsubscriptions()
00159 {
00160 int argc=0;
00161 ros::init(argc,NULL,"openrave", ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00162
00163 if( ros::master::check() ) {
00164 _node.reset(new ros::NodeHandle());
00165 _submstate = _node->subscribe(scantopic, 10, &ROSLaser2D::newscan_cb, this);
00166
00167 _bDestroyThread = false;
00168 _threadsensor = boost::thread(boost::bind(&ROSLaser2D::_SensorThread, this));
00169 }
00170 else
00171 RAVELOG_WARNA("failed to detect ROS master");
00172 }
00173
00174 virtual bool SimulationStep(dReal fTimeElapsed)
00175 {
00176 if( _bUpdatePlot ) {
00177 _RenderGeometry();
00178 }
00179
00180 return true;
00181 }
00182
00183 virtual SensorGeometryPtr GetSensorGeometry(SensorType type)
00184 {
00185 if( type == ST_Invalid || type == ST_Laser ) {
00186 LaserGeomData* pgeom = new LaserGeomData();
00187 *pgeom = *_pgeom;
00188 return SensorGeometryPtr(pgeom);
00189 }
00190 return SensorGeometryPtr();
00191 }
00192
00193 virtual SensorDataPtr CreateSensorData(SensorType type)
00194 {
00195 if( type == ST_Invalid || type == ST_Laser ) {
00196 return SensorDataPtr(new LaserSensorData());
00197 }
00198 return SensorDataPtr();
00199 }
00200
00201 virtual bool GetSensorData(SensorDataPtr psensordata)
00202 {
00203 if( psensordata->GetType() == ST_Laser ) {
00204 boost::mutex::scoped_lock lock(_mutexdata);
00205 *boost::dynamic_pointer_cast<LaserSensorData>(psensordata) = *_pdata;
00206 return true;
00207 }
00208 return false;
00209 }
00210
00211 virtual bool Supports(SensorType type) { return type == ST_Laser; }
00212
00213 virtual bool SendCommand(std::ostream& os, std::istream& is)
00214 {
00215 string cmd;
00216 is >> cmd;
00217 if( !is )
00218 throw openrave_exception("no command",ORE_InvalidArguments);
00219 std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower);
00220
00221 if( cmd == "show" || cmd == "render" ) {
00222 is >> _bRenderData;
00223 }
00224 else if( cmd == "power") {
00225 is >> _bPower;
00226 if( _bPower && !_node ) {
00227 startsubscriptions();
00228 }
00229 else if( !_bPower && !!_node ) {
00230 _submstate.shutdown();
00231 _node.reset();
00232 boost::mutex::scoped_lock lock(_mutexdata);
00233 _listGraphicsHandles.resize(0);
00234 }
00235 }
00236
00237 return !!is;
00238 }
00239
00240 virtual void SetTransform(const Transform& trans)
00241 {
00242 _trans = trans;
00243 _bUpdatePlot = true;
00244 }
00245
00246 virtual Transform GetTransform() { return _trans; }
00247
00248 protected:
00249
00250 virtual void _Reset()
00251 {
00252 boost::mutex::scoped_lock lock(_mutexdata);
00253
00254 _listGraphicsHandles.clear();
00255 _graphgeometry.reset();
00256
00257 _bUpdatePlot = true;
00258 _pdata->positions.clear();
00259 _pdata->ranges.clear();
00260 _pdata->intensity.clear();
00261
00262 _bDestroyThread = true;
00263 _submstate.shutdown();
00264 _node.reset();
00265 _threadsensor.join();
00266 }
00267
00268 virtual void _RenderGeometry()
00269 {
00270 if( !_bRenderGeometry ) {
00271 return;
00272 }
00273 Transform t = GetLaserPlaneTransform();
00274 if( _pgeom->max_angle[0] > _pgeom->min_angle[0] ) {
00275 if( !_graphgeometry ) {
00276 int N = 10;
00277 vector<RaveVector<float> > viconpoints;
00278 vector<int> viconindices;
00279 viconpoints.resize(N+2);
00280 viconindices.resize(3*N);
00281 viconpoints[0] = t.trans;
00282 Transform trot;
00283
00284 for(int i = 0; i <= N; ++i) {
00285 dReal fang = _pgeom->min_angle[0] + (_pgeom->max_angle[0]-_pgeom->min_angle[0])*(float)i/(float)N;
00286 trot.rot = quatFromAxisAngle(Vector(0,0,1), fang);
00287 viconpoints[i+1] = trot.rotate(Vector(0.05f,0,0));
00288
00289 if( i < N ) {
00290 viconindices[3*i+0] = 0;
00291 viconindices[3*i+1] = i+1;
00292 viconindices[3*i+2] = i+2;
00293 }
00294 }
00295
00296 RaveVector<float> vcolor = _vColor*0.5f;
00297 vcolor.w = 0.7f;
00298 _graphgeometry = GetEnv()->drawtrimesh(&viconpoints[0][0], sizeof(viconpoints[0]), &viconindices[0], N, vcolor);
00299 }
00300 if( !!_graphgeometry ) {
00301 _graphgeometry->SetTransform(t);
00302 }
00303 }
00304 }
00305 virtual Transform GetLaserPlaneTransform() { return _trans; }
00306 virtual void newscan_cb(const sensor_msgs::LaserScanConstPtr& msg)
00307 {
00308 boost::mutex::scoped_lock lock(_mutexdata);
00309 _pgeom->min_angle[0] = msg->angle_min;
00310 _pgeom->max_angle[0] = msg->angle_max;
00311 _pgeom->resolution[0] = msg->angle_increment;
00312 _pgeom->max_range = msg->range_max;
00313
00314 Transform t = _trans;
00315 _pdata->positions.resize(msg->ranges.size());
00316 _pdata->ranges.resize(msg->ranges.size());
00317 _pdata->intensity.resize(msg->intensities.size());
00318
00319 float ang = msg->angle_min;
00320 for(size_t i = 0; i < msg->ranges.size(); ++i, ang += msg->angle_increment) {
00321 _pdata->positions[i] = _trans.trans;
00322 float range = max(msg->range_min,min(msg->range_max,msg->ranges[i]));
00323 Vector v(range*cosf(ang),range*sinf(ang),0);
00324 _pdata->ranges[i] = t.rotate(v);
00325 }
00326
00327 for(int i = 0; i < (int)_pdata->intensity.size(); ++i) {
00328 _pdata->intensity[i] = msg->intensities[i];
00329 }
00330 if( _bRenderData && msg->ranges.size() > 0 ) {
00331
00332
00333 list<GraphHandlePtr> listhandles;
00334 int N = 0;
00335 vector<RaveVector<float> > vpoints;
00336 vector<int> vindices;
00337
00338 {
00339
00340 N = (int)_pdata->ranges.size();
00341 vpoints.resize(N+1);
00342 ang = msg->angle_min;
00343 for(int i = 0; i < N; ++i, ang += msg->angle_increment) {
00344 float range = max(msg->range_min,min(msg->range_max,msg->ranges[i]));
00345 vpoints[i] = t * Vector(range*cosf(ang),range*sinf(ang),0);
00346 }
00347 vpoints[N] = t.trans;
00348 }
00349
00350
00351 vindices.resize(3*(N-1));
00352
00353 for(int i = 0; i < N-1; ++i) {
00354 vindices[3*i+0] = i;
00355 vindices[3*i+1] = i+1;
00356 vindices[3*i+2] = N;
00357 }
00358
00359 _vColor.w = 1;
00360
00361 listhandles.push_back(GetEnv()->plot3(&vpoints[0].x, N, sizeof(vpoints[0]), 5.0f, _vColor));
00362
00363 _vColor.w = 0.2f;
00364 listhandles.push_back(GetEnv()->drawtrimesh(&vpoints[0][0], sizeof(vpoints[0]), &vindices[0], N-1, _vColor));
00365
00366 _listGraphicsHandles.swap(listhandles);
00367 }
00368 else {
00369 _listGraphicsHandles.clear();
00370 }
00371 }
00372
00373 void _SensorThread()
00374 {
00375 while(!_bDestroyThread) {
00376 ros::spinOnce();
00377 usleep(1000);
00378 }
00379 }
00380
00381 boost::shared_ptr<ros::NodeHandle> _node;
00382 ros::Subscriber _submstate;
00383
00384 boost::shared_ptr<LaserGeomData> _pgeom;
00385 boost::shared_ptr<LaserSensorData> _pdata;
00386
00387
00388 string scantopic;
00389 RaveVector<float> _vColor;
00390
00391 Transform _trans;
00392 list<GraphHandlePtr> _listGraphicsHandles;
00393 GraphHandlePtr _graphgeometry;
00394
00395 boost::mutex _mutexdata;
00396 boost::thread _threadsensor;
00397 bool _bDestroyThread;
00398
00399 bool _bRenderData, _bRenderGeometry, _bPower;
00400 bool _bUpdatePlot;
00401
00402 friend class BaseLaser2DXMLReader;
00403 };
00404
00405 #endif