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
00030 #include <ros/ros.h>
00031
00032 #include <actionlib/client/simple_action_client.h>
00033 #include <simple_arm_server/MoveArmAction.h>
00034 #include <arbotix_msgs/Relax.h>
00035
00036 #include <interactive_markers/interactive_marker_server.h>
00037 #include <interactive_markers/menu_handler.h>
00038
00039 #include <geometry_msgs/Twist.h>
00040 #include <geometry_msgs/Pose.h>
00041 #include <std_msgs/Float64.h>
00042
00043 #include <tf/tf.h>
00044 #include <tf/transform_listener.h>
00045
00046 #include <string.h>
00047
00048 #include <boost/foreach.hpp>
00049
00050 using namespace visualization_msgs;
00051 using namespace interactive_markers;
00052 using namespace std;
00053
00054 class ArmMarkerServer
00055 {
00056 private:
00057 ros::NodeHandle nh;
00058 actionlib::SimpleActionClient<simple_arm_server::MoveArmAction> client;
00059 interactive_markers::InteractiveMarkerServer server;
00060 tf::TransformListener tf_listener;
00061
00062 MenuHandler arm_menu_handler;
00063 map<std::string, MenuHandler> joint_menu_handlers;
00064
00065 bool immediate_commands;
00066 bool in_move;
00067
00068 ros::Timer arm_timer;
00069
00070
00071 vector<string> joints;
00072 vector<string> links;
00073 string tip_link;
00074 string root_link;
00075
00076
00077 double gripper_marker_offset_x;
00078 double gripper_marker_offset_y;
00079 double gripper_marker_offset_z;
00080
00081 double gripper_box_offset_x;
00082 double gripper_box_offset_y;
00083 double gripper_box_offset_z;
00084
00085
00086 double move_time;
00087
00088
00089 map<std::string, ros::Publisher> joint_command_publishers;
00090 map<std::string, ros::ServiceClient> joint_relax_clients;
00091
00092 public:
00093 ArmMarkerServer()
00094 : nh("~"), client("simple_move_arm", true), server("arm_marker_server"), tf_listener(nh), immediate_commands(true), in_move(false)
00095 {
00096
00097 nh.param<std::string>("root_link", root_link, "torso_link");
00098 nh.param<std::string>("tip_link", tip_link, "gripper_link");
00099 nh.param<double>("move_time", move_time, 2.0);
00100
00101
00102 XmlRpc::XmlRpcValue joint_list;
00103 nh.getParam("joints", joint_list);
00104 ROS_ASSERT(joint_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
00105
00106 for (int32_t i = 0; i < joint_list.size(); ++i)
00107 {
00108 ROS_ASSERT(joint_list[i].getType() == XmlRpc::XmlRpcValue::TypeString);
00109 joints.push_back(joint_list[i]);
00110 }
00111
00112
00113 XmlRpc::XmlRpcValue link_list;
00114 nh.getParam("links", link_list);
00115 ROS_ASSERT(link_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
00116
00117 for (int32_t i = 0; i < joint_list.size(); ++i)
00118 {
00119 ROS_ASSERT(link_list[i].getType() == XmlRpc::XmlRpcValue::TypeString);
00120 links.push_back(link_list[i]);
00121 }
00122
00123
00124 nh.param<double>("gripper/marker_offset/x", gripper_marker_offset_x, 0.02);
00125 nh.param<double>("gripper/marker_offset/y", gripper_marker_offset_y, 0.025);
00126 nh.param<double>("gripper/marker_offset/z", gripper_marker_offset_z, 0.0);
00127
00128 nh.param<double>("gripper/box_offset/x", gripper_box_offset_x, -0.017);
00129 nh.param<double>("gripper/box_offset/y", gripper_box_offset_y, -0.008);
00130 nh.param<double>("gripper/box_offset/z", gripper_box_offset_z, 0.0);
00131
00132 createArmMarker();
00133 createGripperMarker();
00134 createArmMenu();
00135
00136 createJointPublishers();
00137
00138 resetMarker();
00139
00140 ROS_INFO("[arm marker server] Initialized.");
00141 }
00142
00143 void createJointPublishers()
00144 {
00145 BOOST_FOREACH( std::string joint_name, joints )
00146 {
00147 joint_command_publishers[joint_name] = (nh.advertise<std_msgs::Float64>("/" + joint_name + "/command", 1, false));
00148 joint_relax_clients[joint_name] = (nh.serviceClient<arbotix_msgs::Relax>("/" + joint_name + "/relax"));
00149 }
00150
00151 }
00152
00153 void processArmFeedback(const InteractiveMarkerFeedbackConstPtr &feedback)
00154 {
00155 if (feedback->event_type == visualization_msgs::InteractiveMarkerFeedback::MOUSE_DOWN && feedback->marker_name == "arm_marker")
00156 {
00157 arm_timer.stop();
00158 }
00159 if (feedback->event_type != visualization_msgs::InteractiveMarkerFeedback::MOUSE_UP || feedback->marker_name != "arm_marker")
00160 return;
00161
00162 if (immediate_commands)
00163 {
00164 sendTrajectoryCommand(feedback);
00165 }
00166 }
00167
00168 void processJointFeedback(const InteractiveMarkerFeedbackConstPtr &feedback)
00169 {
00170 std_msgs::Float64 command;
00171 command.data = feedback->pose.orientation.y;
00172 joint_command_publishers[feedback->marker_name].publish(command);
00173 }
00174
00175 void changeMarkerColor(double r, double g, double b, bool set_pose=false, geometry_msgs::Pose pose = geometry_msgs::Pose())
00176 {
00177 InteractiveMarker int_marker;
00178 server.get("arm_marker", int_marker);
00179
00180 Marker *box_marker = &int_marker.controls[0].markers[0];
00181
00182 box_marker->color.r = r;
00183 box_marker->color.g = g;
00184 box_marker->color.b = b;
00185
00186 if (set_pose)
00187 int_marker.pose = pose;
00188
00189 server.insert(int_marker);
00190 server.applyChanges();
00191 }
00192
00193 void processCommand(const actionlib::SimpleClientGoalState& state,
00194 const simple_arm_server::MoveArmResultConstPtr& result,
00195 const InteractiveMarkerFeedbackConstPtr &feedback)
00196 {
00197 ROS_INFO("Finished in state [%s]", state.toString().c_str());
00198
00199
00200 if (state == actionlib::SimpleClientGoalState::SUCCEEDED)
00201 {
00202 changeMarkerColor(0, 1, 0, true, feedback->pose);
00203 ros::Duration(0.25).sleep();
00204 resetMarker();
00205
00206 }
00207 else
00208 {
00209 changeMarkerColor(1, 0, 0, true, feedback->pose);
00210 }
00211 }
00212
00213 bool sendTrajectoryCommand(const InteractiveMarkerFeedbackConstPtr &feedback)
00214 {
00215 simple_arm_server::MoveArmGoal goal;
00216 simple_arm_server::ArmAction action;
00217
00218 goal.header.frame_id = root_link;
00219
00220 geometry_msgs::Pose pose;
00221 getTransformedPose(feedback->header.frame_id, feedback->pose, root_link, pose, feedback->header.stamp);
00222
00223 action.goal.orientation = pose.orientation;
00224 action.goal.position = pose.position;
00225 action.move_time = ros::Duration(move_time);
00226 goal.motions.push_back(action);
00227
00228 client.sendGoal(goal, boost::bind(&ArmMarkerServer::processCommand, this, _1, _2, feedback));
00229 changeMarkerColor(0, 0, 1, true, feedback->pose);
00230
00231 return true;
00232 }
00233
00234 bool sendGripperCommand(const InteractiveMarkerFeedbackConstPtr &feedback)
00235 {
00236 simple_arm_server::MoveArmGoal goal;
00237 simple_arm_server::ArmAction action;
00238
00239 goal.header.frame_id = tip_link;
00240 action.type = simple_arm_server::ArmAction::MOVE_GRIPPER;
00241 action.command = feedback->pose.position.y;
00242 goal.motions.push_back(action);
00243
00244 client.sendGoal(goal);
00245
00246
00247
00248
00249
00250
00251 return true;
00252 }
00253
00254 void getTransformedPose(const string& source_frame, const geometry_msgs::Pose& source_pose,
00255 const string& target_frame, geometry_msgs::Pose& target_pose,
00256 const ros::Time& time)
00257 {
00258 tf::Pose bt_source_pose;
00259
00260 tf::poseMsgToTF(source_pose, bt_source_pose);
00261
00262 tf::Stamped<tf::Pose> posein(bt_source_pose, time, source_frame);
00263 tf::Stamped<tf::Pose> poseout;
00264
00265 try
00266 {
00267 ros::Duration timeout(10.0);
00268
00269
00270 tf_listener.waitForTransform(target_frame, source_frame,
00271 time, timeout);
00272 tf_listener.transformPose(target_frame, posein, poseout);
00273
00274
00275 }
00276 catch (tf::TransformException& ex) {
00277 ROS_WARN("[arm interactive markers] TF exception:\n%s", ex.what());
00278 return;
00279 }
00280
00281 tf::poseTFToMsg(poseout, target_pose);
00282 }
00283
00284 void resetMarker()
00285 {
00286 geometry_msgs::Pose arm_pose;
00287 geometry_msgs::Pose blank_pose;
00288 blank_pose.orientation.w = 1;
00289
00290 getTransformedPose(tip_link, blank_pose, root_link, arm_pose, ros::Time(0));
00291
00292 server.setPose("arm_marker", arm_pose);
00293 server.applyChanges();
00294 }
00295
00296 void createArmMarker()
00297 {
00298
00299 InteractiveMarker int_marker;
00300 int_marker.header.frame_id = root_link;
00301 int_marker.name = "arm_marker";
00302 int_marker.scale = 0.1;
00303
00304 Marker marker;
00305
00306 marker.type = Marker::CUBE;
00307 marker.scale.x = 0.03;
00308 marker.scale.y = 0.03;
00309 marker.scale.z = 0.03;
00310 marker.color.r = 0.0;
00311 marker.color.g = 1.0;
00312 marker.color.b = 0.0;
00313 marker.color.a = .7;
00314
00315 InteractiveMarkerControl box_control;
00316 box_control.always_visible = true;
00317 box_control.interaction_mode = InteractiveMarkerControl::BUTTON;
00318 box_control.markers.push_back( marker );
00319 int_marker.controls.push_back( box_control );
00320
00321 InteractiveMarkerControl control;
00322
00323 control.orientation.w = 1;
00324 control.orientation.x = 1;
00325 control.orientation.y = 0;
00326 control.orientation.z = 0;
00327 control.name = "rotate_x";
00328 control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
00329 int_marker.controls.push_back(control);
00330 control.name = "move_x";
00331 control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
00332 int_marker.controls.push_back(control);
00333
00334 control.orientation.w = 1;
00335 control.orientation.x = 0;
00336 control.orientation.y = 1;
00337 control.orientation.z = 0;
00338 control.name = "rotate_z";
00339 control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
00340 int_marker.controls.push_back(control);
00341 control.name = "move_z";
00342 control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
00343 int_marker.controls.push_back(control);
00344
00345 control.orientation.w = 1;
00346 control.orientation.x = 0;
00347 control.orientation.y = 0;
00348 control.orientation.z = 1;
00349 control.name = "rotate_y";
00350 control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
00351 int_marker.controls.push_back(control);
00352 control.name = "move_y";
00353 control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
00354 int_marker.controls.push_back(control);
00355
00356
00357 server.insert(int_marker, boost::bind( &ArmMarkerServer::processArmFeedback, this, _1 ));
00358
00359 server.applyChanges();
00360 }
00361
00362 void createGripperMarker()
00363 {
00364
00365 InteractiveMarker int_marker;
00366 int_marker.header.frame_id = tip_link;
00367 int_marker.name = "gripper_marker";
00368 int_marker.scale = 0.075;
00369
00370 int_marker.pose.position.x = gripper_marker_offset_x;
00371 int_marker.pose.position.y = gripper_marker_offset_y;
00372 int_marker.pose.position.z = gripper_marker_offset_z;
00373
00374 Marker marker;
00375
00376 marker.type = Marker::CUBE;
00377 marker.scale.x = 0.05;
00378 marker.scale.y = 0.005;
00379 marker.scale.z = 0.05;
00380 marker.color.r = 0.0;
00381 marker.color.g = 1.0;
00382 marker.color.b = 0.0;
00383 marker.color.a = .7;
00384
00385 marker.pose.position.x = gripper_box_offset_x;
00386 marker.pose.position.y = gripper_box_offset_y;
00387 marker.pose.position.z = gripper_box_offset_z;
00388
00389 InteractiveMarkerControl box_control;
00390 box_control.always_visible = true;
00391 box_control.interaction_mode = InteractiveMarkerControl::BUTTON;
00392 box_control.markers.push_back( marker );
00393 int_marker.controls.push_back( box_control );
00394
00395 InteractiveMarkerControl control;
00396
00397 control.orientation.w = 1;
00398 control.orientation.x = 0;
00399 control.orientation.y = 0;
00400 control.orientation.z = 1;
00401 control.name = "move_z";
00402 control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
00403 int_marker.controls.push_back(control);
00404
00405 server.insert(int_marker, boost::bind( &ArmMarkerServer::sendGripperCommand, this, _1 ));
00406
00407 server.applyChanges();
00408 }
00409
00410 void createJointMarkers()
00411 {
00412 for (unsigned int i = 0; i < joints.size() && i < links.size(); i++)
00413 {
00414 createJointMarker(joints[i], links[i]);
00415 }
00416 }
00417
00418 void createJointMarker(const string joint_name, const string link_name)
00419 {
00420 InteractiveMarker int_marker;
00421 int_marker.header.frame_id = link_name;
00422 int_marker.name = joint_name;
00423 int_marker.scale = 0.05;
00424
00425 InteractiveMarkerControl control;
00426
00427 control.orientation.w = 1;
00428 control.orientation.x = 0;
00429 control.orientation.y = 0;
00430 control.orientation.z = 1;
00431 control.name = "rotate_z";
00432 control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
00433 int_marker.controls.push_back(control);
00434
00435 server.insert(int_marker, boost::bind( &ArmMarkerServer::processJointFeedback, this, _1 ));
00436
00437 server.applyChanges();
00438 }
00439
00440 void createArmMenu()
00441 {
00442 arm_menu_handler = MenuHandler();
00443 arm_menu_handler.insert("Send command", boost::bind(&ArmMarkerServer::sendCommandCb, this, _1));
00444 arm_menu_handler.setCheckState(
00445 arm_menu_handler.insert("Send command immediately", boost::bind(&ArmMarkerServer::immediateCb, this, _1)), MenuHandler::CHECKED );
00446 arm_menu_handler.insert("Reset marker", boost::bind(&ArmMarkerServer::resetPoseCb, this, _1));
00447
00448 MenuHandler::EntryHandle entry = arm_menu_handler.insert("Relax joints");
00449 arm_menu_handler.insert( entry, "All", boost::bind(&ArmMarkerServer::relaxAllCb, this, _1));
00450 BOOST_FOREACH(string joint_name, joints)
00451 {
00452 arm_menu_handler.insert( entry, joint_name, boost::bind(&ArmMarkerServer::relaxCb, this, joint_name, _1) );
00453 }
00454
00455 arm_menu_handler.insert("Switch to Joint Control", boost::bind(&ArmMarkerServer::switchToJointControlCb, this, _1));
00456
00457 arm_menu_handler.apply( server, "arm_marker" );
00458 server.applyChanges();
00459 }
00460
00461 void createJointMenus()
00462 {
00463 BOOST_FOREACH(string joint_name, joints)
00464 {
00465 createJointMenu(joint_name);
00466 }
00467 }
00468
00469 void createJointMenu(const string joint_name)
00470 {
00471 MenuHandler joint_handler;
00472 joint_handler.insert("Relax all", boost::bind(&ArmMarkerServer::relaxAllCb, this, _1));
00473 joint_handler.insert("Relax this joint", boost::bind(&ArmMarkerServer::relaxCb, this, joint_name, _1));
00474 joint_handler.insert("Switch to Trajectory Control", boost::bind(&ArmMarkerServer::switchToArmControlCb, this, _1));
00475
00476 joint_menu_handlers[joint_name] = joint_handler;
00477
00478 joint_menu_handlers[joint_name].apply( server, joint_name );
00479 server.applyChanges();
00480 }
00481
00482 void sendCommandCb(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00483 {
00484 sendTrajectoryCommand(feedback);
00485 }
00486
00487 void relaxAllCb(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00488 {
00489 BOOST_FOREACH( std::string joint_name, joints )
00490 {
00491 relaxCb(joint_name, feedback);
00492 }
00493 }
00494
00495 void relaxCb(const std::string joint_name, const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00496 {
00497 arbotix_msgs::Relax srv;
00498 joint_relax_clients[joint_name].call(srv);
00499 }
00500
00501 void immediateCb(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00502 {
00503 MenuHandler::EntryHandle handle = feedback->menu_entry_id;
00504 MenuHandler::CheckState state;
00505 arm_menu_handler.getCheckState( handle, state );
00506
00507 if ( state == MenuHandler::CHECKED )
00508 {
00509 arm_menu_handler.setCheckState( handle, MenuHandler::UNCHECKED );
00510 ROS_INFO("Switching to cached commands");
00511 immediate_commands = false;
00512 }
00513 else
00514 {
00515 arm_menu_handler.setCheckState( handle, MenuHandler::CHECKED );
00516 ROS_INFO("Switching to immediate comands");
00517 immediate_commands = true;
00518 }
00519 arm_menu_handler.reApply(server);
00520
00521 server.applyChanges();
00522 }
00523
00524 void resetPoseCb(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00525 {
00526 resetMarker();
00527 arm_timer.start();
00528 }
00529
00530 void switchToJointControlCb(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00531 {
00532 server.clear();
00533 server.applyChanges();
00534
00535 createJointMarkers();
00536 createJointMenus();
00537 }
00538
00539 void switchToArmControlCb(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
00540 {
00541 server.clear();
00542 server.applyChanges();
00543
00544 createArmMarker();
00545 createGripperMarker();
00546
00547
00548 arm_menu_handler.reApply(server);
00549
00550 resetMarker();
00551 }
00552 };
00553
00554 int main(int argc, char** argv)
00555 {
00556 ros::init(argc, argv, "turtlebot_arm_marker_server");
00557 ArmMarkerServer turtleserver;
00558
00559 ros::spin();
00560 }