Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00036 #include <cmath>
00037 #include <cstring>
00038 #include <boost/bind.hpp>
00039 #include <sensor_msgs/JointState.h>
00040 #include <tf/LinearMath/Quaternion.h>
00041 #include <gazebo/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
00052 if (!ros::isInitialized())
00053 {
00054 ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
00055 << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
00056 return;
00057 }
00058
00059
00060 wheel_speed_cmd_[LEFT] = 0.0;
00061 wheel_speed_cmd_[RIGHT] = 0.0;
00062 cliff_detected_left_ = false;
00063 cliff_detected_center_ = false;
00064 cliff_detected_right_ = false;
00065 }
00066
00067 GazeboRosKobuki::~GazeboRosKobuki()
00068 {
00069
00070 shutdown_requested_ = true;
00071
00072
00073
00074
00075
00076 }
00077
00078 void GazeboRosKobuki::Load(physics::ModelPtr parent, sdf::ElementPtr sdf)
00079 {
00080 model_ = parent;
00081 if (!model_)
00082 {
00083 ROS_ERROR_STREAM("Invalid model pointer! [" << node_name_ << "]");
00084 return;
00085 }
00086
00087 std::string model_name = sdf->GetParent()->Get<std::string>("name");
00088 gzdbg << "Plugin model name: " << model_name << "\n";
00089 nh_ = ros::NodeHandle("");
00090
00091 nh_priv_ = ros::NodeHandle("/" + model_name);
00092 node_name_ = model_name;
00093
00094 world_ = parent->GetWorld();
00095
00096
00097
00098
00099 motor_power_sub_ = nh_priv_.subscribe("commands/motor_power", 10, &GazeboRosKobuki::motorPowerCB, this);
00100 motors_enabled_ = true;
00101
00102
00103
00104
00105 if (sdf->HasElement("left_wheel_joint_name"))
00106 {
00107 left_wheel_joint_name_ = sdf->GetElement("left_wheel_joint_name")->Get<std::string>();
00108 }
00109 else
00110 {
00111 ROS_ERROR_STREAM("Couldn't find left wheel joint in the model description!"
00112 << " Did you specify the correct joint name?" << " [" << node_name_ <<"]");
00113 return;
00114 }
00115 if (sdf->HasElement("right_wheel_joint_name"))
00116 {
00117 right_wheel_joint_name_ = sdf->GetElement("right_wheel_joint_name")->Get<std::string>();
00118 }
00119 else
00120 {
00121 ROS_ERROR_STREAM("Couldn't find right wheel joint in the model description!"
00122 << " Did you specify the correct joint name?" << " [" << node_name_ <<"]");
00123 return;
00124 }
00125 joints_[LEFT] = parent->GetJoint(left_wheel_joint_name_);
00126 joints_[RIGHT] = parent->GetJoint(right_wheel_joint_name_);
00127 if (!joints_[LEFT] || !joints_[RIGHT])
00128 {
00129 ROS_ERROR_STREAM("Couldn't find specified wheel joints in the model! [" << node_name_ <<"]");
00130 return;
00131 }
00132 joint_state_.header.frame_id = "Joint States";
00133 joint_state_.name.push_back(left_wheel_joint_name_);
00134 joint_state_.position.push_back(0);
00135 joint_state_.velocity.push_back(0);
00136 joint_state_.effort.push_back(0);
00137 joint_state_.name.push_back(right_wheel_joint_name_);
00138 joint_state_.position.push_back(0);
00139 joint_state_.velocity.push_back(0);
00140 joint_state_.effort.push_back(0);
00141 joint_state_pub_ = nh_.advertise<sensor_msgs::JointState>("joint_states", 1);
00142
00143
00144
00145
00146 if (sdf->HasElement("publish_tf"))
00147 {
00148 publish_tf_ = sdf->GetElement("publish_tf")->Get<bool>();
00149 if (publish_tf_)
00150 {
00151 ROS_INFO_STREAM("Will publish tf." << " [" << node_name_ <<"]");
00152 }
00153 else
00154 {
00155 ROS_INFO_STREAM("Won't publish tf." << " [" << node_name_ <<"]");
00156 }
00157 }
00158 else
00159 {
00160 publish_tf_ = false;
00161 ROS_INFO_STREAM("Couldn't find the 'publish tf' parameter in the model description."
00162 << " Won't publish tf." << " [" << node_name_ <<"]");
00163 return;
00164 }
00165 if (sdf->HasElement("wheel_separation"))
00166 {
00167 wheel_sep_ = sdf->GetElement("wheel_separation")->Get<double>();
00168 }
00169 else
00170 {
00171 ROS_ERROR_STREAM("Couldn't find the wheel separation parameter in the model description!"
00172 << " Did you specify it?" << " [" << node_name_ <<"]");
00173 return;
00174 }
00175 if (sdf->HasElement("wheel_diameter"))
00176 {
00177 wheel_diam_ = sdf->GetElement("wheel_diameter")->Get<double>();
00178 }
00179 else
00180 {
00181 ROS_ERROR_STREAM("Couldn't find the wheel diameter parameter in the model description!"
00182 << " Did you specify it?" << " [" << node_name_ <<"]");
00183 return;
00184 }
00185 if (sdf->HasElement("torque"))
00186 {
00187 torque_ = sdf->GetElement("torque")->Get<double>();
00188 }
00189 else
00190 {
00191 ROS_ERROR_STREAM("Couldn't find the torque parameter in the model description!"
00192 << " Did you specify it?" << " [" << node_name_ <<"]");
00193 return;
00194 }
00195 odom_pose_[0] = 0.0;
00196 odom_pose_[1] = 0.0;
00197 odom_pose_[2] = 0.0;
00198 odom_pub_ = nh_.advertise<nav_msgs::Odometry>("odom", 1);
00199 odom_reset_sub_ = nh_priv_.subscribe("commands/reset_odometry", 10, &GazeboRosKobuki::resetOdomCB, this);
00200
00201
00202
00203
00204 if (sdf->HasElement("velocity_command_timeout"))
00205 {
00206 cmd_vel_timeout_ = sdf->GetElement("velocity_command_timeout")->Get<double>();
00207 }
00208 else
00209 {
00210 ROS_ERROR_STREAM("Couldn't find the wheel separation parameter in the model description!"
00211 << " Did you specify it?" << " [" << node_name_ <<"]");
00212 return;
00213 }
00214 last_cmd_vel_time_ = world_->GetSimTime();
00215 cmd_vel_sub_ = nh_priv_.subscribe("commands/velocity", 100, &GazeboRosKobuki::cmdVelCB, this);
00216
00217
00218
00219
00220 std::string cliff_sensor_left_name, cliff_sensor_center_name, cliff_sensor_right_name;
00221 if (sdf->HasElement("cliff_sensor_left_name"))
00222 {
00223 cliff_sensor_left_name = sdf->GetElement("cliff_sensor_left_name")->Get<std::string>();
00224 }
00225 else
00226 {
00227 ROS_ERROR_STREAM("Couldn't find the name of left cliff sensor in the model description!"
00228 << " Did you specify it?" << " [" << node_name_ <<"]");
00229 return;
00230 }
00231 if (sdf->HasElement("cliff_sensor_center_name"))
00232 {
00233 cliff_sensor_center_name = sdf->GetElement("cliff_sensor_center_name")->Get<std::string>();
00234 }
00235 else
00236 {
00237 ROS_ERROR_STREAM("Couldn't find the name of frontal cliff sensor in the model description!"
00238 << " Did you specify it?" << " [" << node_name_ <<"]");
00239 return;
00240 }
00241 if (sdf->HasElement("cliff_sensor_right_name"))
00242 {
00243 cliff_sensor_right_name = sdf->GetElement("cliff_sensor_right_name")->Get<std::string>();
00244 }
00245 else
00246 {
00247 ROS_ERROR_STREAM("Couldn't find the name of right cliff sensor in the model description!"
00248 << " Did you specify it?" << " [" << node_name_ <<"]");
00249 return;
00250 }
00251 cliff_sensor_left_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00252 sensors::SensorManager::Instance()->GetSensor(cliff_sensor_left_name));
00253 cliff_sensor_center_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00254 sensors::SensorManager::Instance()->GetSensor(cliff_sensor_center_name));
00255 cliff_sensor_right_ = boost::dynamic_pointer_cast<sensors::RaySensor>(
00256 sensors::SensorManager::Instance()->GetSensor(cliff_sensor_right_name));
00257 if (!cliff_sensor_left_)
00258 {
00259 ROS_ERROR_STREAM("Couldn't find the left cliff sensor in the model! [" << node_name_ <<"]");
00260 return;
00261 }
00262 if (!cliff_sensor_center_)
00263 {
00264 ROS_ERROR_STREAM("Couldn't find the center cliff sensor in the model! [" << node_name_ <<"]");
00265 return;
00266 }
00267 if (!cliff_sensor_right_)
00268 {
00269 ROS_ERROR_STREAM("Couldn't find the right cliff sensor in the model! [" << node_name_ <<"]");
00270 return;
00271 }
00272 if (sdf->HasElement("cliff_detection_threshold"))
00273 {
00274 cliff_detection_threshold_ = sdf->GetElement("cliff_detection_threshold")->Get<double>();
00275 }
00276 else
00277 {
00278 ROS_ERROR_STREAM("Couldn't find the cliff detection threshold parameter in the model description!"
00279 << " Did you specify it?" << " [" << node_name_ <<"]");
00280 return;
00281 }
00282 cliff_sensor_left_->SetActive(true);
00283 cliff_sensor_center_->SetActive(true);
00284 cliff_sensor_right_->SetActive(true);
00285 cliff_event_pub_ = nh_priv_.advertise<kobuki_msgs::CliffEvent>("events/cliff", 1);
00286
00287
00288
00289
00290 std::string bumper_name;
00291 if (sdf->HasElement("bumper_name"))
00292 {
00293 bumper_name = sdf->GetElement("bumper_name")->Get<std::string>();
00294 }
00295 else
00296 {
00297 ROS_ERROR_STREAM("Couldn't find the name of bumper sensor in the model description!"
00298 << " Did you specify it?" << " [" << node_name_ <<"]");
00299 return;
00300 }
00301 bumper_ = boost::dynamic_pointer_cast<sensors::ContactSensor>(
00302 sensors::SensorManager::Instance()->GetSensor(bumper_name));
00303 if (!bumper_)
00304 {
00305 ROS_ERROR_STREAM("Couldn't find the bumpers in the model! [" << node_name_ <<"]");
00306 return;
00307 }
00308 bumper_->SetActive(true);
00309 bumper_event_pub_ = nh_priv_.advertise<kobuki_msgs::BumperEvent>("events/bumper", 1);
00310
00311
00312
00313
00314 std::string imu_name;
00315 if (sdf->HasElement("imu_name"))
00316 {
00317 imu_name = sdf->GetElement("imu_name")->Get<std::string>();
00318 }
00319 else
00320 {
00321 ROS_ERROR_STREAM("Couldn't find the name of IMU sensor in the model description!"
00322 << " Did you specify it?" << " [" << node_name_ <<"]");
00323 return;
00324 }
00325 imu_ = boost::dynamic_pointer_cast<sensors::ImuSensor>(
00326 sensors::SensorManager::Instance()->GetSensor(imu_name));
00327 if (!imu_)
00328 {
00329 ROS_ERROR_STREAM("Couldn't find the IMU in the model! [" << node_name_ <<"]");
00330 return;
00331 }
00332 imu_->SetActive(true);
00333 imu_pub_ = nh_priv_.advertise<sensor_msgs::Imu>("sensors/imu_data", 1);
00334
00335 prev_update_time_ = world_->GetSimTime();
00336 ROS_INFO_STREAM("GazeboRosKobuki plugin ready to go! [" << node_name_ << "]");
00337 update_connection_ = event::Events::ConnectWorldUpdateBegin(boost::bind(&GazeboRosKobuki::OnUpdate, this));
00338 }
00339
00340 void GazeboRosKobuki::motorPowerCB(const kobuki_msgs::MotorPowerPtr &msg)
00341 {
00342 if ((msg->state == kobuki_msgs::MotorPower::ON) && (!motors_enabled_))
00343 {
00344 motors_enabled_ = true;
00345 ROS_INFO_STREAM("Motors fired up. [" << node_name_ << "]");
00346 }
00347 else if ((msg->state == kobuki_msgs::MotorPower::OFF) && (motors_enabled_))
00348 {
00349 motors_enabled_ = false;
00350 ROS_INFO_STREAM("Motors taking a rest. [" << node_name_ << "]");
00351 }
00352 }
00353
00354 void GazeboRosKobuki::cmdVelCB(const geometry_msgs::TwistConstPtr &msg)
00355 {
00356 last_cmd_vel_time_ = world_->GetSimTime();
00357 wheel_speed_cmd_[LEFT] = msg->linear.x - msg->angular.z * (wheel_sep_) / 2;
00358 wheel_speed_cmd_[RIGHT] = msg->linear.x + msg->angular.z * (wheel_sep_) / 2;
00359 }
00360
00361 void GazeboRosKobuki::resetOdomCB(const std_msgs::EmptyConstPtr &msg)
00362 {
00363 odom_pose_[0] = 0.0;
00364 odom_pose_[1] = 0.0;
00365 odom_pose_[2] = 0.0;
00366 }
00367
00368 void GazeboRosKobuki::OnUpdate()
00369 {
00370
00371
00372
00373 ros::spinOnce();
00374
00375
00376
00377
00378 common::Time time_now = world_->GetSimTime();
00379 common::Time step_time = time_now - prev_update_time_;
00380 prev_update_time_ = time_now;
00381
00382
00383
00384
00385 joint_state_.header.stamp = ros::Time::now();
00386 joint_state_.header.frame_id = "base_link";
00387 joint_state_.position[LEFT] = joints_[LEFT]->GetAngle(0).Radian();
00388 joint_state_.velocity[LEFT] = joints_[LEFT]->GetVelocity(0);
00389 joint_state_.position[RIGHT] = joints_[RIGHT]->GetAngle(0).Radian();
00390 joint_state_.velocity[RIGHT] = joints_[RIGHT]->GetVelocity(0);
00391 joint_state_pub_.publish(joint_state_);
00392
00393
00394
00395
00396 odom_.header.stamp = joint_state_.header.stamp;
00397 odom_.header.frame_id = "odom";
00398 odom_.child_frame_id = "base_footprint";
00399
00400
00401 double d1, d2;
00402 double dr, da;
00403 d1 = d2 = 0;
00404 dr = da = 0;
00405 d1 = step_time.Double() * (wheel_diam_ / 2) * joints_[LEFT]->GetVelocity(0);
00406 d2 = step_time.Double() * (wheel_diam_ / 2) * joints_[RIGHT]->GetVelocity(0);
00407
00408 if (isnan(d1))
00409 {
00410 ROS_WARN_STREAM_THROTTLE(0.1, "Gazebo ROS Kobuki plugin: NaN in d1. Step time: " << step_time.Double()
00411 << ", WD: " << wheel_diam_ << ", velocity: " << joints_[LEFT]->GetVelocity(0));
00412 d1 = 0;
00413 }
00414 if (isnan(d2))
00415 {
00416 ROS_WARN_STREAM_THROTTLE(0.1, "Gazebo ROS Kobuki plugin: NaN in d2. Step time: " << step_time.Double()
00417 << ", WD: " << wheel_diam_ << ", velocity: " << joints_[RIGHT]->GetVelocity(0));
00418 d2 = 0;
00419 }
00420 dr = (d1 + d2) / 2;
00421 da = (d2 - d1) / wheel_sep_;
00422
00423
00424 vel_angular_ = imu_->GetAngularVelocity();
00425
00426
00427 odom_pose_[0] += dr * cos( odom_pose_[2] );
00428 odom_pose_[1] += dr * sin( odom_pose_[2] );
00429 odom_pose_[2] += vel_angular_.z * step_time.Double();
00430
00431 odom_vel_[0] = dr / step_time.Double();
00432 odom_vel_[1] = 0.0;
00433 odom_vel_[2] = vel_angular_.z;
00434
00435 odom_.pose.pose.position.x = odom_pose_[0];
00436 odom_.pose.pose.position.y = odom_pose_[1];
00437 odom_.pose.pose.position.z = 0;
00438
00439 tf::Quaternion qt;
00440 qt.setEuler(0,0,odom_pose_[2]);
00441 odom_.pose.pose.orientation.x = qt.getX();
00442 odom_.pose.pose.orientation.y = qt.getY();
00443 odom_.pose.pose.orientation.z = qt.getZ();
00444 odom_.pose.pose.orientation.w = qt.getW();
00445
00446 odom_.pose.covariance[0] = 0.1;
00447 odom_.pose.covariance[7] = 0.1;
00448 odom_.pose.covariance[35] = 0.05;
00449 odom_.pose.covariance[14] = 1e6;
00450 odom_.pose.covariance[21] = 1e6;
00451 odom_.pose.covariance[28] = 1e6;
00452
00453 odom_.twist.twist.linear.x = odom_vel_[0];
00454 odom_.twist.twist.linear.y = 0;
00455 odom_.twist.twist.linear.z = 0;
00456 odom_.twist.twist.angular.x = 0;
00457 odom_.twist.twist.angular.y = 0;
00458 odom_.twist.twist.angular.z = odom_vel_[2];
00459 odom_pub_.publish(odom_);
00460
00461 if (publish_tf_)
00462 {
00463 odom_tf_.header = odom_.header;
00464 odom_tf_.child_frame_id = odom_.child_frame_id;
00465 odom_tf_.transform.translation.x = odom_.pose.pose.position.x;
00466 odom_tf_.transform.translation.y = odom_.pose.pose.position.y;
00467 odom_tf_.transform.translation.z = odom_.pose.pose.position.z;
00468 odom_tf_.transform.rotation = odom_.pose.pose.orientation;
00469 tf_broadcaster_.sendTransform(odom_tf_);
00470 }
00471
00472
00473
00474
00475 imu_msg_.header = joint_state_.header;
00476 math::Quaternion quat = imu_->GetOrientation();
00477 imu_msg_.orientation.x = quat.x;
00478 imu_msg_.orientation.y = quat.y;
00479 imu_msg_.orientation.z = quat.z;
00480 imu_msg_.orientation.w = quat.w;
00481 imu_msg_.orientation_covariance[0] = 1e6;
00482 imu_msg_.orientation_covariance[4] = 1e6;
00483 imu_msg_.orientation_covariance[8] = 0.05;
00484 imu_msg_.angular_velocity.x = vel_angular_.x;
00485 imu_msg_.angular_velocity.y = vel_angular_.y;
00486 imu_msg_.angular_velocity.z = vel_angular_.z;
00487 imu_msg_.angular_velocity_covariance[0] = 1e6;
00488 imu_msg_.angular_velocity_covariance[4] = 1e6;
00489 imu_msg_.angular_velocity_covariance[8] = 0.05;
00490 math::Vector3 lin_acc = imu_->GetLinearAcceleration();
00491 imu_msg_.linear_acceleration.x = lin_acc.x;
00492 imu_msg_.linear_acceleration.y = lin_acc.y;
00493 imu_msg_.linear_acceleration.z = lin_acc.z;
00494 imu_pub_.publish(imu_msg_);
00495
00496
00497
00498
00499
00500 if (((time_now - last_cmd_vel_time_).Double() > cmd_vel_timeout_) || !motors_enabled_)
00501 {
00502 wheel_speed_cmd_[LEFT] = 0.0;
00503 wheel_speed_cmd_[RIGHT] = 0.0;
00504 }
00505 joints_[LEFT]->SetVelocity(0, wheel_speed_cmd_[LEFT] / (wheel_diam_ / 2.0));
00506 joints_[RIGHT]->SetVelocity(0, wheel_speed_cmd_[RIGHT] / (wheel_diam_ / 2.0));
00507 joints_[LEFT]->SetMaxForce(0, torque_);
00508 joints_[RIGHT]->SetMaxForce(0, torque_);
00509
00510
00511
00512
00513
00514
00515 if ((cliff_detected_left_ == false) &&
00516 (cliff_sensor_left_->GetRange(0) >= cliff_detection_threshold_))
00517 {
00518 cliff_detected_left_ = true;
00519 cliff_event_.sensor = kobuki_msgs::CliffEvent::LEFT;
00520 cliff_event_.state = kobuki_msgs::CliffEvent::CLIFF;
00521
00522 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, cliff_sensor_left_->GetRange(0)));
00523 cliff_event_pub_.publish(cliff_event_);
00524 }
00525 else if ((cliff_detected_left_ == true) &&
00526 (cliff_sensor_left_->GetRange(0) < cliff_detection_threshold_))
00527 {
00528 cliff_detected_left_ = false;
00529 cliff_event_.sensor = kobuki_msgs::CliffEvent::LEFT;
00530 cliff_event_.state = kobuki_msgs::CliffEvent::FLOOR;
00531
00532 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, cliff_sensor_left_->GetRange(0)));
00533 cliff_event_pub_.publish(cliff_event_);
00534 }
00535
00536 if ((cliff_detected_center_ == false) &&
00537 (cliff_sensor_center_->GetRange(0) >= cliff_detection_threshold_))
00538 {
00539 cliff_detected_center_ = true;
00540 cliff_event_.sensor = kobuki_msgs::CliffEvent::CENTER;
00541 cliff_event_.state = kobuki_msgs::CliffEvent::CLIFF;
00542
00543 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, cliff_sensor_center_->GetRange(0)));
00544 cliff_event_pub_.publish(cliff_event_);
00545 }
00546 else if ((cliff_detected_center_ == true) &&
00547 (cliff_sensor_center_->GetRange(0) < cliff_detection_threshold_))
00548 {
00549 cliff_detected_center_ = false;
00550 cliff_event_.sensor = kobuki_msgs::CliffEvent::CENTER;
00551 cliff_event_.state = kobuki_msgs::CliffEvent::FLOOR;
00552
00553 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, cliff_sensor_center_->GetRange(0)));
00554 cliff_event_pub_.publish(cliff_event_);
00555 }
00556
00557 if ((cliff_detected_right_ == false) &&
00558 (cliff_sensor_right_->GetRange(0) >= cliff_detection_threshold_))
00559 {
00560 cliff_detected_right_ = true;
00561 cliff_event_.sensor = kobuki_msgs::CliffEvent::RIGHT;
00562 cliff_event_.state = kobuki_msgs::CliffEvent::CLIFF;
00563
00564 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, cliff_sensor_right_->GetRange(0)));
00565 cliff_event_pub_.publish(cliff_event_);
00566 }
00567 else if ((cliff_detected_right_ == true) &&
00568 (cliff_sensor_right_->GetRange(0) < cliff_detection_threshold_))
00569 {
00570 cliff_detected_right_ = false;
00571 cliff_event_.sensor = kobuki_msgs::CliffEvent::RIGHT;
00572 cliff_event_.state = kobuki_msgs::CliffEvent::FLOOR;
00573
00574 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, cliff_sensor_right_->GetRange(0)));
00575 cliff_event_pub_.publish(cliff_event_);
00576 }
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588 bumper_left_is_pressed_ = false;
00589 bumper_center_is_pressed_ = false;
00590 bumper_right_is_pressed_ = false;
00591
00592
00593 msgs::Contacts contacts;
00594 contacts = bumper_->GetContacts();
00595 math::Pose current_pose = model_->GetWorldPose();
00596 double robot_heading = current_pose.rot.GetYaw();
00597
00598 for (int i = 0; i < contacts.contact_size(); ++i)
00599 {
00600 double rel_contact_pos = contacts.contact(i).position(0).z() - current_pose.pos.z;
00601 if ((rel_contact_pos >= 0.015)
00602 && (rel_contact_pos <= 0.085))
00603 {
00604
00605
00606 double global_contact_angle = std::atan2(-contacts.contact(i).normal(0).y(), -contacts.contact(i).normal(0).x());
00607 double relative_contact_angle = global_contact_angle - robot_heading;
00608
00609 if ((relative_contact_angle <= (M_PI/2)) && (relative_contact_angle > (M_PI/6)))
00610 {
00611 bumper_left_is_pressed_ = true;
00612 }
00613 else if ((relative_contact_angle <= (M_PI/6)) && (relative_contact_angle >= (-M_PI/6)))
00614 {
00615 bumper_center_is_pressed_ = true;
00616 }
00617 else if ((relative_contact_angle < (-M_PI/6)) && (relative_contact_angle >= (-M_PI/2)))
00618 {
00619 bumper_right_is_pressed_ = true;
00620 }
00621 }
00622 }
00623
00624
00625 if (bumper_left_is_pressed_ && !bumper_left_was_pressed_)
00626 {
00627 bumper_left_was_pressed_ = true;
00628 bumper_event_.state = kobuki_msgs::BumperEvent::PRESSED;
00629 bumper_event_.bumper = kobuki_msgs::BumperEvent::LEFT;
00630 bumper_event_pub_.publish(bumper_event_);
00631 }
00632 else if (!bumper_left_is_pressed_ && bumper_left_was_pressed_)
00633 {
00634 bumper_left_was_pressed_ = false;
00635 bumper_event_.state = kobuki_msgs::BumperEvent::RELEASED;
00636 bumper_event_.bumper = kobuki_msgs::BumperEvent::LEFT;
00637 bumper_event_pub_.publish(bumper_event_);
00638 }
00639 if (bumper_center_is_pressed_ && !bumper_center_was_pressed_)
00640 {
00641 bumper_center_was_pressed_ = true;
00642 bumper_event_.state = kobuki_msgs::BumperEvent::PRESSED;
00643 bumper_event_.bumper = kobuki_msgs::BumperEvent::CENTER;
00644 bumper_event_pub_.publish(bumper_event_);
00645 }
00646 else if (!bumper_center_is_pressed_ && bumper_center_was_pressed_)
00647 {
00648 bumper_center_was_pressed_ = false;
00649 bumper_event_.state = kobuki_msgs::BumperEvent::RELEASED;
00650 bumper_event_.bumper = kobuki_msgs::BumperEvent::CENTER;
00651 bumper_event_pub_.publish(bumper_event_);
00652 }
00653 if (bumper_right_is_pressed_ && !bumper_right_was_pressed_)
00654 {
00655 bumper_right_was_pressed_ = true;
00656 bumper_event_.state = kobuki_msgs::BumperEvent::PRESSED;
00657 bumper_event_.bumper = kobuki_msgs::BumperEvent::RIGHT;
00658 bumper_event_pub_.publish(bumper_event_);
00659 }
00660 else if (!bumper_right_is_pressed_ && bumper_right_was_pressed_)
00661 {
00662 bumper_right_was_pressed_ = false;
00663 bumper_event_.state = kobuki_msgs::BumperEvent::RELEASED;
00664 bumper_event_.bumper = kobuki_msgs::BumperEvent::RIGHT;
00665 bumper_event_pub_.publish(bumper_event_);
00666 }
00667 }
00668
00669 void GazeboRosKobuki::spin()
00670 {
00671 while(ros::ok() && !shutdown_requested_)
00672 {
00673 ros::spinOnce();
00674 }
00675 }
00676
00677
00678 GZ_REGISTER_MODEL_PLUGIN(GazeboRosKobuki);
00679
00680 }