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 <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
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 wheel_speed_cmd_[LEFT] = 0.0;
00062 wheel_speed_cmd_[RIGHT] = 0.0;
00063
00064
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
00077 shutdown_requested_ = true;
00078
00079
00080
00081
00082
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
00094 std::string model_name = sdf->GetParent()->GetValueString("name");
00095 gzdbg << "Plugin model name: " << model_name << "\n";
00096 nh_ = ros::NodeHandle("");
00097
00098 nh_priv_ = ros::NodeHandle("/" + model_name);
00099 node_name_ = model_name;
00100
00101 world_ = parent->GetWorld();
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 motor_power_sub_ = nh_priv_.subscribe("commands/motor_power", 10, &GazeboRosKobuki::motorPowerCB, this);
00114 motors_enabled_ = true;
00115
00116
00117
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
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
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
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
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
00327
00328 ros::spinOnce();
00329
00330
00331
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
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
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
00359 double d1, d2;
00360 double dr, da;
00361 d1 = d2 = 0;
00362 dr = da = 0;
00363
00364 d1 = step_time.Double() * (wheel_diam_ / 2) * joints_[LEFT]->GetVelocity(0);
00365
00366 d2 = step_time.Double() * (wheel_diam_ / 2) * joints_[RIGHT]->GetVelocity(0);
00367
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
00384 odom_pose_[0] += dr * cos( odom_pose_[2] );
00385 odom_pose_[1] += dr * sin( odom_pose_[2] );
00386 odom_pose_[2] += da;
00387
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_);
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
00423
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
00437
00438
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
00466 if ((cliff_event_.state == kobuki_msgs::CliffEvent::CLIFF)
00467 && (cliff_event_.sensor != cliff_event_old_.sensor))
00468 {
00469
00470 cliff_event_.bottom = (int)(76123.0f * atan2(0.995f, max_floot_dist_));
00471 cliff_event_pub_.publish(cliff_event_);
00472 cliff_event_old_ = cliff_event_;
00473 }
00474
00475
00476
00477 msgs::Contacts contacts;
00478 contacts = bumper_->GetContacts();
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504 bumper_event_.state = 0;
00505 bumper_event_.bumper = 0;
00506
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))
00516 {
00517 math::Pose current_pose = model_->GetWorldPose();
00518 double robot_heading = current_pose.rot.GetYaw();
00519
00520
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
00534
00535
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
00544
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
00555
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
00566
00567 }
00568 }
00569 }
00570 }
00571
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
00590 GZ_REGISTER_MODEL_PLUGIN(GazeboRosKobuki);
00591
00592 }