Infra Red Sensor in Gazebo
Hi I'm using ROS electric and I want to simulate an IRSensor in Gazebo. I've found a tutorial about creating new plugins but it works only for Fuerte. Anyone can help me to understand how to create a new controller gazeborosIR similar to gazeboroslaser.
EDIT: I looked at gazebo plugins and on the base of gazeboros laser I created a new package with two files: **ircontroller_file.h**,
#ifndef GAZEBO_ROS_IR_HH
#define GAZEBO_ROS_IR_HH
#define USE_CBQ
#ifdef USE_CBQ
#include <ros/callback_queue.h>
#include <ros/advertise_options.h>
#endif
#include <gazebo/Controller.hh>
#include <gazebo/Param.hh>
#include <ros/ros.h>
#include <boost/thread/mutex.hpp>
#include <sensor_msgs/Range.h>
namespace gazebo
{
class IRSensor;
class GazeboRosIr : public Controller
{
/// \brief Constructor
/// \param parent The parent entity, must be a Model or a Sensor
public: GazeboRosIr(Entity *parent);
/// \brief Destructor
public: virtual ~GazeboRosIr();
/// \brief Load the controller
/// \param node XML config node
protected: virtual void LoadChild(XMLConfigNode *node);
/// \brief Init the controller
protected: virtual void InitChild();
/// \brief Update the controller
protected: virtual void UpdateChild();
/// \brief Finalize the controller
protected: virtual void FiniChild();
/// \brief Put laser data to the ROS topic
private: void PutIrData();
/// \brief Keep track of number of connctions
private: int IrConnectCount;
private: void IrConnect();
private: void IrDisconnect();
private: int deprecatedIrConnectCount;
private: void DeprecatedIrConnect();
private: void DeprecatedIrDisconnect();
/// \brief The parent sensor
private: IRSensor *myParent;
/// \brief pointer to ros node
private: ros::NodeHandle* rosnode_;
private: ros::Publisher pub_;
private: ros::Publisher deprecated_pub_;
/// \brief ros message
private: sensor_msgs::Range irMsg;
/// \brief topic name
private: ParamT<std::string> *topicNameP;
private: std::string topicName;
private: ParamT<std::string> *deprecatedTopicNameP;
private: std::string deprecatedTopicName;
/// \brief frame transform name, should match link name
private: ParamT<std::string> *frameNameP;
private: std::string frameName;
/// \brief Gaussian noise
private: ParamT<double> *gaussianNoiseP;
private: double gaussianNoise;
/// \brief Gaussian noise generator
private: double GaussianKernel(double mu,double sigma);
/// \brief A mutex to lock access to fields that are used in message callbacks
private: boost::mutex lock;
/// \brief hack to mimic hokuyo intensity cutoff of 100
private: ParamT<double> *hokuyoMinIntensityP;
private: double hokuyoMinIntensity;
/// \brief for setting ROS name space
private: ParamT<std::string> *robotNamespaceP;
private: std::string robotNamespace;
#ifdef USE_CBQ
private: ros::CallbackQueue ir_queue_;
private: void IrQueueThread();
private: boost::thread callback_queue_thread_;
#endif
};
/** \} */
/// @}
}
#endif
and ircontrollerfile.cpp
#include <algorithm>
#include <assert.h>
#include <ir_controller_package/ir_controller_file.h>
#include <gazebo/Sensor.hh>
#include <gazebo/Global.hh>
#include <gazebo/XMLConfig.hh>
#include <gazebo/HingeJoint.hh>
#include <gazebo/World.hh>
#include <gazebo/Simulator.hh>
#include <gazebo/gazebo.h>
#include <gazebo/GazeboError.hh>
#include <gazebo/ControllerFactory.hh>
#include <gazebo/IRSensor.hh>
#include <pluginlib/class_list_macros.h>
namespace gazebo
{
GZ_REGISTER_DYNAMIC_CONTROLLER("ir_controller_package", GazeboRosIr);
////////////////////////////////////////////////////////////////////////////////
// Constructor
GazeboRosIr::GazeboRosIr(Entity *parent)
: Controller(parent)
{
this->myParent = dynamic_cast<IRSensor*>(this->parent);
if (!this->myParent)
gzthrow("GazeboRosIr controller requires a IR Sensor as its parent");
Param::Begin(&this->parameters);
this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0);
//this->hokuyoMinIntensityP = new ParamT<double>("hokuyoMinIntensity", 101.0, 0);
this->gaussianNoiseP = new ParamT<double>("gaussianNoise", 0.0, 0);
this->topicNameP = new ParamT<std::string>("topicName", "", 1);
this->deprecatedTopicNameP = new ParamT<std::string>("deprecatedTopicName", "", 0);
this->frameNameP = new ParamT<std::string>("frameName", "default_gazebo_ros_ir_frame", 0);
Param::End();
this->IrConnectCount = 0;
this->deprecatedIrConnectCount = 0;
}
////////////////////////////////////////////////////////////////////////////////
// Destructor
GazeboRosIr::~GazeboRosIr()
{
delete this->robotNamespaceP;
//delete this->hokuyoMinIntensityP;
delete this->gaussianNoiseP;
delete this->topicNameP;
delete this->deprecatedTopicNameP;
delete this->frameNameP;
delete this->rosnode_;
}
////////////////////////////////////////////////////////////////////////////////
// Load the controller
void GazeboRosIr::LoadChild(XMLConfigNode *node)
{
this->robotNamespaceP->Load(node);
this->robotNamespace = this->robotNamespaceP->GetValue();
if (!ros::isInitialized())
{
int argc = 0;
char** argv = NULL;
ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
}
this->rosnode_ = new ros::NodeHandle(this->robotNamespace);
//this->hokuyoMinIntensityP->Load(node);
//this->hokuyoMinIntensity = this->hokuyoMinIntensityP->GetValue();
//ROS_INFO("INFO: gazebo_ros_ir plugin artifically sets minimum intensity to %f due to cutoff in hokuyo filters." , this->hokuyoMinIntensity);
this->topicNameP->Load(node);
this->topicName = this->topicNameP->GetValue();
this->deprecatedTopicNameP->Load(node);
this->deprecatedTopicName = this->deprecatedTopicNameP->GetValue();
this->frameNameP->Load(node);
this->frameName = this->frameNameP->GetValue();
this->gaussianNoiseP->Load(node);
this->gaussianNoise = this->gaussianNoiseP->GetValue();
if (this->topicName != "")
{
#ifdef USE_CBQ
ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<sensor_msgs::Range>(
this->topicName,1,
boost::bind( &GazeboRosIr::IrConnect,this),
boost::bind( &GazeboRosIr::IrDisconnect,this), ros::VoidPtr(), &this->ir_queue_);
this->pub_ = this->rosnode_->advertise(ao);
#else
this->pub_ = this->rosnode_->advertise<sensor_msgs::Range>(this->topicName,1,
boost::bind( &GazeboRosIr::IrConnect, this),
boost::bind( &GazeboRosIr::IrDisconnect, this));
#endif
}
if (this->deprecatedTopicName != "")
{
#ifdef USE_CBQ
ros::AdvertiseOptions ao = ros::AdvertiseOptions::create<sensor_msgs::Range>(
this->deprecatedTopicName,1,
boost::bind( &GazeboRosIr::DeprecatedIrConnect,this),
boost::bind( &GazeboRosIr::DeprecatedIrDisconnect,this), ros::VoidPtr(), &this->ir_queue_);
this->deprecated_pub_ = this->rosnode_->advertise(ao);
#else
this->deprecated_pub_ = this->rosnode_->advertise<sensor_msgs::IrScan>(this->deprecatedTopicName,1,
boost::bind( &GazeboRosIr::DeprecatedIrConnect, this),
boost::bind( &GazeboRosIr::DeprecatedIrDisconnect, this));
#endif
}
}
////////////////////////////////////////////////////////////////////////////////
// Initialize the controller
void GazeboRosIr::InitChild()
{
// sensor generation off by default
this->myParent->SetActive(false);
#ifdef USE_CBQ
// start custom queue for Ir
this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosIr::IrQueueThread,this ) );
#endif
}
////////////////////////////////////////////////////////////////////////////////
// Increment count
void GazeboRosIr::IrConnect()
{
this->IrConnectCount++;
}
////////////////////////////////////////////////////////////////////////////////
// Decrement count
void GazeboRosIr::IrDisconnect()
{
this->IrConnectCount--;
if (this->IrConnectCount == 0 && this->deprecatedIrConnectCount == 0)
this->myParent->SetActive(false);
}
////////////////////////////////////////////////////////////////////////////////
// Increment count
void GazeboRosIr::DeprecatedIrConnect()
{
ROS_WARN("you are subscribing to a deprecated ROS topic %s, please change your code/launch script to use new ROS topic %s",
this->deprecatedTopicName.c_str(), this->topicName.c_str());
this->deprecatedIrConnectCount++;
}
////////////////////////////////////////////////////////////////////////////////
// Decrement count
void GazeboRosIr::DeprecatedIrDisconnect()
{
this->deprecatedIrConnectCount--;
if (this->IrConnectCount == 0 && this->deprecatedIrConnectCount == 0)
this->myParent->SetActive(false);
}
////////////////////////////////////////////////////////////////////////////////
// Update the controller
void GazeboRosIr::UpdateChild()
{
// as long as ros is connected, parent is active
//ROS_ERROR("debug ir count %d",this->irConnectCount);
if (!this->myParent->IsActive())
{
// do this first so there's chance for sensor to run 1 frame after activate
if ((this->IrConnectCount > 0 && this->topicName != "") ||
(this->deprecatedIrConnectCount > 0 && this->deprecatedTopicName != ""))
this->myParent->SetActive(true);
}
else
{
this->PutIrData();
}
}
////////////////////////////////////////////////////////////////////////////////
// Finalize the controller
void GazeboRosIr::FiniChild()
{
this->ir_queue_.clear();
this->ir_queue_.disable();
this->rosnode_->shutdown();
sleep(1);
#ifdef USE_CBQ
this->callback_queue_thread_.join();
#endif
}
////////////////////////////////////////////////////////////////////////////////
// Put Ir data to the interface
void GazeboRosIr::PutIrData()
{
// int i, ja, jb;
//double ra, rb, r, b;
//double intensity;
//Angle maxAngle = this->myParent->GetMaxAngle();
//Angle minAngle = this->myParent->GetMinAngle();
//double maxRange = this->myParent->GetMaxRange();
//double minRange = this->myParent->GetMinRange();
int irCount = this->myParent->GetIRCount();
//int rangeCount = this->myParent->GetRangeCount();
/***************************************************************/
/* */
/* point scan from Ir */
/* */
/***************************************************************/
this->lock.lock();
// Add Frame Name
this->irMsg.header.frame_id = this->frameName;
this->irMsg.header.stamp.sec = (Simulator::Instance()->GetSimTime()).sec;
this->irMsg.header.stamp.nsec = (Simulator::Instance()->GetSimTime()).nsec;
//double tmp_res_angle = (maxAngle.GetAsRadian() - minAngle.GetAsRadian())/((double)(rangeCount -1)); // for computing yaw
this->irMsg.min_range = 0;
this->irMsg.max_range = 250;
//this->irMsg.angle_increment = tmp_res_angle;
//this->irMsg.time_increment = 0; // instantaneous simulator scan
//this->irMsg.scan_time = 0; // FIXME: what's this?
//this->irMsg.range_min = minRange;
//this->irMsg.range_max = maxRange;
//this->irMsg.ranges.clear();
//this->irMsg.intensities.clear();
/*
// Interpolate the range readings from the rays
for (i = 0; i<rangeCount; i++)
{
b = (double) i * (rayCount - 1) / (rangeCount - 1);
ja = (int) floor(b);
jb = std::min(ja + 1, rayCount - 1);
b = b - floor(b);
assert(ja >= 0 && ja < rayCount);
assert(jb >= 0 && jb < rayCount);
ra = std::min(this->myParent->GetRange(ja) , maxRange-minRange); // length of ray
rb = std::min(this->myParent->GetRange(jb) , maxRange-minRange); // length of ray
// Range is linear interpolation if values are close,
// and min if they are very different
//if (fabs(ra - rb) < 0.10)
r = (1 - b) * ra + b * rb;
//else r = std::min(ra, rb);
// Intensity is averaged
intensity = 0.5*( this->myParent->GetRetro(ja) + (int) this->myParent->GetRetro(jb));
*/
/***************************************************************/
/* */
/* point scan from Ir */
/* */
/***************************************************************/
//this->irMsg.ranges.push_back(std::min(r + minRange + this->GaussianKernel(0,this->gaussianNoise), maxRange));
//this->irMsg.intensities.push_back(std::max(this->hokuyoMinIntensity,intensity + this->GaussianKernel(0,this->gaussianNoise)));
// }
this->irMsg.range=this->myParent->GetRange(0);
this->irMsg.field_of_view = 0;
this->irMsg.radiation_type=1;
// send data out via ros message
if (this->IrConnectCount > 0 && this->topicName != "")
this->pub_.publish(this->irMsg);
if (this->deprecatedIrConnectCount > 0 && this->deprecatedTopicName != "")
this->deprecated_pub_.publish(this->irMsg);
this->lock.unlock();
}
//////////////////////////////////////////////////////////////////////////////
// Utility for adding noise
double GazeboRosIr::GaussianKernel(double mu,double sigma)
{
// using Box-Muller transform to generate two independent standard normally disbributed normal variables
// see wikipedia
double U = (double)rand()/(double)RAND_MAX; // normalized uniform random variable
double V = (double)rand()/(double)RAND_MAX; // normalized uniform random variable
double X = sqrt(-2.0 * ::log(U)) * cos( 2.0*M_PI * V);
//double Y = sqrt(-2.0 * ::log(U)) * sin( 2.0*M_PI * V); // the other indep. normal variable
// we'll just use X
// scale to our mu and sigma
X = sigma * X + mu;
return X;
}
#ifdef USE_CBQ
////////////////////////////////////////////////////////////////////////////////
// Put ir data to the interface
void GazeboRosIr::IrQueueThread()
{
static const double timeout = 0.01;
while (this->rosnode_->ok())
{
this->ir_queue_.callAvailable(ros::WallDuration(timeout));
}
}
#endif
}
I added rosbuild_add_library(ir_controller_lib src/ir_controller_file.cpp)
to my CMakeLists.txt
Then I defined an IR element
<?xml version="1.0"?>
<robot
xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"
xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"
xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface">
<macro name="erratic_ir" params="parent *origin">
<joint name="my_ir_joint" type="fixed">
<insert_block name="origin" />
<parent link="${parent}" />
<child link="my_ir_link" />
</joint>
<link name="my_ir_link">
<inertial>
<mass value="0.01"/>
<origin xyz="0 0 0" />
<inertia ixx="0.001" ixy="0.0" ixz="0.0"
iyy="0.001" iyz="0.0" izx="0.0"
izz="0.001" />
</inertial>
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<box size="0.01 0.01 0.01" />
</geometry>
</visual>
<collision>
<origin xyz="0.0 0.0 0.0" rpy="0 0 0" />
<geometry>
<box size="0.001 0.001 0.001"/>
</geometry>
</collision>
</link>
<gazebo reference="my_ir_link">
<sensor:ir name="my_ir_sensor">
<minRange>0.06</minRange>
<maxRange>4.0</maxRange>
<updateRate>20.0</updateRate>
<controller:ir_controller_file name="my_ir_controller" plugin="libir_controller_lib.so">
<alwaysOn>true</alwaysOn>
<updateRate>20.0</updateRate>
<topicName>my_ir/ir</topicName>
<frameName>my_ir_link</frameName>
<interface:irarray name="my_ir_iface" />
</controller:ir_controller_file>
</sensor:ir>
<!-- <turnGravityOff>true</turnGravityOff> -->
<material>Erratic/White</material>
</gazebo>
</macro>
</robot>
and tried to add it to a pioneer p3dx model simulated in gazebo. But I receive the error:
Failed to load libircontrollerlib.so: libircontrollerlib.so: cannot open shared object file: No such file or directory
How can I let the simulation know where the library is? Many thanks!
Asked by camilla on 2013-02-26 00:27:44 UTC
Comments
Please ask gazebo questions on http://answers.gazebosim.org/questions/
Asked by tfoote on 2015-06-24 13:40:35 UTC