gazebo_ros_kobuki.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Yujin Robot.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of Yujin Robot nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00036 #include <cmath>
00037 #include <cstring>
00038 #include <boost/bind.hpp>
00039 #include <sensor_msgs/JointState.h>
00040 #include <LinearMath/btQuaternion.h>
00041 #include <math/gzmath.hh>
00042 #include "kobuki_gazebo_plugins/gazebo_ros_kobuki.h"
00043 
00044 namespace gazebo
00045 {
00046 
00047 enum {LEFT= 0, RIGHT=1};
00048 
00049 GazeboRosKobuki::GazeboRosKobuki() : shutdown_requested_(false)
00050 {
00051   // Start up ROS
00052 //  int argc = 0;
00053 //  ros::init(argc, NULL, "gazebo_ros_kobuki_node"); // looks like this is not needed
00054 // alternative
00055 //  if (!ros::isInitialized())
00056 //  {
00057 //    int argc = 0;
00058 //    char** argv = NULL;
00059 //    ros::init(argc, argv, "gazebo_kobuki", ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00060 //  }
00061   wheel_speed_cmd_[LEFT] = 0.0;
00062   wheel_speed_cmd_[RIGHT] = 0.0;
00063 
00064   // using the same values as in kobuki_node
00065   double pose_cov[36] = {0.1, 0, 0, 0, 0, 0,
00066                           0, 0.1, 0, 0, 0, 0,
00067                           0, 0, 1e6, 0, 0, 0,
00068                           0, 0, 0, 1e6, 0, 0,
00069                           0, 0, 0, 0, 1e6, 0,
00070                           0, 0, 0, 0, 0, 0.2};
00071   memcpy(&pose_cov, &pose_cov_, sizeof(double[36]));
00072 }
00073 
00074 GazeboRosKobuki::~GazeboRosKobuki()
00075 {
00076 //  rosnode_->shutdown();
00077   shutdown_requested_ = true;
00078   // Wait for spinner thread to end
00079 //  ros_spinner_thread_->join();
00080 
00081   //  delete spinner_thread_;
00082 //  delete rosnode_;
00083 }
00084 
00085 void GazeboRosKobuki::Load(physics::ModelPtr parent, sdf::ElementPtr sdf)
00086 {
00087   model_ = parent;
00088   if (!model_)
00089   {
00090     ROS_ERROR_STREAM("Invalid model pointer! [" << node_name_ << "]");
00091     return;
00092   }
00093   // Get then name of the parent model and use it as node name
00094   std::string model_name = sdf->GetParent()->GetValueString("name");
00095   gzdbg << "Plugin model name: " << model_name << "\n";
00096   nh_ = ros::NodeHandle("");
00097   // creating a private name pace until Gazebo implements topic remappings
00098   nh_priv_ = ros::NodeHandle("/" + model_name);
00099   node_name_ = model_name;
00100 
00101   world_ = parent->GetWorld();
00102 
00103 // TODO: use when implementing subs
00104 //  ros_spinner_thread_ = new boost::thread(boost::bind(&GazeboRosKobuki::spin, this));
00105 //
00106 //  this->node_namespace_ = "";
00107 //  if (_sdf->HasElement("node_namespace"))
00108 //    this->node_namespace_ = _sdf->GetElement("node_namespace")->GetValueString() + "/";
00109 
00110   /*
00111    * Prepare receiving motor power commands
00112    */
00113   motor_power_sub_ = nh_priv_.subscribe("commands/motor_power", 10, &GazeboRosKobuki::motorPowerCB, this);
00114   motors_enabled_ = true;
00115 
00116   /*
00117    * Prepare joint state publishing
00118    */
00119   if (sdf->HasElement("left_wheel_joint_name"))
00120   {
00121     left_wheel_joint_name_ = sdf->GetElement("left_wheel_joint_name")->GetValueString();
00122   }
00123   else
00124   {
00125     ROS_ERROR_STREAM("Couldn't find left wheel joint in the model description!"
00126                      << " Did you specify the correct joint name?" << " [" << node_name_ <<"]");
00127     return;
00128   }
00129   if (sdf->HasElement("right_wheel_joint_name"))
00130   {
00131     right_wheel_joint_name_ = sdf->GetElement("right_wheel_joint_name")->GetValueString();
00132   }
00133   else
00134   {
00135     ROS_ERROR_STREAM("Couldn't find right wheel joint in the model description!"
00136                      << " Did you specify the correct joint name?" << " [" << node_name_ <<"]");
00137     return;
00138   }
00139   joints_[LEFT] = parent->GetJoint(left_wheel_joint_name_);
00140   joints_[RIGHT] = parent->GetJoint(right_wheel_joint_name_);
00141   if (!joints_[LEFT] || !joints_[RIGHT])
00142   {
00143     ROS_ERROR_STREAM("Couldn't find specified wheel joints in the model! [" << node_name_ <<"]");
00144     return;
00145   }
00146   joint_state_.header.frame_id = "Joint States";
00147   joint_state_.name.push_back(left_wheel_joint_name_);
00148   joint_state_.position.push_back(0);
00149   joint_state_.velocity.push_back(0);
00150   joint_state_.effort.push_back(0);
00151   joint_state_.name.push_back(right_wheel_joint_name_);
00152   joint_state_.position.push_back(0);
00153   joint_state_.velocity.push_back(0);
00154   joint_state_.effort.push_back(0);
00155   joint_state_pub_ = nh_.advertise<sensor_msgs::JointState>("joint_states", 1);
00156 
00157   /*
00158    * Prepare publishing odometry data
00159    */
00160   if (sdf->HasElement("wheel_separation"))
00161   {
00162     wheel_sep_ = sdf->GetElement("wheel_separation")->GetValueDouble();
00163   }
00164   else
00165   {
00166     ROS_ERROR_STREAM("Couldn't find the wheel separation parameter in the model description!"
00167                      << " Did you specify it?" << " [" << node_name_ <<"]");
00168     return;
00169   }
00170   if (sdf->HasElement("wheel_diameter"))
00171   {
00172     wheel_diam_ = sdf->GetElement("wheel_diameter")->GetValueDouble();
00173   }
00174   else
00175   {
00176     ROS_ERROR_STREAM("Couldn't find the wheel diameter parameter in the model description!"
00177                      << " Did you specify it?" << " [" << node_name_ <<"]");
00178     return;
00179   }
00180   if (sdf->HasElement("torque"))
00181   {
00182     torque_ = sdf->GetElement("torque")->GetValueDouble();
00183   }
00184   else
00185   {
00186     ROS_ERROR_STREAM("Couldn't find the torque parameter in the model description!"
00187                      << " Did you specify it?" << " [" << node_name_ <<"]");
00188     return;
00189   }
00190   odom_pub_ = nh_.advertise<nav_msgs::Odometry>("odom", 1);
00191 
00192   /*
00193    * Prepare receiving velocity commands
00194    */
00195   if (sdf->HasElement("velocity_command_timeout"))
00196   {
00197     cmd_vel_timeout_ = sdf->GetElement("velocity_command_timeout")->GetValueDouble();
00198   }
00199   else
00200   {
00201     ROS_ERROR_STREAM("Couldn't find the wheel separation parameter in the model description!"
00202                      << " Did you specify it?" << " [" << node_name_ <<"]");
00203     return;
00204   }
00205   last_cmd_vel_time_ = world_->GetSimTime();
00206   cmd_vel_sub_ = nh_priv_.subscribe("commands/velocity", 100, &GazeboRosKobuki::cmdVelCB, this);
00207 
00208   /*
00209    * Prepare cliff sensors
00210    */
00211   std::string cliff_sensor_left_name, cliff_sensor_front_name, cliff_sensor_right_name;
00212   if (sdf->HasElement("cliff_sensor_left_name"))
00213   {
00214     cliff_sensor_left_name = sdf->GetElement("cliff_sensor_left_name")->GetValueString();
00215   }
00216   else
00217   {
00218     ROS_ERROR_STREAM("Couldn't find the name of left cliff sensor in the model description!"
00219                      << " Did you specify it?" << " [" << node_name_ <<"]");
00220     return;
00221   }
00222   if (sdf->HasElement("cliff_sensor_front_name"))
00223   {
00224     cliff_sensor_front_name = sdf->GetElement("cliff_sensor_front_name")->GetValueString();
00225   }
00226   else
00227   {
00228     ROS_ERROR_STREAM("Couldn't find the name of frontal cliff sensor in the model description!"
00229                      << " Did you specify it?" << " [" << node_name_ <<"]");
00230     return;
00231   }
00232   if (sdf->HasElement("cliff_sensor_right_name"))
00233   {
00234     cliff_sensor_right_name = sdf->GetElement("cliff_sensor_right_name")->GetValueString();
00235   }
00236   else
00237   {
00238     ROS_ERROR_STREAM("Couldn't find the name of right cliff sensor in the model description!"
00239                      << " Did you specify it?" << " [" << node_name_ <<"]");
00240     return;
00241   }
00242   cliff_sensor_left_ = boost::shared_dynamic_cast<sensors::RaySensor>(
00243                        sensors::SensorManager::Instance()->GetSensor(cliff_sensor_left_name));
00244   cliff_sensor_front_ = boost::shared_dynamic_cast<sensors::RaySensor>(
00245                         sensors::SensorManager::Instance()->GetSensor(cliff_sensor_front_name));
00246   cliff_sensor_right_ = boost::shared_dynamic_cast<sensors::RaySensor>(
00247                         sensors::SensorManager::Instance()->GetSensor(cliff_sensor_right_name));
00248   if (!cliff_sensor_left_)
00249   {
00250     ROS_ERROR_STREAM("Couldn't find the left cliff sensor in the model! [" << node_name_ <<"]");
00251     return;
00252   }
00253   if (!cliff_sensor_front_)
00254   {
00255     ROS_ERROR_STREAM("Couldn't find the frontal cliff sensor in the model! [" << node_name_ <<"]");
00256     return;
00257   }
00258   if (!cliff_sensor_right_)
00259   {
00260     ROS_ERROR_STREAM("Couldn't find the right cliff sensor in the model! [" << node_name_ <<"]");
00261     return;
00262   }
00263   if (sdf->HasElement("cliff_detection_threshold"))
00264   {
00265     cliff_detection_threshold_ = sdf->GetElement("cliff_detection_threshold")->GetValueDouble();
00266   }
00267   else
00268   {
00269     ROS_ERROR_STREAM("Couldn't find the cliff detection threshold parameter in the model description!"
00270                      << " Did you specify it?" << " [" << node_name_ <<"]");
00271     return;
00272   }
00273   cliff_sensor_left_->SetActive(true);
00274   cliff_sensor_front_->SetActive(true);
00275   cliff_sensor_right_->SetActive(true);
00276   cliff_event_pub_ = nh_priv_.advertise<kobuki_msgs::CliffEvent>("events/cliff", 1);
00277 
00278   /*
00279    * Prepare bumper
00280    */
00281   std::string bumper_name;
00282   if (sdf->HasElement("bumper_name"))
00283   {
00284     bumper_name = sdf->GetElement("bumper_name")->GetValueString();
00285   }
00286   else
00287   {
00288     ROS_ERROR_STREAM("Couldn't find the name of bumper sensor in the model description!"
00289                      << " Did you specify it?" << " [" << node_name_ <<"]");
00290     return;
00291   }
00292   bumper_ = boost::shared_dynamic_cast<sensors::ContactSensor>(
00293             sensors::SensorManager::Instance()->GetSensor(bumper_name));
00294   bumper_->SetActive(true);
00295   bumper_event_pub_ = nh_priv_.advertise<kobuki_msgs::BumperEvent>("events/bumper", 1);
00296 
00297   prev_update_time_ = world_->GetSimTime();
00298   ROS_INFO_STREAM("GazeboRosKobuki plugin ready to go! [" << node_name_ << "]");
00299   update_connection_ = event::Events::ConnectWorldUpdateStart(boost::bind(&GazeboRosKobuki::OnUpdate, this));
00300 }
00301 
00302 void GazeboRosKobuki::motorPowerCB( const kobuki_msgs::MotorPowerPtr &msg)
00303 {
00304   if ((msg->state == kobuki_msgs::MotorPower::ON) && (!motors_enabled_))
00305   {
00306     motors_enabled_ = true;
00307     ROS_INFO_STREAM("Motors fired up. [" << node_name_ << "]");
00308   }
00309   else if ((msg->state == kobuki_msgs::MotorPower::OFF) && (motors_enabled_))
00310   {
00311     motors_enabled_ = false;
00312     ROS_INFO_STREAM("Motors taking a rest. [" << node_name_ << "]");
00313   }
00314 }
00315 
00316 void GazeboRosKobuki::cmdVelCB( const geometry_msgs::TwistConstPtr &msg)
00317 {
00318   last_cmd_vel_time_ = world_->GetSimTime();
00319   wheel_speed_cmd_[LEFT] = msg->linear.x - msg->angular.z * (wheel_sep_) / 2;
00320   wheel_speed_cmd_[RIGHT] = msg->linear.x + msg->angular.z * (wheel_sep_) / 2;
00321 }
00322 
00323 void GazeboRosKobuki::OnUpdate()
00324 {
00325   /*
00326    * First process ROS callbacks
00327    */
00328   ros::spinOnce();
00329 
00330   /*
00331    * Update current time and time step
00332    */
00333   common::Time time_now = world_->GetSimTime();
00334   common::Time step_time = time_now - prev_update_time_;
00335   prev_update_time_ = time_now;
00336 
00337   /*
00338    * Joint states
00339    */
00340   joint_state_.header.stamp.sec = time_now.sec;
00341   joint_state_.header.stamp.nsec = time_now.nsec;
00342   joint_state_.position[LEFT] = joints_[LEFT]->GetAngle(0).Radian();
00343   joint_state_.velocity[LEFT] = joints_[LEFT]->GetVelocity(0);
00344   joint_state_.position[RIGHT] = joints_[RIGHT]->GetAngle(0).Radian();
00345   joint_state_.velocity[RIGHT] = joints_[RIGHT]->GetVelocity(0);
00346   joint_state_pub_.publish(joint_state_);
00347 
00348   /*
00349    * Odometry
00350    */
00351   odom_.header.stamp.sec = time_now.sec;
00352   odom_.header.stamp.nsec = time_now.nsec;
00353   odom_.header.frame_id = "odom";
00354   odom_.child_frame_id = "base_footprint";
00355   odom_tf_.header = odom_.header;
00356   odom_tf_.child_frame_id = odom_.child_frame_id;
00357 
00358   // Distance travelled by front wheels
00359   double d1, d2;
00360   double dr, da;
00361   d1 = d2 = 0;
00362   dr = da = 0;
00363 //  if (set_joints_[LEFT])
00364   d1 = step_time.Double() * (wheel_diam_ / 2) * joints_[LEFT]->GetVelocity(0);
00365 //  if (set_joints_[RIGHT])
00366   d2 = step_time.Double() * (wheel_diam_ / 2) * joints_[RIGHT]->GetVelocity(0);
00367   // Can see NaN values here, just zero them out if needed
00368   if (isnan(d1))
00369   {
00370     ROS_WARN_STREAM_THROTTLE(0.1, "Gazebo ROS Kobuki plugin: NaN in d1. Step time: " << step_time.Double()
00371                              << ", WD: " << wheel_diam_ << ", velocity: " << joints_[LEFT]->GetVelocity(0));
00372     d1 = 0;
00373   }
00374   if (isnan(d2))
00375   {
00376     ROS_WARN_STREAM_THROTTLE(0.1, "Gazebo ROS Kobuki plugin: NaN in d2. Step time: " << step_time.Double()
00377                              << ", WD: " << wheel_diam_ << ", velocity: " << joints_[RIGHT]->GetVelocity(0));
00378     d2 = 0;
00379   }
00380   dr = (d1 + d2) / 2;
00381   da = (d2 - d1) / wheel_sep_;
00382 
00383   // Compute odometric pose
00384   odom_pose_[0] += dr * cos( odom_pose_[2] );
00385   odom_pose_[1] += dr * sin( odom_pose_[2] );
00386   odom_pose_[2] += da;
00387   // Compute odometric instantaneous velocity
00388   odom_vel_[0] = dr / step_time.Double();
00389   odom_vel_[1] = 0.0;
00390   odom_vel_[2] = da / step_time.Double();
00391 
00392   odom_.pose.pose.position.x = odom_pose_[0];
00393   odom_.pose.pose.position.y = odom_pose_[1];
00394   odom_.pose.pose.position.z = 0;
00395 
00396   btQuaternion qt;
00397   qt.setEuler(0,0,odom_pose_[2]);
00398   odom_.pose.pose.orientation.x = qt.getX();
00399   odom_.pose.pose.orientation.y = qt.getY();
00400   odom_.pose.pose.orientation.z = qt.getZ();
00401   odom_.pose.pose.orientation.w = qt.getW();
00402 
00403   memcpy(&odom_.pose.covariance[0], pose_cov_, sizeof(double)*36);
00404   memcpy(&odom_.twist.covariance[0], pose_cov_, sizeof(double)*36);
00405 
00406   odom_.twist.twist.linear.x = 0;
00407   odom_.twist.twist.linear.y = 0;
00408   odom_.twist.twist.linear.z = 0;
00409   odom_.twist.twist.angular.x = 0;
00410   odom_.twist.twist.angular.y = 0;
00411   odom_.twist.twist.angular.z = 0;
00412   odom_pub_.publish(odom_); // publish odom message
00413   odom_tf_.transform.translation.x = odom_.pose.pose.position.x;
00414   odom_tf_.transform.translation.y = odom_.pose.pose.position.y;
00415   odom_tf_.transform.translation.z = odom_.pose.pose.position.z;
00416   odom_tf_.transform.rotation = odom_.pose.pose.orientation;
00417   tf_broadcaster_.sendTransform(odom_tf_);
00418 
00419 
00420 
00421   /*
00422    * Propagate velocity commands
00423    * TODO: Check how to simulate disabled motors, e.g. set MaxForce to zero, but then damping is important!
00424    */
00425   if (((time_now - last_cmd_vel_time_).Double() > cmd_vel_timeout_) || !motors_enabled_)
00426   {
00427     wheel_speed_cmd_[LEFT] = 0.0;
00428     wheel_speed_cmd_[RIGHT] = 0.0;
00429   }
00430   joints_[LEFT]->SetVelocity(0, wheel_speed_cmd_[LEFT] / (wheel_diam_ / 2.0));
00431   joints_[RIGHT]->SetVelocity(0, wheel_speed_cmd_[RIGHT] / (wheel_diam_ / 2.0));
00432   joints_[LEFT]->SetMaxForce(0, torque_);
00433   joints_[RIGHT]->SetMaxForce(0, torque_);
00434 
00435   /*
00436    * Cliff sensors
00437    */
00438   // check current state
00439   cliff_event_.sensor = 0;
00440   cliff_event_.state = kobuki_msgs::CliffEvent::FLOOR;
00441   if (cliff_sensor_left_->GetRange(0) >= cliff_detection_threshold_)
00442   {
00443     cliff_event_.sensor += kobuki_msgs::CliffEvent::LEFT;
00444     cliff_event_.state = kobuki_msgs::CliffEvent::CLIFF;
00445     max_floot_dist_ = cliff_sensor_left_->GetRange(0);
00446   }
00447   if (cliff_sensor_front_->GetRange(0) >= cliff_detection_threshold_)
00448   {
00449     cliff_event_.sensor += kobuki_msgs::CliffEvent::CENTER;
00450     cliff_event_.state = kobuki_msgs::CliffEvent::CLIFF;
00451     if (cliff_sensor_front_->GetRange(0) > max_floot_dist_)
00452     {
00453       max_floot_dist_ = cliff_sensor_front_->GetRange(0);
00454     }
00455   }
00456   if (cliff_sensor_right_->GetRange(0) >= cliff_detection_threshold_)
00457   {
00458     cliff_event_.sensor += kobuki_msgs::CliffEvent::RIGHT;
00459     cliff_event_.state = kobuki_msgs::CliffEvent::CLIFF;
00460     if (cliff_sensor_right_->GetRange(0) > max_floot_dist_)
00461     {
00462       max_floot_dist_ = cliff_sensor_right_->GetRange(0);
00463     }
00464   }
00465   // Only publish new message, if something has changed
00466   if ((cliff_event_.state == kobuki_msgs::CliffEvent::CLIFF)
00467       && (cliff_event_.sensor != cliff_event_old_.sensor))
00468   {
00469 //    max_floot_dist_ = static_cast<int>(0.995f / ( tan( static_cast<float>( m_pk.psd[i]) / 76123.0f )
00470     cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, max_floot_dist_)); // convert distance back to an AD reading
00471     cliff_event_pub_.publish(cliff_event_);
00472     cliff_event_old_ = cliff_event_;
00473   }
00474   /*
00475    * Bumpers
00476    */
00477   msgs::Contacts contacts;
00478   contacts = bumper_->GetContacts();
00479 
00480 //  for (int i = 0; i < contacts.contact_size(); ++i)
00481 //  {
00482 //    std::cout << "Collision between[" << contacts.contact(i).collision1()
00483 //              << "] and [" << contacts.contact(i).collision2() << "]\n";
00484 //
00485 //    for (int j = 0; j < contacts.contact(i).position_size(); ++j)
00486 //    {
00487 //      std::cout << j << "  Position:"
00488 //                << contacts.contact(i).position(j).x() << " "
00489 //                << contacts.contact(i).position(j).y() << " "
00490 //                << contacts.contact(i).position(j).z() << "\n";
00491 //      std::cout << "   Normal:"
00492 //                << contacts.contact(i).normal(j).x() << " "
00493 //                << contacts.contact(i).normal(j).y() << " "
00494 //                << contacts.contact(i).normal(j).z() << "\n";
00495 //      std::cout << "   Depth:" << contacts.contact(i).depth(j) << "\n";
00496 //    }
00497 //  }
00498 
00499   // In order to simulate the three bumper sensors, a contact is assigned to one of the bumpers
00500   // depending on its position. Each sensor covers a range of 60 degrees.
00501   // +90 ... +30: left bumper
00502   // +30 ... -30: centre bumper
00503   // -30 ... -90: right bumper
00504   bumper_event_.state = 0;
00505   bumper_event_.bumper = 0;
00506   // flags used for avoiding multiple triggering of the same bumper due to multiple contacts
00507   bool bumper_left_pressed = false;
00508   bool bumper_centre_pressed = false;
00509   bool bumper_right_pressed = false;
00510 
00511 
00512   for (int i = 0; i < contacts.contact_size(); ++i)
00513   {
00514     if ((contacts.contact(i).position(0).z() >= 0.015)
00515         && (contacts.contact(i).position(0).z() <= 0.085)) // only consider contacts at the height of the bumper
00516     {
00517       math::Pose current_pose = model_->GetWorldPose();
00518       double robot_heading = current_pose.rot.GetYaw();
00519       // using the force normals below, since the contact position is given in world coordinates
00520       // negate normal, because it points from contact to robot centre
00521       double global_contact_angle = std::atan2(-contacts.contact(i).normal(0).y(), -contacts.contact(i).normal(0).x());
00522       double relative_contact_angle = global_contact_angle - robot_heading;
00523 
00524       std::cout << "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" << std::endl;
00525                 std::cout << "   Position:"
00526                           << contacts.contact(i).position(0).x() << " "
00527                           << contacts.contact(i).position(0).y() << " "
00528                           << contacts.contact(i).position(0).z() << "\n";
00529                 std::cout << "   Normal:"
00530                           << contacts.contact(i).normal(0).x() << " "
00531                           << contacts.contact(i).normal(0).y() << " "
00532                           << contacts.contact(i).normal(0).z() << "\n";
00533 //      std::cout << "Current robot heading: " << (robot_heading * (180/M_PI)) << std::endl;
00534 //      std::cout << "Global contact angle: " << (contact_angle * (180/M_PI)) << std::endl;
00535 //      std::cout << "Robot contact angle: " << (relative_contact_angle * (180/M_PI)) << std::endl;
00536       if ((relative_contact_angle <= (M_PI/2)) && (relative_contact_angle > (M_PI/6)))
00537       {
00538         if (!bumper_left_pressed)
00539         {
00540           bumper_left_pressed = true;
00541           bumper_event_.state = kobuki_msgs::BumperEvent::PRESSED;
00542           bumper_event_.bumper += kobuki_msgs::BumperEvent::LEFT;
00543 //          std::cout << "Left bumper pressed." << std::endl;
00544 //          std::cout << "-----------------------------------------" << std::endl;
00545         }
00546       }
00547       else if ((relative_contact_angle <= (M_PI/6)) && (relative_contact_angle >= (-M_PI/6)))
00548       {
00549         if (!bumper_centre_pressed)
00550         {
00551           bumper_centre_pressed = true;
00552           bumper_event_.state = kobuki_msgs::BumperEvent::PRESSED;
00553           bumper_event_.bumper += kobuki_msgs::BumperEvent::CENTER;
00554 //          std::cout << "Centre bumper pressed." << std::endl;
00555 //          std::cout << "-----------------------------------------" << std::endl;
00556         }
00557       }
00558       else if ((relative_contact_angle < (-M_PI/6)) && (relative_contact_angle >= (-M_PI/2)))
00559       {
00560         if (!bumper_right_pressed)
00561         {
00562           bumper_right_pressed = true;
00563           bumper_event_.state = kobuki_msgs::BumperEvent::PRESSED;
00564           bumper_event_.bumper += kobuki_msgs::BumperEvent::RIGHT;
00565 //          std::cout << "Right bumper pressed." << std::endl;
00566 //          std::cout << "-----------------------------------------" << std::endl;
00567         }
00568       }
00569     }
00570   }
00571   // Only publish new message, if something has changed
00572   if ((bumper_event_.state != bumper_event_old_.state)
00573       || (bumper_event_.bumper != bumper_event_old_.bumper))
00574   {
00575     bumper_event_pub_.publish(bumper_event_);
00576     bumper_event_old_ = bumper_event_;
00577   }
00578 }
00579 
00580 
00581 void GazeboRosKobuki::spin()
00582 {
00583   while(ros::ok() && !shutdown_requested_)
00584   {
00585     ros::spinOnce();
00586   }
00587 }
00588 
00589 // Register this plugin with the simulator
00590 GZ_REGISTER_MODEL_PLUGIN(GazeboRosKobuki);
00591 
00592 } // namespace gazebo


kobuki_gazebo_plugins
Author(s): Marcus Liebhardt
autogenerated on Mon Oct 6 2014 01:31:55