diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a09237d75a274bc0d36e0afbb307deea3640b80..69b371c990bd02ea4040ae38c1b2a842f4aecfc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,8 +43,6 @@ message("psource " ${PROTO_SRC}) message("pheaders" ${PROTO_HDRS}) find_package(PkgConfig REQUIRED) -pkg_check_modules(JSONCPP jsoncpp) -message(${JSONCPP_LIBRARIES}) add_subdirectory(lib/paho.mqtt.c) @@ -90,36 +88,32 @@ include_directories( add_dependencies(paho-mqttpp3 paho-mqtt3c) add_library(TrajectoryUtil src/util/TrajectoryUtil.cpp src/util/TrajectoryUtil.h) +add_library(MqttUtil src/util/MqttUtil.cpp src/util/MqttUtil.h) # Specify libraries to link a library or executable target against target_link_libraries(TrajectoryUtil ${catkin_LIBRARIES}) -add_executable(robot_control_node src/robot_control_node.cpp) -add_executable(SafetyAwarePlanner src/SafetyAwarePlanner.cpp src/SafetyEnvironmentCreator.cpp) -add_executable(SampleConstraintPlanner src/samples/SampleConstraintPlanner.cpp) -add_executable(SampleTimedCartesianPlanner src/samples/SampleTimedCartesianPlanner.cpp) -add_executable(RobotStateProvider src/RobotStateProvider.cpp src/mem_persistence.cpp ${PROTO_SRCS} ${PROTO_HDRS}) +add_executable(RobotStateProvider src/RobotStateProvider.cpp ${PROTO_SRCS} ${PROTO_HDRS}) add_executable(TimedPlanner src/TimedPlanner.cpp) add_executable(MqttToRosNode src/MqttToRosNode.cpp ${PROTO_SRCS} ${PROTO_HDRS}) add_executable(MqttRosConnectionTestNode src/MqttRosConnectionTestNode.cpp ${PROTO_SRCS} ${PROTO_HDRS}) -target_link_libraries(robot_control_node ${catkin_LIBRARIES} boost_filesystem ${JSONCPP_LIBRARIES}) -target_link_libraries(SafetyAwarePlanner ${catkin_LIBRARIES}) -target_link_libraries(SampleConstraintPlanner ${catkin_LIBRARIES}) -target_link_libraries(SampleTimedCartesianPlanner ${catkin_LIBRARIES}) target_link_libraries(RobotStateProvider LINK_PUBLIC + MqttUtil ${catkin_LIBRARIES} paho-mqttpp3 ${Protobuf_LIBRARIES} ) target_link_libraries(MqttToRosNode LINK_PUBLIC + MqttUtil ${catkin_LIBRARIES} paho-mqttpp3 ${Protobuf_LIBRARIES} ) target_link_libraries(MqttRosConnectionTestNode LINK_PUBLIC + MqttUtil ${catkin_LIBRARIES} paho-mqttpp3 ${Protobuf_LIBRARIES} ) -target_link_libraries(TimedPlanner ${catkin_LIBRARIES} TrajectoryUtil) \ No newline at end of file +target_link_libraries(TimedPlanner ${catkin_LIBRARIES} TrajectoryUtil) diff --git a/launch/simulation_rosrag.launch b/launch/simulation_rosrag.launch index b662c1a7be4a3ab036a0a64b4f1252ece5cdf1a8..120adc7cb41fa1c6d96a99adb1c6ee0fc13cadb0 100644 --- a/launch/simulation_rosrag.launch +++ b/launch/simulation_rosrag.launch @@ -1,7 +1,5 @@ <launch> <include file="$(find panda_simulation)/launch/simulation.launch"/> - <include file="$(find panda_moveit_config)/launch/moveit_rviz.launch" /> - <node name="rqt_console" pkg="rqt_console" type="rqt_console" /> <node name="TimedPlanner" pkg="panda_mqtt_connector" type="TimedPlanner" respawn="false" output="screen"/> <node name="MqttToRosNode" pkg="panda_mqtt_connector" type="MqttToRosNode" respawn="false" output="screen"/> diff --git a/launch/simulation_rosrag_test.launch b/launch/simulation_rosrag_test.launch index c1b2c2cbf92f960ab8405dc7ac7fb1dc11f1a3f5..c489c2db372a223e3d4e938978e71a821a40a3b0 100644 --- a/launch/simulation_rosrag_test.launch +++ b/launch/simulation_rosrag_test.launch @@ -1,7 +1,5 @@ <launch> <include file="$(find panda_simulation)/launch/simulation.launch"/> - <include file="$(find panda_moveit_config)/launch/moveit_rviz.launch" /> - <node name="rqt_console" pkg="rqt_console" type="rqt_console" /> <node name="TimedPlanner" pkg="panda_mqtt_connector" type="TimedPlanner" respawn="false" output="screen"/> <node name="MqttToRosNode" pkg="panda_mqtt_connector" type="MqttToRosNode" respawn="false" output="screen"/> diff --git a/launch/simulation_test_test.launch b/launch/simulation_test_test.launch new file mode 100644 index 0000000000000000000000000000000000000000..69da94afc9379fe1a0357157523d5863a707e771 --- /dev/null +++ b/launch/simulation_test_test.launch @@ -0,0 +1,3 @@ +<launch> + <node name="MqttRosConnectionTestNode" pkg="panda_mqtt_connector" type="MqttRosConnectionTestNode" respawn="false" output="screen"/> +</launch> diff --git a/package.xml b/package.xml index 8a2ba17707df0b9b8401228bcabed00090455024..7aa73dd2f1ba748fa553ffeefe129d4452321dbf 100644 --- a/package.xml +++ b/package.xml @@ -33,7 +33,6 @@ <depend>std_msgs</depend> <depend>tf</depend> <depend>xacro</depend> - <depend>libjsoncpp-dev</depend> <depend>moveit_simple_controller_manager</depend> <!-- CUSTOM --> @@ -48,6 +47,5 @@ <!-- The export tag contains other, unspecified, tags --> <export> - <controller_interface plugin="${prefix}/controller_plugins.xml" /> </export> </package> diff --git a/src/MqttRosConnectionTestNode.cpp b/src/MqttRosConnectionTestNode.cpp index 25ee0a61819d0f665f57cf89af9a1b39d525690b..f5a8798976b4a5bd1d5acfa2f4c0ce247f0844d4 100644 --- a/src/MqttRosConnectionTestNode.cpp +++ b/src/MqttRosConnectionTestNode.cpp @@ -1,17 +1,18 @@ // // Created by sebastian on 31.03.20. // +#include "dataconfig.pb.h" +#include "robotconfig.pb.h" +#include "trajectory.pb.h" + #include "ros/ros.h" #include <gazebo_msgs/LinkStates.h> + +#include "util/MqttUtil.h" + #include <mqtt/client.h> -#include "string.h" -#include "robotconfig.pb.h" -#include "dataconfig.pb.h" -#include "mem_persistence.cpp" -#include "trajectory.pb.h" using namespace std; -using namespace std::chrono; /* * mqtt-topics for all links @@ -21,224 +22,126 @@ std::string topics[11] = {"panda_ground", "panda_link_0", "panda_link_1", "panda "panda_link_3", "panda_link_4", "panda_link_5", "panda_link_6", "panda_link_7", "panda_link_8", "panda_link_9"}; -const string SERVER_ADDRESS { "tcp://localhost:1883" }; -const string CLIENT_ID { "ros_mqtt_tester" }; - -bool mqttSetup = false; -bool isInitialized = false; - -const int QOS = 1; - -mem_persistence persist; -mqtt::client client("tcp://localhost:1883", "robot_state_provider_mqtt_test", &persist); +const string CLIENT_ID{"ros_mqtt_tester"}; -void setupMqtt() { +MqttUtil mqttUtil(CLIENT_ID); - if (!mqttSetup) { - std::cout << "MQTT: Initializing." << std::endl; +void testTrajectoryUpdate(ros::NodeHandle n) { - mqtt::connect_options connOpts; - connOpts.set_keep_alive_interval(20); - connOpts.set_clean_session(true); - std::cout << "MQTT: Initialized." << std::endl; + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", ">>>>>>> STARTING TRAJECTORY UPDATE TEST <<<<<<<"); - std::cout << "MQTT: Connecting." << std::endl; - client.connect(connOpts); - std::cout << "MQTT: Connected." << std::endl; - mqttSetup = true; - } -} - -bool try_reconnect(mqtt::client& cli) -{ - constexpr int N_ATTEMPT = 30; - - for (int i=0; i<N_ATTEMPT && !cli.is_connected(); ++i) { - try { - cli.reconnect(); - return true; - } - catch (const mqtt::exception&) { - this_thread::sleep_for(seconds(1)); - } - } - return false; -} - -void testTrajectoryUpdate(ros::NodeHandle n){ + plan::Trajectory traj; - std::cout << ">>>>>>>>>>>> STARTING TRAJECTORY UPDATE TEST <<<<<<<<<<<<<" << std::endl; - setupMqtt(); + plan::Trajectory_Position pos1; + pos1.set_x(0.6); + pos1.set_y(0.0); + pos1.set_z(0.6); - plan::Trajectory traj; + traj.add_pos()->CopyFrom(pos1); - plan::Trajectory_Position pos1; - pos1.set_x(0.6); - pos1.set_y(0.0); - pos1.set_z(0.6); + plan::Trajectory_Position pos2; + pos2.set_x(-0.6); + pos2.set_y(0.0); + pos2.set_z(0.6); - traj.add_pos()->CopyFrom(pos1); + traj.add_pos()->CopyFrom(pos2); - plan::Trajectory_Position pos2; - pos2.set_x(-0.6); - pos2.set_y(0.0); - pos2.set_z(0.6); + std::string mqtt_msg; + traj.SerializeToString(&mqtt_msg); - traj.add_pos()->CopyFrom(pos2); + auto pubmsg = mqtt::make_message("trajectoryconfig", mqtt_msg); + mqttUtil.getClient().publish(pubmsg); - std::string mqtt_msg; - traj.SerializeToString(&mqtt_msg); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", ">>>>>>>>>>>> CHECKING SERVER <<<<<<<<<<<<<"); - auto pubmsg = mqtt::make_message("trajectoryconfig", mqtt_msg); - pubmsg->set_qos(QOS); - client.publish(pubmsg); + std::vector<double> x_pos; + std::vector<double> y_pos; + std::vector<double> z_pos; - std::cout << ">>>>>>>>>>>> CHECKING SERVER <<<<<<<<<<<<<" << std::endl; + ros::Duration(5.0).sleep(); - std::vector<double> x_pos; - std::vector<double> y_pos; - std::vector<double> z_pos; + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "x configured: " << n.getParam("trajectory_pos_x", x_pos)); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "y configured: " << n.getParam("trajectory_pos_y", y_pos)); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "z configured: " << n.getParam("trajectory_pos_z", z_pos)); - ros::Duration(5.0).sleep(); - - std::cout << "x configured: " << n.getParam("trajectory_pos_x", x_pos) << std::endl; - std::cout << "y configured: " << n.getParam("trajectory_pos_y", y_pos) << std::endl; - std::cout << "z configured: " << n.getParam("trajectory_pos_z", z_pos) << std::endl; - - for(int i = 0; i < x_pos.size(); i++) - { - std::cout << "X POS: " << x_pos.at(i) << std::endl; - std::cout << "Y POS: " << y_pos.at(i) << std::endl; - std::cout << "Z POS: " << z_pos.at(i) << std::endl; - } + for (int i = 0; i < x_pos.size(); i++) { + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "X POS: " << x_pos.at(i)); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "Y POS: " << y_pos.at(i)); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "Z POS: " << z_pos.at(i)); + } } -void testPlanningModeChange(ros::NodeHandle n){ +void testPlanningModeChange(ros::NodeHandle n) { - std::cout << ">>>>>>>>>>>> STARTING PLANNING TEST <<<<<<<<<<<<<" << std::endl; - setupMqtt(); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", ">>>>>>> STARTING PLANNING MODE CHANGE TEST <<<<<<<"); - config::RobotConfig rc; + config::RobotConfig rc; - rc.set_speed(1.0); - rc.set_planningmode(config::RobotConfig_PlanningMode_FLUID); + rc.set_speed(1.0); + rc.set_planningmode(config::RobotConfig_PlanningMode_FLUID); - std::string mqtt_msg; - rc.SerializeToString(&mqtt_msg); + std::string mqtt_msg; + rc.SerializeToString(&mqtt_msg); - auto pubmsg = mqtt::make_message("robotconfig", mqtt_msg); - pubmsg->set_qos(QOS); - client.publish(pubmsg); + auto pubmsg = mqtt::make_message("robotconfig", mqtt_msg); + mqttUtil.getClient().publish(pubmsg); } void testConfig(ros::NodeHandle n) { - std::cout << ">>>>>>>>>>>> STARTING CONFIG TEST <<<<<<<<<<<<<" << std::endl; - setupMqtt(); + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", ">>>>>>> STARTING CONFIG UPDATE TEST <<<<<<<"); - config::DataConfig dc; + config::DataConfig dc; - dc.set_enableposition(true); - dc.set_enableorientation(true); - dc.set_enabletwistangular(true); - dc.set_enabletwistlinear(true); - dc.set_publishrate(1000); + dc.set_enableposition(true); + dc.set_enableorientation(true); + dc.set_enabletwistangular(true); + dc.set_enabletwistlinear(true); + dc.set_publishrate(1000); - std::string mqtt_msg; - dc.SerializeToString(&mqtt_msg); + std::string mqtt_msg; + dc.SerializeToString(&mqtt_msg); - auto pubmsg = mqtt::make_message("dataconfig", mqtt_msg); - pubmsg->set_qos(QOS); - client.publish(pubmsg); + auto pubmsg = mqtt::make_message("dataconfig", mqtt_msg); + mqttUtil.getClient().publish(pubmsg); } -void receiveMqttMessages(ros::NodeHandle n) -{ - mqtt::connect_options connOpts; - mqtt::client cli(SERVER_ADDRESS, CLIENT_ID); - - connOpts.set_keep_alive_interval(20); - connOpts.set_clean_session(true); - try { - ROS_INFO_STREAM("TEST Connecting to the MQTT server."); - mqtt::connect_response rsp = cli.connect(connOpts); - ROS_INFO_STREAM("TEST Connected to the MQTT server."); - - if (!rsp.is_session_present()) { - ROS_INFO_STREAM("TEST Subscribing to topics."); - cli.subscribe("configtest", 1); - cli.subscribe("modetest", 1); - cli.subscribe("trajectorytest", 1); - ROS_INFO_STREAM("TEST Subscribed to topics."); - }else { - ROS_WARN_STREAM("TEST Session already present. Skipping subscribe."); - } - - // Consume messages - while (true) { - - auto msg = cli.consume_message(); - - if (!msg) { - if (!cli.is_connected()) { - ROS_ERROR_STREAM("TEST Lost connection. Attempting reconnect"); - if (try_reconnect(cli)) { - cli.subscribe("nodetest", 1); - ROS_INFO_STREAM("TEST Reconnected"); - continue; - } - else { - ROS_ERROR_STREAM("TEST Reconnect failed."); - } - } - else { - ROS_ERROR_STREAM("TEST An error occurred retrieving messages."); - } - break; - } - - if (msg->get_topic() == "configtest") - { - testConfig(n); - } - - if (msg->get_topic() == "modetest") - { - testPlanningModeChange(n); - } - - if (msg->get_topic() == "trajectorytest") - { - testTrajectoryUpdate(n); - } - } - } - catch (const mqtt::exception& exc) { - ROS_ERROR_STREAM("TEST: " << exc.what()); - cli.disconnect(); - return; +void receiveMqttMessages(ros::NodeHandle n) { + + if (mqttUtil.ensureConnection()) { + ROS_INFO_STREAM_NAMED("MqttRosConnectionTestNode", "Waiting 500ms for message..."); + mqtt::const_message_ptr *msg = new mqtt::const_message_ptr; + if (mqttUtil.getClient().try_consume_message_for(msg, std::chrono::milliseconds (500))) { + if (msg->get()->get_topic() == "test_config") { + testConfig(n); + } else if (msg->get()->get_topic() == "test_mode_change") { + testPlanningModeChange(n); + } else if (msg->get()->get_topic() == "test_trajectory_update") { + testTrajectoryUpdate(n); + } } - cli.disconnect(); + } else { + ROS_ERROR_STREAM_NAMED("MqttRosConnectionTestNode", "Not connected! Unable to listen to messages."); + } } int main(int argc, char **argv) { - ros::init(argc, argv, "robot_state_provider_test"); - ros::NodeHandle n; - n.getParam("ready", isInitialized); + ros::init(argc, argv, "MqttRosConnectionTestNode"); + ros::NodeHandle n; - while (ros::ok()) { + ROS_INFO_NAMED("MqttRosConnectionTestNode", "Setting up MQTT."); - // make sure the robot is initialized - while (!isInitialized) { - n.getParam("tud_planner_ready", isInitialized); - } + mqttUtil.addTopic("test_config"); + mqttUtil.addTopic("test_mode_change"); + mqttUtil.addTopic("test_trajectory_update"); - receiveMqttMessages(n); - ros::spin(); - } + mqttUtil.connect(); + + while (ros::ok()) { + receiveMqttMessages(n); + ros::spinOnce(); + } - // disconnect from mqtt - client.disconnect(); - return 0; + return 0; } \ No newline at end of file diff --git a/src/MqttToRosNode.cpp b/src/MqttToRosNode.cpp index 8bd463c607d0b0de1862e1c1e02aaffab134d339..01e47bd70cca3d756aadd5e3df479f62b207d268 100644 --- a/src/MqttToRosNode.cpp +++ b/src/MqttToRosNode.cpp @@ -1,208 +1,135 @@ +#include "mqtt/client.h" +#include <chrono> #include <iostream> #include <string> -#include <cstring> #include <thread> -#include <chrono> -#include "mqtt/client.h" #include "ros/ros.h" -#include "robotconfig.pb.h" +#include "util/MqttUtil.h" + #include "dataconfig.pb.h" +#include "robotconfig.pb.h" #include "trajectory.pb.h" using namespace std; using namespace std::chrono; -const string SERVER_ADDRESS { "tcp://localhost:1883" }; -const string CLIENT_ID { "ros_mqtt_consumer" }; - -// Simple function to manually reconnect a client. -bool try_reconnect(mqtt::client& cli) -{ - constexpr int N_ATTEMPT = 30; - - for (int i=0; i<N_ATTEMPT && !cli.is_connected(); ++i) { - try { - cli.reconnect(); - return true; - } - catch (const mqtt::exception&) { - this_thread::sleep_for(seconds(1)); - } - } - return false; -} +const string CLIENT_ID{"mqtt_to_ros"}; -void handleRobotConfig(config::RobotConfig robotConfig, ros::NodeHandle n) -{ - std::cout << "Retrieved new target-speed: " << robotConfig.speed() << std::endl; - n.setParam("robot_speed_factor", robotConfig.speed()); - - std::cout << "Retrieved new loop-mode: " << robotConfig.looptrajectory() << std::endl; - n.setParam("loop_trajectory", robotConfig.looptrajectory()); - - std::cout << "Retrieved new planning-mode: " << std::endl; - switch (robotConfig.planningmode()) - { - case config::RobotConfig_PlanningMode_FLUID: - n.setParam("robot_planning_mode", "fluid_path"); - std::cout << "Planning-mode: fluid" << std::endl; - break; - case config::RobotConfig_PlanningMode_CARTESIAN: - n.setParam("robot_planning_mode", "cartesian_path"); - std::cout << "Planning-mode: cartesian" << std::endl; - break; - } +MqttUtil mqttUtil(CLIENT_ID); + +void handleRobotConfig(config::RobotConfig robotConfig, ros::NodeHandle n) { + std::cout << "Retrieved new target-speed: " << robotConfig.speed() << std::endl; + n.setParam("robot_speed_factor", robotConfig.speed()); + + std::cout << "Retrieved new loop-mode: " << robotConfig.looptrajectory() << std::endl; + n.setParam("loop_trajectory", robotConfig.looptrajectory()); + + std::cout << "Retrieved new planning-mode: " << std::endl; + switch (robotConfig.planningmode()) { + case config::RobotConfig_PlanningMode_FLUID: + n.setParam("robot_planning_mode", "fluid_path"); + std::cout << "Planning-mode: fluid" << std::endl; + break; + case config::RobotConfig_PlanningMode_CARTESIAN: + n.setParam("robot_planning_mode", "cartesian_path"); + std::cout << "Planning-mode: cartesian" << std::endl; + break; + } } -void handleNewTrajectory(plan::Trajectory trajectory, ros::NodeHandle n) -{ - ROS_INFO("Received new trajectory"); - - /*XmlRpc::XmlRpcValue::ValueArray x_rpc_array; - XmlRpc::XmlRpcValue::ValueArray y_rpc_array; - XmlRpc::XmlRpcValue::ValueArray z_rpc_array; - - // build xml-rpc-lists for the parameter server - for(int i = 0; i < trajectory.pos().size(); i++) - { - x_rpc_array.push_back(XmlRpc::XmlRpcValue(trajectory.pos().Get(i).x())); - y_rpc_array.push_back(XmlRpc::XmlRpcValue(trajectory.pos().Get(i).y())); - z_rpc_array.push_back(XmlRpc::XmlRpcValue(trajectory.pos().Get(i).z())); - }*/ - - std::vector<double> x_values; - std::vector<double> y_values; - std::vector<double> z_values; - - for(int i = 0; i < trajectory.pos().size(); i++) - { - x_values.push_back(trajectory.pos().Get(i).x()); - y_values.push_back(trajectory.pos().Get(i).y()); - z_values.push_back(trajectory.pos().Get(i).z()); - } +void handleNewTrajectory(plan::Trajectory trajectory, ros::NodeHandle n) { + ROS_INFO("Received new trajectory"); + + std::vector<double> x_values; + std::vector<double> y_values; + std::vector<double> z_values; - n.deleteParam("trajectory_pos_x"); - n.deleteParam("trajectory_pos_y"); - n.deleteParam("trajectory_pos_z"); + for (int i = 0; i < trajectory.pos().size(); i++) { + x_values.push_back(trajectory.pos().Get(i).x()); + y_values.push_back(trajectory.pos().Get(i).y()); + z_values.push_back(trajectory.pos().Get(i).z()); + } - n.setParam("trajectory_pos_x", x_values); - n.setParam("trajectory_pos_y", y_values); - n.setParam("trajectory_pos_z", z_values); + n.deleteParam("trajectory_pos_x"); + n.deleteParam("trajectory_pos_y"); + n.deleteParam("trajectory_pos_z"); - n.setParam("new_trajectory_available", true); + n.setParam("trajectory_pos_x", x_values); + n.setParam("trajectory_pos_y", y_values); + n.setParam("trajectory_pos_z", z_values); + + n.setParam("new_trajectory_available", true); } -void handleDataConfig(config::DataConfig dataConfig, ros::NodeHandle n) -{ - std::cout << "Retrieved new data-config: -- publish-rate: " << dataConfig.publishrate() - << " -- enablePosition: " << dataConfig.enableposition() - << " -- enableOrientation: " << dataConfig.enableorientation() - << " -- enableTwistLinear: " << dataConfig.enabletwistlinear() - << " -- enableTwistAngular: " << dataConfig.enabletwistangular() - << std::endl; - - n.setParam("data_publish_rate", dataConfig.publishrate()); - n.setParam("data_enable_position", dataConfig.enableposition()); - n.setParam("data_enable_orientation", dataConfig.enableorientation()); - n.setParam("data_enable_twist_linear", dataConfig.enabletwistlinear()); - n.setParam("data_enable_twist_angular", dataConfig.enabletwistangular()); +void handleDataConfig(config::DataConfig dataConfig, ros::NodeHandle n) { + std::cout << "Retrieved new data-config: -- publish-rate: " << dataConfig.publishrate() + << " -- enablePosition: " << dataConfig.enableposition() + << " -- enableOrientation: " << dataConfig.enableorientation() + << " -- enableTwistLinear: " << dataConfig.enabletwistlinear() + << " -- enableTwistAngular: " << dataConfig.enabletwistangular() << std::endl; + + n.setParam("data_publish_rate", dataConfig.publishrate()); + n.setParam("data_enable_position", dataConfig.enableposition()); + n.setParam("data_enable_orientation", dataConfig.enableorientation()); + n.setParam("data_enable_twist_linear", dataConfig.enabletwistlinear()); + n.setParam("data_enable_twist_angular", dataConfig.enabletwistangular()); } void handleMessage(const ros::NodeHandle &n, const mqtt::const_message_ptr &msg) { - if (msg->get_topic() == "robotconfig") - { - const string rc_payload = msg->get_payload_str(); - config::RobotConfig robotConfig; - robotConfig.ParseFromString(rc_payload); - handleRobotConfig(robotConfig, n); - } - - if (msg->get_topic() == "dataconfig") - { - const string dc_payload = msg->get_payload_str(); - config::DataConfig dataConfig; - dataConfig.ParseFromString(dc_payload); - handleDataConfig(dataConfig, n); - } - - if (msg->get_topic() == "trajectoryconfig") - { - const string tc_payload = msg->get_payload_str(); - plan::Trajectory trajectoryConfig; - trajectoryConfig.ParseFromString(tc_payload); - handleNewTrajectory(trajectoryConfig, n); - } + if (msg->get_topic() == "robotconfig") { + const string rc_payload = msg->get_payload_str(); + config::RobotConfig robotConfig; + robotConfig.ParseFromString(rc_payload); + handleRobotConfig(robotConfig, n); + } + + if (msg->get_topic() == "dataconfig") { + const string dc_payload = msg->get_payload_str(); + config::DataConfig dataConfig; + dataConfig.ParseFromString(dc_payload); + handleDataConfig(dataConfig, n); + } + + if (msg->get_topic() == "trajectoryconfig") { + const string tc_payload = msg->get_payload_str(); + plan::Trajectory trajectoryConfig; + trajectoryConfig.ParseFromString(tc_payload); + handleNewTrajectory(trajectoryConfig, n); + } } -void receiveMqttMessages(ros::NodeHandle n) -{ - mqtt::connect_options connOpts; - mqtt::client cli(SERVER_ADDRESS, CLIENT_ID); - - connOpts.set_keep_alive_interval(20); - connOpts.set_clean_session(true); - - const vector<string> TOPICS { "robotconfig", "dataconfig", "trajectoryconfig" }; - const vector<int> QOS { 1, 1, 1 }; - - try { - ROS_INFO_STREAM("Connecting to the MQTT server."); - mqtt::connect_response rsp = cli.connect(connOpts); - ROS_INFO_STREAM("Connected to the MQTT server."); - - if (!rsp.is_session_present()) { - ROS_INFO_STREAM("Subscribing to topics."); - cli.subscribe(TOPICS, QOS); - ROS_INFO_STREAM("Subscribed to topics."); - }else { - ROS_WARN_STREAM("Session already present. Skipping subscribe."); - } - - // Consume messages - while (true) { - - auto msg = cli.consume_message(); - - if (!msg) { - if (!cli.is_connected()) { - ROS_ERROR_STREAM("Lost connection. Attempting reconnect"); - if (try_reconnect(cli)) { - cli.subscribe(TOPICS, QOS); - ROS_INFO_STREAM("Reconnected"); - continue; - } - else { - ROS_ERROR_STREAM("Reconnect failed."); - } - } - else { - ROS_ERROR_STREAM("An error occurred retrieving messages."); - } - break; - } - - handleMessage(n, msg); - //ROS_INFO_STREAM("NEW MESSAGE: " << msg->get_topic() << ": " << msg->to_string()); - } +void receiveMqttMessages(ros::NodeHandle n) { + if (mqttUtil.ensureConnection()) { + mqtt::const_message_ptr msg; + if (mqttUtil.getClient().try_consume_message_for(&msg, std::chrono::milliseconds(500))) { + ROS_INFO_STREAM("NEW MESSAGE: " << msg.get()->get_topic() << ": " << msg.get()->to_string()); + handleMessage(n, msg); } - catch (const mqtt::exception& exc) { - ROS_ERROR_STREAM("MQTT2ROS " << exc.what()); - cli.disconnect(); - return; - } - cli.disconnect(); + } else { + ROS_ERROR_STREAM_NAMED("MqttToRosNode", "Not connected! Unable to listen to messages."); + } } -int main(int argc, char* argv[]) -{ - ros::init(argc, argv, "mqtt_listener"); - ros::NodeHandle n; +int main(int argc, char *argv[]) { + ros::init(argc, argv, "mqtt_listener"); + ros::NodeHandle n; + + mqttUtil.addTopic("robotconfig"); + mqttUtil.addTopic("dataconfig"); + mqttUtil.addTopic("trajectoryconfig"); + + if (!mqttUtil.connect()) { + ROS_INFO_STREAM("Unable to connect to MQTT server. Exiting..."); + return -1; + } + while (ros::ok()) { receiveMqttMessages(n); + ros::spinOnce(); + } - ros::spin(); - return 0; + return 0; } \ No newline at end of file diff --git a/src/RobotStateProvider.cpp b/src/RobotStateProvider.cpp index 82cbe76d1b5fc2e4c38f20b6f893e2504211940d..228119a6cb6aee7d5091bb7dbbe4114ba96e7b63 100644 --- a/src/RobotStateProvider.cpp +++ b/src/RobotStateProvider.cpp @@ -4,9 +4,10 @@ #include "ros/ros.h" #include <gazebo_msgs/LinkStates.h> #include <mqtt/client.h> -#include "string.h" + #include "linkstate.pb.h" -#include "mem_persistence.cpp" + +#include "util/MqttUtil.h" bool export_to_log = false; @@ -18,227 +19,198 @@ std::string topics[11] = {"panda_ground", "panda_link_0", "panda_link_1", "panda "panda_link_3", "panda_link_4", "panda_link_5", "panda_link_6", "panda_link_7", "panda_link_8", "panda_link_9"}; -bool mqttSetup = false; bool isInitialized = false; const int QOS = 1; int current_redirect = 0; -mem_persistence persist; -mqtt::client client("tcp://localhost:1883", "robot_state_provider_mqtt", &persist); +const std::string CLIENT_ID{"robot_state_provider_mqtt"}; + +MqttUtil mqttUtil(CLIENT_ID); /* * logs to its own file in /.ros/logs (configured in launch-file) */ void exportMessageToLog(const gazebo_msgs::LinkStates &msg) { - bool export_position = false; - bool export_orientation = false; - bool export_twist_linear = false; - bool export_twist_angular = false; + bool export_position = false; + bool export_orientation = false; + bool export_twist_linear = false; + bool export_twist_angular = false; - ros::NodeHandle n; + ros::NodeHandle n; - n.getParam("data_enable_position", export_position); - n.getParam("data_enable_orientation", export_orientation); - n.getParam("data_enable_twist_linear", export_twist_linear); - n.getParam("data_enable_twist_angular", export_twist_angular); + n.getParam("data_enable_position", export_position); + n.getParam("data_enable_orientation", export_orientation); + n.getParam("data_enable_twist_linear", export_twist_linear); + n.getParam("data_enable_twist_angular", export_twist_angular); - ROS_INFO_STREAM("<<< LINK NAMES >>>"); + ROS_INFO_STREAM("<<< LINK NAMES >>>"); - for (int i = 0; i < msg.name.size(); i++) { - ROS_INFO_STREAM("[" << i << "] " << msg.name.at(i)); - } + for (int i = 0; i < msg.name.size(); i++) { + ROS_INFO_STREAM("[" << i << "] " << msg.name.at(i)); + } - if (export_position) { + if (export_position) { - ROS_INFO_STREAM("<<< POSITIONS BY LINK >>>"); + ROS_INFO_STREAM("<<< POSITIONS BY LINK >>>"); - for (int i = 0; i < msg.pose.size(); i++) { - ROS_INFO_STREAM("[" << i << "] [x] " << msg.pose.at(i).position.x); - ROS_INFO_STREAM("[" << i << "] [y] " << msg.pose.at(i).position.y); - ROS_INFO_STREAM("[" << i << "] [z] " << msg.pose.at(i).position.z); - } + for (int i = 0; i < msg.pose.size(); i++) { + ROS_INFO_STREAM("[" << i << "] [x] " << msg.pose.at(i).position.x); + ROS_INFO_STREAM("[" << i << "] [y] " << msg.pose.at(i).position.y); + ROS_INFO_STREAM("[" << i << "] [z] " << msg.pose.at(i).position.z); } + } - if (export_orientation) { + if (export_orientation) { - ROS_INFO_STREAM("<<< ORIENTATIONS BY LINK >>>"); + ROS_INFO_STREAM("<<< ORIENTATIONS BY LINK >>>"); - for (int i = 0; i < msg.pose.size(); i++) { - ROS_INFO_STREAM("[" << i << "] [w] " << msg.pose.at(i).orientation.w); - ROS_INFO_STREAM("[" << i << "] [x] " << msg.pose.at(i).orientation.x); - ROS_INFO_STREAM("[" << i << "] [y] " << msg.pose.at(i).orientation.y); - ROS_INFO_STREAM("[" << i << "] [z] " << msg.pose.at(i).orientation.z); - } + for (int i = 0; i < msg.pose.size(); i++) { + ROS_INFO_STREAM("[" << i << "] [w] " << msg.pose.at(i).orientation.w); + ROS_INFO_STREAM("[" << i << "] [x] " << msg.pose.at(i).orientation.x); + ROS_INFO_STREAM("[" << i << "] [y] " << msg.pose.at(i).orientation.y); + ROS_INFO_STREAM("[" << i << "] [z] " << msg.pose.at(i).orientation.z); } - - if (export_twist_linear) { - ROS_INFO_STREAM("<<< LINEAR TWISTS BY LINK >>>"); - for (int i = 0; i < msg.twist.size(); i++) { - ROS_INFO_STREAM("[" << i << "] [x] " << msg.twist.at(i).linear.x); - ROS_INFO_STREAM("[" << i << "] [y] " << msg.twist.at(i).linear.y); - ROS_INFO_STREAM("[" << i << "] [z] " << msg.twist.at(i).linear.z); - } + } + + if (export_twist_linear) { + ROS_INFO_STREAM("<<< LINEAR TWISTS BY LINK >>>"); + for (int i = 0; i < msg.twist.size(); i++) { + ROS_INFO_STREAM("[" << i << "] [x] " << msg.twist.at(i).linear.x); + ROS_INFO_STREAM("[" << i << "] [y] " << msg.twist.at(i).linear.y); + ROS_INFO_STREAM("[" << i << "] [z] " << msg.twist.at(i).linear.z); } - - if (export_twist_angular) { - ROS_INFO_STREAM("<<< ANGULAR TWISTS BY LINK >>>"); - for (int i = 0; i < msg.twist.size(); i++) { - ROS_INFO_STREAM("[" << i << "] [x] " << msg.twist.at(i).angular.x); - ROS_INFO_STREAM("[" << i << "] [y] " << msg.twist.at(i).angular.y); - ROS_INFO_STREAM("[" << i << "] [z] " << msg.twist.at(i).angular.z); - } + } + + if (export_twist_angular) { + ROS_INFO_STREAM("<<< ANGULAR TWISTS BY LINK >>>"); + for (int i = 0; i < msg.twist.size(); i++) { + ROS_INFO_STREAM("[" << i << "] [x] " << msg.twist.at(i).angular.x); + ROS_INFO_STREAM("[" << i << "] [y] " << msg.twist.at(i).angular.y); + ROS_INFO_STREAM("[" << i << "] [z] " << msg.twist.at(i).angular.z); } + } } panda::PandaLinkState buildLinkStateMessage(const gazebo_msgs::LinkStates &msg, int link_number) { - bool export_position = false; - bool export_orientation = false; - bool export_twist_linear = false; - bool export_twist_angular = false; - - ros::NodeHandle n; - - n.getParam("data_enable_position", export_position); - n.getParam("data_enable_orientation", export_orientation); - n.getParam("data_enable_twist_linear", export_twist_linear); - n.getParam("data_enable_twist_angular", export_twist_angular); - - //std::cout << "Building LinkStateMessage with pos: " << export_position << " ori: " << export_orientation << " twistlin: " - // << export_twist_linear << " twistang: " << export_twist_angular << std::endl; - - panda::PandaLinkState pls_msg; - - pls_msg.set_name(msg.name.at(link_number)); - - if (export_position) { - panda::PandaLinkState_Position *pos = new panda::PandaLinkState_Position(); - pos->set_positionx(msg.pose.at(link_number).position.x); - pos->set_positiony(msg.pose.at(link_number).position.y); - pos->set_positionz(msg.pose.at(link_number).position.z); - pls_msg.set_allocated_pos(pos); - } - - if (export_orientation) { - panda::PandaLinkState_Orientation *orient = new panda::PandaLinkState_Orientation(); - orient->set_orientationw(msg.pose.at(link_number).orientation.w); - orient->set_orientationx(msg.pose.at(link_number).orientation.x); - orient->set_orientationy(msg.pose.at(link_number).orientation.y); - orient->set_orientationz(msg.pose.at(link_number).orientation.z); - pls_msg.set_allocated_orient(orient); - } - - if (export_twist_linear) { - panda::PandaLinkState_TwistLinear *tl = new panda::PandaLinkState_TwistLinear(); - tl->set_twistlinearx(msg.twist.at(link_number).linear.x); - tl->set_twistlineary(msg.twist.at(link_number).linear.y); - tl->set_twistlinearz(msg.twist.at(link_number).linear.z); - pls_msg.set_allocated_tl(tl); - } - - if (export_twist_angular) { - panda::PandaLinkState_TwistAngular *ta = new panda::PandaLinkState_TwistAngular(); - ta->set_twistangularx(msg.twist.at(link_number).angular.x); - ta->set_twistangulary(msg.twist.at(link_number).angular.y); - ta->set_twistangularz(msg.twist.at(link_number).angular.z); - pls_msg.set_allocated_ta(ta); - } - - return pls_msg; -} - -void setupMqtt() { - - if (!mqttSetup) { - std::cout << "MQTT: Initializing." << std::endl; - - mqtt::connect_options connOpts; - connOpts.set_keep_alive_interval(20); - connOpts.set_clean_session(true); - std::cout << "MQTT: Initialized." << std::endl; - - std::cout << "MQTT: Connecting." << std::endl; - client.connect(connOpts); - std::cout << "MQTT: Connected." << std::endl; - mqttSetup = true; - } + bool export_position = false; + bool export_orientation = false; + bool export_twist_linear = false; + bool export_twist_angular = false; + + ros::NodeHandle n; + + n.getParam("data_enable_position", export_position); + n.getParam("data_enable_orientation", export_orientation); + n.getParam("data_enable_twist_linear", export_twist_linear); + n.getParam("data_enable_twist_angular", export_twist_angular); + + // std::cout << "Building LinkStateMessage with pos: " << export_position << " ori: " << export_orientation << " + // twistlin: " + // << export_twist_linear << " twistang: " << export_twist_angular << std::endl; + + panda::PandaLinkState pls_msg; + + pls_msg.set_name(msg.name.at(link_number)); + + if (export_position) { + panda::PandaLinkState_Position *pos = new panda::PandaLinkState_Position(); + pos->set_positionx(msg.pose.at(link_number).position.x); + pos->set_positiony(msg.pose.at(link_number).position.y); + pos->set_positionz(msg.pose.at(link_number).position.z); + pls_msg.set_allocated_pos(pos); + } + + if (export_orientation) { + panda::PandaLinkState_Orientation *orient = new panda::PandaLinkState_Orientation(); + orient->set_orientationw(msg.pose.at(link_number).orientation.w); + orient->set_orientationx(msg.pose.at(link_number).orientation.x); + orient->set_orientationy(msg.pose.at(link_number).orientation.y); + orient->set_orientationz(msg.pose.at(link_number).orientation.z); + pls_msg.set_allocated_orient(orient); + } + + if (export_twist_linear) { + panda::PandaLinkState_TwistLinear *tl = new panda::PandaLinkState_TwistLinear(); + tl->set_twistlinearx(msg.twist.at(link_number).linear.x); + tl->set_twistlineary(msg.twist.at(link_number).linear.y); + tl->set_twistlinearz(msg.twist.at(link_number).linear.z); + pls_msg.set_allocated_tl(tl); + } + + if (export_twist_angular) { + panda::PandaLinkState_TwistAngular *ta = new panda::PandaLinkState_TwistAngular(); + ta->set_twistangularx(msg.twist.at(link_number).angular.x); + ta->set_twistangulary(msg.twist.at(link_number).angular.y); + ta->set_twistangularz(msg.twist.at(link_number).angular.z); + pls_msg.set_allocated_ta(ta); + } + + return pls_msg; } - void sendMqttMessages(const gazebo_msgs::LinkStates &msg) { - setupMqtt(); - + if (mqttUtil.ensureConnection()) { try { - for (int i = 0; i < msg.name.size(); i++) { - panda::PandaLinkState pls_msg = buildLinkStateMessage(msg, i); - std::string mqtt_msg; - pls_msg.SerializeToString(&mqtt_msg); - - //std::cout << "SENDING MESSAGE TO " << topics[i] << std::endl; - auto pubmsg = mqtt::make_message(topics[i], mqtt_msg); - pubmsg->set_qos(QOS); - client.publish(pubmsg); - } + for (int i = 0; i < msg.name.size(); i++) { + panda::PandaLinkState pls_msg = buildLinkStateMessage(msg, i); + std::string mqtt_msg; + pls_msg.SerializeToString(&mqtt_msg); + + // std::cout << "SENDING MESSAGE TO " << topics[i] << std::endl; + auto pubmsg = mqtt::make_message(topics[i], mqtt_msg); + pubmsg->set_qos(QOS); + mqttUtil.getClient().publish(pubmsg); + } } // happens at lib paho sometimes when multiple instances of an mqtt-client are publishing at the same time catch (const mqtt::exception &exc) { - ROS_ERROR_STREAM("RSP: " << exc.what()); - // causes automatic reconnect - mqttSetup = false; - return; + ROS_ERROR_STREAM("RSP: " << exc.what()); + return; } + } else { + ROS_ERROR_STREAM_NAMED("MqttToRosNode", "Not connected! Unable to listen to messages."); + } } void providerCallback(const gazebo_msgs::LinkStates &msg) { - ros::NodeHandle n; - int message_redirect_rate = 200; - n.getParam("data_publish_rate", message_redirect_rate); - - if (current_redirect != 0 && current_redirect != message_redirect_rate) { - // std::cout << "Ignoring message (redirect: " << current_redirect << " )" << std::endl; - current_redirect++; - return; - } - - if (current_redirect == 0 || current_redirect == message_redirect_rate) { - //std::cout << "Sending LinkStates with rate: " << message_redirect_rate << std::endl; + // TODO the rate should not be depending on the link state rate, but rather be a time or frequency!!!! - if (export_to_log) { - exportMessageToLog(msg); - } + ros::NodeHandle n; + int message_redirect_rate; + n.getParam("data_publish_rate", message_redirect_rate); - sendMqttMessages(msg); - - if (current_redirect == message_redirect_rate) { - current_redirect = 1; - } else { - current_redirect++; - } + if (current_redirect == 0) { + if (export_to_log) { + exportMessageToLog(msg); } + sendMqttMessages(msg); + } + current_redirect = ++current_redirect % message_redirect_rate; } int main(int argc, char **argv) { - ros::init(argc, argv, "robot_state_provider"); - ros::NodeHandle n; - n.getParam("ready", isInitialized); + ros::init(argc, argv, "robot_state_provider"); + ros::NodeHandle n; + n.getParam("ready", isInitialized); - while (ros::ok()) { + mqttUtil.connect(); - // make sure the robot is initialized - while (!isInitialized) { - //std::cout << "Waiting" << std::endl; - n.getParam("tud_planner_ready", isInitialized); - } + while (ros::ok()) { - ros::Subscriber sub = n.subscribe("/gazebo/link_states", 10000, providerCallback); - ros::spin(); + // make sure the robot is initialized + while (!isInitialized) { + // std::cout << "Waiting" << std::endl; + n.getParam("tud_planner_ready", isInitialized); } - // disconnect from mqtt - client.disconnect(); - return 0; + ros::Subscriber sub = n.subscribe("/gazebo/link_states", 10000, providerCallback); + ros::spin(); + } + + return 0; } \ No newline at end of file diff --git a/src/SafetyAwarePlanner.cpp b/src/SafetyAwarePlanner.cpp deleted file mode 100644 index afe69ecc2e5f16c385af1bcaf82bee58570e8253..0000000000000000000000000000000000000000 --- a/src/SafetyAwarePlanner.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include <moveit/move_group_interface/move_group_interface.h> -#include <moveit/planning_scene_interface/planning_scene_interface.h> -#include <moveit_msgs/CollisionObject.h> -#include <moveit_visual_tools/moveit_visual_tools.h> - -#include "SafetyEnvironmentCreator.cpp" - -int main(int argc, char** argv) -{ - ros::init(argc, argv, "Safety-aware PLANNER"); - ros::NodeHandle node_handle; - ros::AsyncSpinner spinner(1); - spinner.start(); - - static const std::string PLANNING_GROUP = "panda_arm"; - moveit::planning_interface::MoveGroupInterface move_group(PLANNING_GROUP); - moveit::planning_interface::PlanningSceneInterface planning_scene_interface; - const robot_state::JointModelGroup* joint_model_group = - move_group.getCurrentState()->getJointModelGroup(PLANNING_GROUP); - - // Visualization Setup - namespace rvt = rviz_visual_tools; - moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0"); - //visual_tools.deleteAllMarkers(); - visual_tools.loadRemoteControl(); - visual_tools.setAlpha(0.5); - - Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity(); - text_pose.translation().z() = 1.75; - visual_tools.publishText(text_pose, "Safety-aware planner node", rvt::WHITE, rvt::XLARGE); - - // Batch publishing is used to reduce the number of messages being sent to RViz for large visualizations - visual_tools.trigger(); - - // Getting Basic Information - ROS_INFO_NAMED("safety_aware_planner", "Planning frame: %s", move_group.getPlanningFrame().c_str()); - ROS_INFO_NAMED("safety_aware_planner", "End effector link: %s", move_group.getEndEffectorLink().c_str()); - ROS_INFO_NAMED("safety_aware_planner", "Available Planning Groups:"); - std::copy(move_group.getJointModelGroupNames().begin(), move_group.getJointModelGroupNames().end(), - std::ostream_iterator<std::string>(std::cout, ", ")); - - shape_msgs::SolidPrimitive safety_box; - geometry_msgs::Pose safety_box_pose; - - safety_box_pose.orientation.w = 1.0; - safety_box_pose.orientation.x = 0.0; - safety_box_pose.orientation.y = 0.0; - safety_box_pose.orientation.z = 0.0; - safety_box_pose.position.x = 0.0; - safety_box_pose.position.y = 0.0; - safety_box_pose.position.z = 0.0; - - safety_box.type = safety_box.BOX; - safety_box.dimensions.resize(3); - - safety_box.dimensions[0] = 2.0; - safety_box.dimensions[1] = 2.0; - safety_box.dimensions[2] = 2.0; - - // Safety Box - SafetyEnvironmentCreator sec(safety_box, safety_box_pose); - std::vector<moveit_msgs::CollisionObject> collision_objects = sec.createCentralizedSafetyEnvironment(move_group); - - //visual_tools.processCollisionObjectMsg(collision_objects[2], rviz_visual_tools::RED); - // visual_tools.setAlpha(0.0); - // Now, let's add the collision object into the world - ROS_INFO_NAMED("safety_aware_planner", "Add an object into the world"); - - planning_scene_interface.addCollisionObjects(collision_objects); - - // Show text in RViz of status - visual_tools.publishText(text_pose, "Add object", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object appears in RViz"); - - // Now when we plan a trajectory it will avoid the obstacle - move_group.setStartState(*move_group.getCurrentState()); - geometry_msgs::Pose another_pose; - another_pose.orientation.w = 1.0; - another_pose.position.x = 0.4; - another_pose.position.y = -0.4; - another_pose.position.z = 0.9; - move_group.setPoseTarget(another_pose); - - //moveit_msgs::MotionPlanRequest mr; - //mr.max_velocity_scaling_factor = 0.5; - //move_group.constructMotionPlanRequest(mr); - - //move_group.setMaxVelocityScalingFactor(0.1); - //move_group.setWorkspace(-0.5, -0.5, -0.5, 0, 0, 0); - - moveit::planning_interface::MoveGroupInterface::Plan my_plan; - bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS); - ROS_INFO_NAMED("safety_aware_planner", "Visualizing constraint plan %s", success ? "" : "FAILED"); - - visual_tools.prompt("Press 'next' to move the simulated robot."); - visual_tools.trigger(); - - // Move the simulated robot in gazebo - move_group.move(); - - ros::shutdown(); - return 0; -} \ No newline at end of file diff --git a/src/SafetyEnvironmentCreator.cpp b/src/SafetyEnvironmentCreator.cpp deleted file mode 100644 index f6ccedb8084b4e384add979d5a65d05fd07e0b7d..0000000000000000000000000000000000000000 --- a/src/SafetyEnvironmentCreator.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// -// Created by Sebastian Ebert -// - -#include <moveit/move_group_interface/move_group_interface.h> -#include <moveit_msgs/CollisionObject.h> -#include <moveit_visual_tools/moveit_visual_tools.h> - -class SafetyEnvironmentCreator { - - private: - double safety_zone_width; - double safety_zone_height; - double safety_zone_depth; - double zone_orientation_w; - double zone_orientation_x; - double zone_orientation_y; - double zone_orientation_z; - double zone_position_x; - double zone_position_y; - double zone_position_z; - - public: - /** - * ctor - * @param shape describes the inner dimensions of the safety zone - * @param pose describes position and orientation of the safety zone - * note: current zone-threshold is 0.1 - */ - SafetyEnvironmentCreator(shape_msgs::SolidPrimitive shape, geometry_msgs::Pose pose) { - if(shape.type != shape.BOX){ - ROS_ERROR("Safety-zone could not be created due to wrong shape-type"); - safety_zone_depth = 0.0; - safety_zone_width = 0.0; - safety_zone_height = 0.0; - zone_orientation_w = 1.0; - zone_orientation_x = 1.0; - zone_orientation_y = 1.0; - zone_orientation_z = 1.0; - }else { - safety_zone_depth = shape.dimensions[0]; - safety_zone_width = shape.dimensions[1]; - safety_zone_height = shape.dimensions[2]; - zone_orientation_w = pose.orientation.w; - zone_orientation_x = pose.orientation.x; - zone_orientation_y = pose.orientation.y; - zone_orientation_z = pose.orientation.z; - zone_position_x = pose.position.x; - zone_position_y = pose.position.y; - zone_position_z = pose.position.z; - } - } - - double getZoneWidth() const { - return safety_zone_width; - } - - double getZoneHeight() const { - return safety_zone_height; - } - - double getZoneDepth() const { - return safety_zone_depth; - } - - double getZoneOrientationW() const { - return zone_orientation_w; - } - - double getZoneOrientationX() const { - return zone_orientation_x; - } - - double getZoneOrientationY() const { - return zone_orientation_y; - } - - double getZoneOrientationZ() const { - return zone_orientation_z; - } - - std::vector<moveit_msgs::CollisionObject> createCentralizedSafetyEnvironment(moveit::planning_interface::MoveGroupInterface &move_group) { - - std::vector<moveit_msgs::CollisionObject> collision_objects; - - // OBJECT 1 ( left box / -y ) - // ^^^^^^^^ - // Define a collision object ROS message. - moveit_msgs::CollisionObject collision_object; - collision_object.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object.id = "box1"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive; - primitive.type = primitive.BOX; - primitive.dimensions.resize(3); - - primitive.dimensions[0] = getZoneDepth() + 0.2; // x - primitive.dimensions[1] = 0.1; // y - primitive.dimensions[2] = getZoneHeight(); // z - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose; - box_pose.orientation.w = 1.0; - box_pose.position.x = zone_position_x; - box_pose.position.y = zone_position_y + (-1 * ((getZoneWidth() / 2) + 0.05)); - box_pose.position.z = zone_position_z + (primitive.dimensions[2] / 2); - - collision_object.primitives.push_back(primitive); - collision_object.primitive_poses.push_back(box_pose); - collision_object.operation = collision_object.ADD; - - collision_objects.push_back(collision_object); - - // OBJECT 2 right box / +y ) - // ^^^^^^^^ - moveit_msgs::CollisionObject collision_object_2; - collision_object_2.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object_2.id = "box2"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive_2; - primitive_2.type = primitive.BOX; - primitive_2.dimensions.resize(3); - primitive_2.dimensions[0] = getZoneDepth() + 0.2; - primitive_2.dimensions[1] = 0.1; - primitive_2.dimensions[2] = getZoneHeight(); - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose_2; - box_pose_2.orientation.w = 1.0; - box_pose_2.position.x = zone_position_x; - box_pose_2.position.y = zone_position_y + ((getZoneWidth() / 2) + 0.05); - box_pose_2.position.z = zone_position_z + (primitive_2.dimensions[2] / 2); - - collision_object_2.primitives.push_back(primitive_2); - collision_object_2.primitive_poses.push_back(box_pose_2); - collision_object_2.operation = collision_object_2.ADD; - - collision_objects.push_back(collision_object_2); - - // OBJECT 3 (front box / +x) - // ^^^^^^^^ - moveit_msgs::CollisionObject collision_object_3; - collision_object_3.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object_3.id = "box3"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive_3; - primitive_3.type = primitive.BOX; - primitive_3.dimensions.resize(3); - primitive_3.dimensions[0] = 0.1; - primitive_3.dimensions[1] = getZoneWidth() + 0.2; - primitive_3.dimensions[2] = getZoneHeight(); - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose_3; - box_pose_3.orientation.w = 1.0; - box_pose_3.position.x = zone_position_x + ((getZoneDepth() / 2) + 0.05); - box_pose_3.position.y = zone_position_y; - box_pose_3.position.z = zone_position_z + (primitive_3.dimensions[2] / 2); - - collision_object_3.primitives.push_back(primitive_3); - collision_object_3.primitive_poses.push_back(box_pose_3); - collision_object_3.operation = collision_object_3.ADD; - - collision_objects.push_back(collision_object_3); - - // OBJECT 4 (back box / -x) - // ^^^^^^^^ - moveit_msgs::CollisionObject collision_object_4; - collision_object_4.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object_4.id = "box4"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive_4; - primitive_4.type = primitive.BOX; - primitive_4.dimensions.resize(3); - primitive_4.dimensions[0] = 0.1; - primitive_4.dimensions[1] = getZoneWidth() + 0.2; - primitive_4.dimensions[2] = getZoneHeight(); - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose_4; - box_pose_4.orientation.w = 1.0; - box_pose_4.position.x = zone_position_x + (-1 * ((getZoneDepth() / 2) + 0.05)); - box_pose_4.position.y = zone_position_y; - box_pose_4.position.z = zone_position_z + (primitive_4.dimensions[2] / 2); - - collision_object_4.primitives.push_back(primitive_4); - collision_object_4.primitive_poses.push_back(box_pose_4); - collision_object_4.operation = collision_object_4.ADD; - - collision_objects.push_back(collision_object_4); - - // OBJECT 5 (floor / -z) - // ^^^^^^^^ - moveit_msgs::CollisionObject collision_object_5; - collision_object_5.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object_5.id = "box5"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive_5; - primitive_5.type = primitive.BOX; - primitive_5.dimensions.resize(3); - primitive_5.dimensions[0] = getZoneDepth() + 0.2; - primitive_5.dimensions[1] = getZoneWidth() + 0.2; - primitive_5.dimensions[2] = 0.1; - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose_5; - box_pose_5.orientation.w = 1.0; - box_pose_5.position.x = zone_position_x; - box_pose_5.position.y = zone_position_y; - box_pose_5.position.z = zone_position_z - 0.05; - - collision_object_5.primitives.push_back(primitive_5); - collision_object_5.primitive_poses.push_back(box_pose_5); - collision_object_5.operation = collision_object_5.ADD; - - collision_objects.push_back(collision_object_5); - - // OBJECT 6 (top / +z) - // ^^^^^^^^ - moveit_msgs::CollisionObject collision_object_6; - collision_object_6.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object_6.id = "box6"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive_6; - primitive_6.type = primitive.BOX; - primitive_6.dimensions.resize(3); - primitive_6.dimensions[0] = getZoneDepth() + 0.2; - primitive_6.dimensions[1] = getZoneWidth() + 0.2; - primitive_6.dimensions[2] = 0.1; - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose_6; - box_pose_6.orientation.w = 1.0; - box_pose_6.position.x = zone_position_x; - box_pose_6.position.y = zone_position_y; - box_pose_6.position.z = zone_position_z + getZoneHeight() + 0.05; - - collision_object_6.primitives.push_back(primitive_6); - collision_object_6.primitive_poses.push_back(box_pose_6); - collision_object_6.operation = collision_object_6.ADD; - collision_objects.push_back(collision_object_6); - - /*for(std::size_t i=0; i<collision_objects.size(); ++i) { - collision_objects[i].primitive_poses[0].orientation.w = getZoneOrientationW(); - collision_objects[i].primitive_poses[0].orientation.x = getZoneOrientationX(); - collision_objects[i].primitive_poses[0].orientation.y = getZoneOrientationY(); - collision_objects[i].primitive_poses[0].orientation.z = getZoneOrientationZ(); - }*/ - - return collision_objects; - } -}; \ No newline at end of file diff --git a/src/TimedPlanner.cpp b/src/TimedPlanner.cpp index 97ead42011a09bb2f103d0d09048932383771e98..5d3005c0fc59b52098ab67076be66e6835355abc 100644 --- a/src/TimedPlanner.cpp +++ b/src/TimedPlanner.cpp @@ -158,17 +158,6 @@ int main(int argc, char **argv) { ROS_INFO(">>>>>>>>>>>>>>>>> START UP FINISHED <<<<<<<<<<<<<<<< "); node_handle.setParam("tud_planner_ready", true); - // Visualization Setup. - namespace rvt = rviz_visual_tools; - moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0"); - visual_tools.deleteAllMarkers(); - visual_tools.loadRemoteControl(); - - Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity(); - text_pose.translation().z() = 1.75; - visual_tools.publishText(text_pose, "cartesian planner node", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - // Initialize start state of robot and target trajectory. moveit::planning_interface::MoveGroupInterface group("panda_arm"); moveRobotToInitialState(node_handle); diff --git a/src/mem_persistence.cpp b/src/mem_persistence.cpp deleted file mode 100644 index b6da0550a59c174145d2b831b4bcc978782b63fa..0000000000000000000000000000000000000000 --- a/src/mem_persistence.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include <string> -#include <map> -#include <vector> -#include "mqtt/client.h" - -// Connection persistence class. -class mem_persistence : virtual public mqtt::iclient_persistence { - // Whether the store is open - bool open_; - - // Use an STL map to store shared persistence pointers - // against string keys. - std::map<std::string, std::string> store_; - -public: - mem_persistence() : open_(false) {} - - // "Open" the store - void open(const std::string &clientId, const std::string &serverURI) override { - open_ = true; - } - - // Close the persistent store that was previously opened. - void close() override { - open_ = false; - } - - // Clears persistence, so that it no longer contains any persisted data. - void clear() override { - store_.clear(); - } - - // Returns whether or not data is persisted using the specified key. - bool contains_key(const std::string &key) override { - return store_.find(key) != store_.end(); - } - - // Returns the keys in this persistent data store. - const mqtt::string_collection &keys() const override { - static mqtt::string_collection ks; - ks.clear(); - for (const auto &k : store_) - ks.push_back(k.first); - return ks; - } - - // Puts the specified data into the persistent store. - void put(const std::string &key, const std::vector<mqtt::string_view> &bufs) override { - std::string str; - for (const auto &b : bufs) - str += b.str(); - store_[key] = std::move(str); - } - - // Gets the specified data out of the persistent store. - mqtt::string_view get(const std::string &key) const override { - auto p = store_.find(key); - if (p == store_.end()) - throw mqtt::persistence_exception(); - - return mqtt::string_view(p->second); - } - - // Remove the data for the specified key. - void remove(const std::string &key) override { - auto p = store_.find(key); - if (p == store_.end()) - throw mqtt::persistence_exception(); - store_.erase(p);; - } -}; \ No newline at end of file diff --git a/src/robot_control_node.cpp b/src/robot_control_node.cpp deleted file mode 100644 index beb175b32de85e11c68c7227be65ff7dcdcb068c..0000000000000000000000000000000000000000 --- a/src/robot_control_node.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include <jsoncpp/json/json.h> -#include <moveit/move_group_interface/move_group_interface.h> -#include <moveit/planning_scene/planning_scene.h> -#include <moveit/planning_scene_interface/planning_scene_interface.h> -#include <moveit_visual_tools/moveit_visual_tools.h> -#include <ros/ros.h> -#include <boost/filesystem.hpp> - -static const std::string PLANNING_GROUP_ARM = "panda_arm"; -static const std::string APP_DIRECTORY_NAME = ".panda_simulation"; - -moveit_msgs::CollisionObject extractObstacleFromJson(Json::Value &root, std::string name) -{ - moveit_msgs::CollisionObject collision_object; - collision_object.header.frame_id = "world"; - collision_object.id = name; - - const Json::Value dimensions = root["dimensions"]; - ROS_INFO_STREAM("Extracted dimensions: " << dimensions); - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive; - primitive.type = primitive.BOX; - primitive.dimensions.resize(3); - primitive.dimensions[0] = dimensions["x"].asDouble(); - primitive.dimensions[1] = dimensions["y"].asDouble(); - primitive.dimensions[2] = dimensions["z"].asDouble(); - - const Json::Value position = root["position"]; - ROS_INFO_STREAM("Extracted position: " << position); - - const Json::Value orientation = root["orientation"]; - ROS_INFO_STREAM("Extracted orientation: " << orientation); - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose; - box_pose.orientation.w = orientation["w"].asDouble(); - box_pose.orientation.x = orientation["x"].asDouble(); - box_pose.orientation.y = orientation["y"].asDouble(); - box_pose.orientation.z = orientation["z"].asDouble(); - - // MoveIt! planning scene expects the center of the object as position. - // We add half of its dimension to its position - box_pose.position.x = position["x"].asDouble() + primitive.dimensions[0] / 2.0; - box_pose.position.y = position["y"].asDouble() + primitive.dimensions[1] / 2.0; - box_pose.position.z = position["z"].asDouble() + primitive.dimensions[2] / 2.0; - - collision_object.primitives.push_back(primitive); - collision_object.primitive_poses.push_back(box_pose); - collision_object.operation = collision_object.ADD; - - return std::move(collision_object); -} - -int main(int argc, char **argv) -{ - namespace fs = boost::filesystem; - ROS_INFO("RUNNING robot_control_node"); - - ros::init(argc, argv, "robot_control_node"); - - ros::NodeHandle node_handle; - ros::AsyncSpinner spinner(1); - spinner.start(); - - moveit::planning_interface::MoveGroupInterface move_group_arm(PLANNING_GROUP_ARM); - - ros::Publisher planning_scene_diff_publisher = node_handle.advertise<moveit_msgs::PlanningScene>("planning_scene", 1); - ros::WallDuration sleep_t(0.5); - while (planning_scene_diff_publisher.getNumSubscribers() < 1) - { - sleep_t.sleep(); - } - moveit_msgs::PlanningScene planning_scene; - - // read JSON files from ~/.panda_simulation - fs::path home(getenv("HOME")); - if (fs::is_directory(home)) - { - fs::path app_directory(home); - app_directory /= APP_DIRECTORY_NAME; - - if (!fs::exists(app_directory) && !fs::is_directory(app_directory)) - { - ROS_WARN_STREAM(app_directory << " does not exist"); - - // Create .panda_simulation directory - std::string path(getenv("HOME")); - path += "/.panda_simulation"; - ROS_INFO("Creating %s collision objects directory.", path); - try - { - boost::filesystem::create_directory(path); - } - catch (const std::exception&) - { - ROS_ERROR( - "%s directory could not be created." - "Please create this directory yourself " - "if you want to specify collision objects.", path.c_str()); - return -1; - } - } - - std::vector<moveit_msgs::CollisionObject> collision_objects; - ROS_INFO_STREAM(app_directory << " is a directory containing:"); - for (auto &entry : boost::make_iterator_range(fs::directory_iterator(app_directory), {})) - { - ROS_INFO_STREAM(entry); - - std::ifstream file_stream(entry.path().string(), std::ifstream::binary); - if (file_stream) - { - Json::Value root; - file_stream >> root; - - moveit_msgs::CollisionObject collision_object = extractObstacleFromJson(root, entry.path().stem().string()); - collision_objects.push_back(collision_object); - } - else - { - ROS_WARN_STREAM("could not open file " << entry.path()); - } - } - - // Publish the collision objects to the scene - for (const auto &collision_object : collision_objects) - { - collision_object.header.frame_id = move_group_arm.getPlanningFrame(); - planning_scene.world.collision_objects.push_back(collision_object); - } - - ROS_INFO_STREAM("# collision objects " << planning_scene.world.collision_objects.size()); - planning_scene.is_diff = true; - planning_scene_diff_publisher.publish(planning_scene); - - ROS_INFO("robot_control_node is ready"); - ros::waitForShutdown(); - - return 0; - } -} \ No newline at end of file diff --git a/src/samples/SampleConstraintPlanner.cpp b/src/samples/SampleConstraintPlanner.cpp deleted file mode 100644 index 4f442184ef3d8d1a11189f1bce2cbff7f8ed8847..0000000000000000000000000000000000000000 --- a/src/samples/SampleConstraintPlanner.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// -// Created by sebastian on 27.03.20. -// -#include <moveit/move_group_interface/move_group_interface.h> -#include <moveit/planning_scene_interface/planning_scene_interface.h> - -#include <moveit_msgs/DisplayRobotState.h> -#include <moveit_msgs/DisplayTrajectory.h> - -#include <moveit_msgs/AttachedCollisionObject.h> -#include <moveit_msgs/CollisionObject.h> - -#include <moveit_visual_tools/moveit_visual_tools.h> -#include <moveit/trajectory_processing/iterative_time_parameterization.h> -#include <trajectory_msgs/JointTrajectoryPoint.h> - -int main(int argc, char** argv) -{ - ros::init(argc, argv, "CONSTRAINT PLANNER"); - ros::NodeHandle node_handle; - ros::AsyncSpinner spinner(1); - spinner.start(); - - static const std::string PLANNING_GROUP = "panda_arm"; - moveit::planning_interface::MoveGroupInterface move_group(PLANNING_GROUP); - moveit::planning_interface::PlanningSceneInterface planning_scene_interface; - const robot_state::JointModelGroup* joint_model_group = - move_group.getCurrentState()->getJointModelGroup(PLANNING_GROUP); - - // Visualization Setup - namespace rvt = rviz_visual_tools; - moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0"); - visual_tools.deleteAllMarkers(); - visual_tools.loadRemoteControl(); - - Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity(); - text_pose.translation().z() = 1.75; - visual_tools.publishText(text_pose, "Sample constraint planner node", rvt::WHITE, rvt::XLARGE); - - // Batch publishing is used to reduce the number of messages being sent to RViz for large visualizations - visual_tools.trigger(); - - // Getting Basic Information - ROS_INFO_NAMED("constraint_planner", "Planning frame: %s", move_group.getPlanningFrame().c_str()); - ROS_INFO_NAMED("constraint_planner", "End effector link: %s", move_group.getEndEffectorLink().c_str()); - ROS_INFO_NAMED("constraint_planner", "Available Planning Groups:"); - std::copy(move_group.getJointModelGroupNames().begin(), move_group.getJointModelGroupNames().end(), - std::ostream_iterator<std::string>(std::cout, ", ")); - - // Define a collision object ROS message. - moveit_msgs::CollisionObject collision_object; - collision_object.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object.id = "box1"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive; - primitive.type = primitive.BOX; - primitive.dimensions.resize(3); - primitive.dimensions[0] = 0.4; - primitive.dimensions[1] = 0.1; - primitive.dimensions[2] = 0.4; - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose; - box_pose.orientation.w = 1.0; - box_pose.position.x = 0.4; - box_pose.position.y = -0.2; - box_pose.position.z = 1.0; - - collision_object.primitives.push_back(primitive); - collision_object.primitive_poses.push_back(box_pose); - collision_object.operation = collision_object.ADD; - - std::vector<moveit_msgs::CollisionObject> collision_objects; - collision_objects.push_back(collision_object); - - // Now, let's add the collision object into the world - ROS_INFO_NAMED("constraint_planner", "Add an object into the world"); - planning_scene_interface.addCollisionObjects(collision_objects); - - // Show text in RViz of status - visual_tools.publishText(text_pose, "Add object", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object appears in RViz"); - - // Now when we plan a trajectory it will avoid the obstacle - move_group.setStartState(*move_group.getCurrentState()); - geometry_msgs::Pose another_pose; - another_pose.orientation.w = 1.0; - another_pose.position.x = 0.4; - another_pose.position.y = -0.4; - another_pose.position.z = 0.9; - move_group.setPoseTarget(another_pose); - - moveit::planning_interface::MoveGroupInterface::Plan my_plan; - bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS); - ROS_INFO_NAMED("constraint_planner", "Visualizing constraint plan %s", success ? "" : "FAILED"); - - visual_tools.prompt("Press 'next' to move the simulated robot."); - visual_tools.trigger(); - - // Move the simulated robot in gazebo - move_group.move(); - - ros::shutdown(); - return 0; -} \ No newline at end of file diff --git a/src/samples/SampleTimedCartesianPlanner.cpp b/src/samples/SampleTimedCartesianPlanner.cpp deleted file mode 100644 index cf8d1cff3e77c9798f01a7bb34704a077f584eb1..0000000000000000000000000000000000000000 --- a/src/samples/SampleTimedCartesianPlanner.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// -// Created by sebastian on 31.03.20. -// -#include <moveit/move_group_interface/move_group_interface.h> -#include <moveit/planning_scene_interface/planning_scene_interface.h> - -#include <moveit_msgs/DisplayRobotState.h> -#include <moveit_msgs/DisplayTrajectory.h> - -#include <moveit_msgs/AttachedCollisionObject.h> -#include <moveit_msgs/CollisionObject.h> - -#include <moveit_visual_tools/moveit_visual_tools.h> -#include <moveit/trajectory_processing/iterative_time_parameterization.h> -#include <trajectory_msgs/JointTrajectoryPoint.h> - -/** - * allows time/velocity-constraint planning for cartesian paths - */ -int main(int argc, char **argv) -{ - ros::init(argc, argv, "move_group_interface_tutorial"); - ros::NodeHandle node_handle; - ros::AsyncSpinner spinner(1); - spinner.start(); - - // wait for robot init of robot_state_initializer - std::cout << ">>>>>>>>>>>>>>>>> SLEEPING <<<<<<<<<<<<<<<< " << std::endl; - ros::Duration(5.0).sleep(); - std::cout << ">>>>>>>>>>>>>>>>> WAKING UP <<<<<<<<<<<<<<<< " << std::endl; - node_handle.setParam("tud_planner_ready", true); - - // Visualization Setup - namespace rvt = rviz_visual_tools; - moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0"); - visual_tools.deleteAllMarkers(); - visual_tools.loadRemoteControl(); - - Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity(); - text_pose.translation().z() = 1.75; - visual_tools.publishText(text_pose, "Sample constraint planner node", rvt::WHITE, rvt::XLARGE); - - // Batch publishing is used to reduce the number of messages being sent to RViz for large visualizations - visual_tools.trigger(); - - moveit::planning_interface::MoveGroupInterface group("panda_arm"); - - moveit::planning_interface::PlanningSceneInterface planning_scene_interface; - - ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true); - moveit_msgs::DisplayTrajectory display_trajectory; - - moveit::planning_interface::MoveGroupInterface::Plan plan; - group.setStartStateToCurrentState(); - - std::vector<geometry_msgs::Pose> waypoints; - - // initial pose of the robot - geometry_msgs::Pose start_pose = group.getCurrentPose().pose; - - // waypoints for a circle - geometry_msgs::Pose target_pose_1 = group.getCurrentPose().pose; - geometry_msgs::Pose target_pose_2 = group.getCurrentPose().pose; - geometry_msgs::Pose target_pose_3 = group.getCurrentPose().pose; - geometry_msgs::Pose target_pose_4 = group.getCurrentPose().pose; - geometry_msgs::Pose target_pose_5 = group.getCurrentPose().pose; - - // specification of the circles waypoints - target_pose_1.position.z = start_pose.position.z - 0.4; - target_pose_1.position.y = start_pose.position.y; - target_pose_1.position.x = start_pose.position.x + 0.5; - waypoints.push_back(target_pose_1); - - target_pose_2.position.z = 0.6;//0.583; - target_pose_2.position.y = -0.6;//63; - target_pose_2.position.x = 0;//-0.007; - waypoints.push_back(target_pose_2); - - target_pose_3.position.z = 0.6;//0.691; - target_pose_3.position.y = -0.032; - target_pose_3.position.x = -0.607; - waypoints.push_back(target_pose_3); - - target_pose_4.position.z = 0.6; - target_pose_4.position.y = 0.6;//0.509; - target_pose_4.position.x = 0;//0.039; - waypoints.push_back(target_pose_4); - - target_pose_5.position.z = target_pose_1.position.z; - target_pose_5.position.y = target_pose_1.position.y; - target_pose_5.position.x = target_pose_1.position.x; - waypoints.push_back(target_pose_5); - - moveit_msgs::RobotTrajectory trajectory_msg; - group.setPlanningTime(10.0); - - double fraction = group.computeCartesianPath(waypoints,0.01,0.0,trajectory_msg, false); - - // The trajectory needs to be modified so it will include velocities as well. - // First to create a RobotTrajectory object - robot_trajectory::RobotTrajectory rt(group.getCurrentState()->getRobotModel(), "panda_arm"); - - // Second get a RobotTrajectory from trajectory - rt.setRobotTrajectoryMsg(*group.getCurrentState(), trajectory_msg); - - // Third create a IterativeParabolicTimeParameterization object - trajectory_processing::IterativeParabolicTimeParameterization iptp; - // Fourth compute computeTimeStamps - bool success = iptp.computeTimeStamps(rt); - ROS_INFO("Computed time stamp %s",success?"SUCCEDED":"FAILED"); - rt.getRobotTrajectoryMsg(trajectory_msg); - - //std::cout << ">>>>>>>>>>>>>>>>> data before: " << trajectory_msg << std::endl; - - // adjust velocities, accelerations and time_from_start - for(int i = 0; i < trajectory_msg.joint_trajectory.points.size(); i++) - { - trajectory_msg.joint_trajectory.points[i].time_from_start.operator*=(2); - for(int j = 0; j < trajectory_msg.joint_trajectory.points.at(i).velocities.size(); j++) - { - if(trajectory_msg.joint_trajectory.points.at(i).velocities.at(j) != 0.0){ - trajectory_msg.joint_trajectory.points.at(i).velocities.at(j) /= 2; - //trajectory_msg.joint_trajectory.points.at(i).velocities.at(j) = 0; - } - } - - for(int j = 0; j < trajectory_msg.joint_trajectory.points.at(i).accelerations.size(); j++) - { - trajectory_msg.joint_trajectory.points.at(i).accelerations.at(j) = - sqrt(std::abs(trajectory_msg.joint_trajectory.points.at(i).accelerations.at(j))); - } - } - - //std::cout << ">>>>>>>>>>>>>>>>> data after: " << trajectory_msg << std::endl; - plan.trajectory_ = trajectory_msg; - ROS_INFO("Visualizing plan 4 (cartesian path) (%.2f%% acheived)",fraction * 100.0); - - group.execute(plan); - - ros::shutdown(); - return 0; -} \ No newline at end of file diff --git a/src/tutorial/motion_planning_api_tutorial.cpp b/src/tutorial/motion_planning_api_tutorial.cpp deleted file mode 100644 index 9e95aadb8f7f14d75eeb88ef81d5faf1555f1c2a..0000000000000000000000000000000000000000 --- a/src/tutorial/motion_planning_api_tutorial.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/********************************************************************* - * Software License Agreement (BSD License) - * - * Copyright (c) 2012, Willow Garage, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Willow Garage nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *********************************************************************/ - -/* Author: Sachin Chitta, Michael Lautman */ - -#include <pluginlib/class_loader.h> -#include <ros/ros.h> - -// MoveIt -#include <moveit/robot_model_loader/robot_model_loader.h> -#include <moveit/planning_interface/planning_interface.h> -#include <moveit/planning_scene/planning_scene.h> -#include <moveit/kinematic_constraints/utils.h> -#include <moveit_msgs/DisplayTrajectory.h> -#include <moveit_msgs/PlanningScene.h> -#include <moveit_visual_tools/moveit_visual_tools.h> - -#include <boost/scoped_ptr.hpp> - -int main(int argc, char** argv) -{ - const std::string node_name = "motion_planning_tutorial"; - ros::init(argc, argv, node_name); - ros::AsyncSpinner spinner(1); - spinner.start(); - ros::NodeHandle node_handle("~"); - - // BEGIN_TUTORIAL - // Start - // ^^^^^ - // Setting up to start using a planner is pretty easy. Planners are - // setup as plugins in MoveIt and you can use the ROS pluginlib - // interface to load any planner that you want to use. Before we - // can load the planner, we need two objects, a RobotModel and a - // PlanningScene. We will start by instantiating a `RobotModelLoader`_ - // object, which will look up the robot description on the ROS - // parameter server and construct a :moveit_core:`RobotModel` for us - // to use. - // - // .. _RobotModelLoader: - // http://docs.ros.org/indigo/api/moveit_ros_planning/html/classrobot__model__loader_1_1RobotModelLoader.html - const std::string PLANNING_GROUP = "panda_arm"; - robot_model_loader::RobotModelLoader robot_model_loader("robot_description"); - robot_model::RobotModelPtr robot_model = robot_model_loader.getModel(); - /* Create a RobotState and JointModelGroup to keep track of the current robot pose and planning group*/ - robot_state::RobotStatePtr robot_state(new robot_state::RobotState(robot_model)); - const robot_state::JointModelGroup* joint_model_group = robot_state->getJointModelGroup(PLANNING_GROUP); - - // Using the :moveit_core:`RobotModel`, we can construct a :planning_scene:`PlanningScene` - // that maintains the state of the world (including the robot). - planning_scene::PlanningScenePtr planning_scene(new planning_scene::PlanningScene(robot_model)); - - // Configure a valid robot state - planning_scene->getCurrentStateNonConst().setToDefaultValues(joint_model_group, "ready"); - - // We will now construct a loader to load a planner, by name. - // Note that we are using the ROS pluginlib library here. - boost::scoped_ptr<pluginlib::ClassLoader<planning_interface::PlannerManager>> planner_plugin_loader; - planning_interface::PlannerManagerPtr planner_instance; - std::string planner_plugin_name; - - // We will get the name of planning plugin we want to load - // from the ROS parameter server, and then load the planner - // making sure to catch all exceptions. - if (!node_handle.getParam("planning_plugin", planner_plugin_name)) - ROS_FATAL_STREAM("Could not find planner plugin name"); - try - { - planner_plugin_loader.reset(new pluginlib::ClassLoader<planning_interface::PlannerManager>( - "moveit_core", "planning_interface::PlannerManager")); - } - catch (pluginlib::PluginlibException& ex) - { - ROS_FATAL_STREAM("Exception while creating planning plugin loader " << ex.what()); - } - try - { - planner_instance.reset(planner_plugin_loader->createUnmanagedInstance(planner_plugin_name)); - if (!planner_instance->initialize(robot_model, node_handle.getNamespace())) - ROS_FATAL_STREAM("Could not initialize planner instance"); - ROS_INFO_STREAM("Using planning interface '" << planner_instance->getDescription() << "'"); - } - catch (pluginlib::PluginlibException& ex) - { - const std::vector<std::string>& classes = planner_plugin_loader->getDeclaredClasses(); - std::stringstream ss; - for (std::size_t i = 0; i < classes.size(); ++i) - ss << classes[i] << " "; - ROS_ERROR_STREAM("Exception while loading planner '" << planner_plugin_name << "': " << ex.what() << std::endl - << "Available plugins: " << ss.str()); - } - - // Visualization - // ^^^^^^^^^^^^^ - // The package MoveItVisualTools provides many capabilities for visualizing objects, robots, - // and trajectories in RViz as well as debugging tools such as step-by-step introspection of a script. - namespace rvt = rviz_visual_tools; - moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0"); - visual_tools.loadRobotStatePub("/display_robot_state"); - visual_tools.enableBatchPublishing(); - visual_tools.deleteAllMarkers(); // clear all old markers - visual_tools.trigger(); - - /* Remote control is an introspection tool that allows users to step through a high level script - via buttons and keyboard shortcuts in RViz */ - visual_tools.loadRemoteControl(); - - /* RViz provides many types of markers, in this demo we will use text, cylinders, and spheres*/ - Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity(); - text_pose.translation().z() = 1.75; - visual_tools.publishText(text_pose, "Motion Planning API Demo", rvt::WHITE, rvt::XLARGE); - - /* Batch publishing is used to reduce the number of messages being sent to RViz for large visualizations */ - visual_tools.trigger(); - - /* We can also use visual_tools to wait for user input */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to start the demo"); - - // Pose Goal - // ^^^^^^^^^ - // We will now create a motion plan request for the arm of the Panda - // specifying the desired pose of the end-effector as input. - visual_tools.publishRobotState(planning_scene->getCurrentStateNonConst(), rviz_visual_tools::GREEN); - visual_tools.trigger(); - planning_interface::MotionPlanRequest req; - planning_interface::MotionPlanResponse res; - geometry_msgs::PoseStamped pose; - pose.header.frame_id = "panda_link0"; - pose.pose.position.x = 0.3; - pose.pose.position.y = 0.4; - pose.pose.position.z = 0.75; - pose.pose.orientation.w = 1.0; - - // A tolerance of 0.01 m is specified in position - // and 0.01 radians in orientation - std::vector<double> tolerance_pose(3, 0.01); - std::vector<double> tolerance_angle(3, 0.01); - - // We will create the request as a constraint using a helper function available - // from the - // `kinematic_constraints`_ - // package. - // - // .. _kinematic_constraints: - // http://docs.ros.org/indigo/api/moveit_core/html/namespacekinematic__constraints.html#a88becba14be9ced36fefc7980271e132 - moveit_msgs::Constraints pose_goal = - kinematic_constraints::constructGoalConstraints("panda_link8", pose, tolerance_pose, tolerance_angle); - - req.group_name = PLANNING_GROUP; - req.goal_constraints.push_back(pose_goal); - - // We now construct a planning context that encapsulate the scene, - // the request and the response. We call the planner using this - // planning context - planning_interface::PlanningContextPtr context = - planner_instance->getPlanningContext(planning_scene, req, res.error_code_); - context->solve(res); - if (res.error_code_.val != res.error_code_.SUCCESS) - { - ROS_ERROR("Could not compute plan successfully"); - return 0; - } - - // Visualize the result - // ^^^^^^^^^^^^^^^^^^^^ - ros::Publisher display_publisher = - node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true); - moveit_msgs::DisplayTrajectory display_trajectory; - - /* Visualize the trajectory */ - moveit_msgs::MotionPlanResponse response; - res.getMessage(response); - - display_trajectory.trajectory_start = response.trajectory_start; - display_trajectory.trajectory.push_back(response.trajectory); - visual_tools.publishTrajectoryLine(display_trajectory.trajectory.back(), joint_model_group); - visual_tools.trigger(); - display_publisher.publish(display_trajectory); - - /* Set the state in the planning scene to the final state of the last plan */ - robot_state->setJointGroupPositions(joint_model_group, response.trajectory.joint_trajectory.points.back().positions); - planning_scene->setCurrentState(*robot_state.get()); - - // Display the goal state - visual_tools.publishRobotState(planning_scene->getCurrentStateNonConst(), rviz_visual_tools::GREEN); - visual_tools.publishAxisLabeled(pose.pose, "goal_1"); - visual_tools.publishText(text_pose, "Pose Goal (1)", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - /* We can also use visual_tools to wait for user input */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); - - // Joint Space Goals - // ^^^^^^^^^^^^^^^^^ - // Now, setup a joint space goal - robot_state::RobotState goal_state(robot_model); - std::vector<double> joint_values = { -1.0, 0.7, 0.7, -1.5, -0.7, 2.0, 0.0 }; - goal_state.setJointGroupPositions(joint_model_group, joint_values); - moveit_msgs::Constraints joint_goal = kinematic_constraints::constructGoalConstraints(goal_state, joint_model_group); - req.goal_constraints.clear(); - req.goal_constraints.push_back(joint_goal); - - // Call the planner and visualize the trajectory - /* Re-construct the planning context */ - context = planner_instance->getPlanningContext(planning_scene, req, res.error_code_); - /* Call the Planner */ - context->solve(res); - /* Check that the planning was successful */ - if (res.error_code_.val != res.error_code_.SUCCESS) - { - ROS_ERROR("Could not compute plan successfully"); - return 0; - } - /* Visualize the trajectory */ - res.getMessage(response); - display_trajectory.trajectory.push_back(response.trajectory); - - /* Now you should see two planned trajectories in series*/ - visual_tools.publishTrajectoryLine(display_trajectory.trajectory.back(), joint_model_group); - visual_tools.trigger(); - display_publisher.publish(display_trajectory); - - /* We will add more goals. But first, set the state in the planning - scene to the final state of the last plan */ - robot_state->setJointGroupPositions(joint_model_group, response.trajectory.joint_trajectory.points.back().positions); - planning_scene->setCurrentState(*robot_state.get()); - - // Display the goal state - visual_tools.publishRobotState(planning_scene->getCurrentStateNonConst(), rviz_visual_tools::GREEN); - visual_tools.publishAxisLabeled(pose.pose, "goal_2"); - visual_tools.publishText(text_pose, "Joint Space Goal (2)", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - /* Wait for user input */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); - - /* Now, we go back to the first goal to prepare for orientation constrained planning */ - req.goal_constraints.clear(); - req.goal_constraints.push_back(pose_goal); - context = planner_instance->getPlanningContext(planning_scene, req, res.error_code_); - context->solve(res); - res.getMessage(response); - - display_trajectory.trajectory.push_back(response.trajectory); - visual_tools.publishTrajectoryLine(display_trajectory.trajectory.back(), joint_model_group); - visual_tools.trigger(); - display_publisher.publish(display_trajectory); - - /* Set the state in the planning scene to the final state of the last plan */ - robot_state->setJointGroupPositions(joint_model_group, response.trajectory.joint_trajectory.points.back().positions); - planning_scene->setCurrentState(*robot_state.get()); - - // Display the goal state - visual_tools.publishRobotState(planning_scene->getCurrentStateNonConst(), rviz_visual_tools::GREEN); - visual_tools.trigger(); - - /* Wait for user input */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); - - // Adding Path Constraints - // ^^^^^^^^^^^^^^^^^^^^^^^ - // Let's add a new pose goal again. This time we will also add a path constraint to the motion. - /* Let's create a new pose goal */ - - pose.pose.position.x = 0.32; - pose.pose.position.y = -0.25; - pose.pose.position.z = 0.65; - pose.pose.orientation.w = 1.0; - moveit_msgs::Constraints pose_goal_2 = - kinematic_constraints::constructGoalConstraints("panda_link8", pose, tolerance_pose, tolerance_angle); - - /* Now, let's try to move to this new pose goal*/ - req.goal_constraints.clear(); - req.goal_constraints.push_back(pose_goal_2); - - /* But, let's impose a path constraint on the motion. - Here, we are asking for the end-effector to stay level*/ - geometry_msgs::QuaternionStamped quaternion; - quaternion.header.frame_id = "panda_link0"; - quaternion.quaternion.w = 1.0; - req.path_constraints = kinematic_constraints::constructGoalConstraints("panda_link8", quaternion); - - // Imposing path constraints requires the planner to reason in the space of possible positions of the end-effector - // (the workspace of the robot) - // because of this, we need to specify a bound for the allowed planning volume as well; - // Note: a default bound is automatically filled by the WorkspaceBounds request adapter (part of the OMPL pipeline, - // but that is not being used in this example). - // We use a bound that definitely includes the reachable space for the arm. This is fine because sampling is not done - // in this volume - // when planning for the arm; the bounds are only used to determine if the sampled configurations are valid. - req.workspace_parameters.min_corner.x = req.workspace_parameters.min_corner.y = - req.workspace_parameters.min_corner.z = -2.0; - req.workspace_parameters.max_corner.x = req.workspace_parameters.max_corner.y = - req.workspace_parameters.max_corner.z = 2.0; - - // Call the planner and visualize all the plans created so far. - context = planner_instance->getPlanningContext(planning_scene, req, res.error_code_); - context->solve(res); - res.getMessage(response); - display_trajectory.trajectory.push_back(response.trajectory); - visual_tools.publishTrajectoryLine(display_trajectory.trajectory.back(), joint_model_group); - visual_tools.trigger(); - display_publisher.publish(display_trajectory); - - /* Set the state in the planning scene to the final state of the last plan */ - robot_state->setJointGroupPositions(joint_model_group, response.trajectory.joint_trajectory.points.back().positions); - planning_scene->setCurrentState(*robot_state.get()); - - // Display the goal state - visual_tools.publishRobotState(planning_scene->getCurrentStateNonConst(), rviz_visual_tools::GREEN); - visual_tools.publishAxisLabeled(pose.pose, "goal_3"); - visual_tools.publishText(text_pose, "Orientation Constrained Motion Plan (3)", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - // END_TUTORIAL - /* Wait for user input */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to exit the demo"); - planner_instance.reset(); - - return 0; -} diff --git a/src/tutorial/move_group_interface_tutorial.cpp b/src/tutorial/move_group_interface_tutorial.cpp deleted file mode 100644 index c61ef2c42fc984f1329340ea4a18c951088e58b6..0000000000000000000000000000000000000000 --- a/src/tutorial/move_group_interface_tutorial.cpp +++ /dev/null @@ -1,409 +0,0 @@ -/********************************************************************* - * Software License Agreement (BSD License) - * - * Copyright (c) 2013, SRI International - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of SRI International nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *********************************************************************/ - -/* Author: Sachin Chitta, Dave Coleman, Mike Lautman */ - -#include <moveit/move_group_interface/move_group_interface.h> -#include <moveit/planning_scene_interface/planning_scene_interface.h> - -#include <moveit_msgs/DisplayRobotState.h> -#include <moveit_msgs/DisplayTrajectory.h> - -#include <moveit_msgs/AttachedCollisionObject.h> -#include <moveit_msgs/CollisionObject.h> - -#include <moveit_visual_tools/moveit_visual_tools.h> - -int main(int argc, char** argv) -{ - ros::init(argc, argv, "move_group_interface_tutorial"); - ros::NodeHandle node_handle; - ros::AsyncSpinner spinner(1); - spinner.start(); - - // BEGIN_TUTORIAL - // - // Setup - // ^^^^^ - // - // MoveIt operates on sets of joints called "planning groups" and stores them in an object called - // the `JointModelGroup`. Throughout MoveIt the terms "planning group" and "joint model group" - // are used interchangably. - static const std::string PLANNING_GROUP = "panda_arm"; - - // The :planning_interface:`MoveGroupInterface` class can be easily - // setup using just the name of the planning group you would like to control and plan for. - moveit::planning_interface::MoveGroupInterface move_group(PLANNING_GROUP); - - // We will use the :planning_interface:`PlanningSceneInterface` - // class to add and remove collision objects in our "virtual world" scene - moveit::planning_interface::PlanningSceneInterface planning_scene_interface; - - // Raw pointers are frequently used to refer to the planning group for improved performance. - const robot_state::JointModelGroup* joint_model_group = - move_group.getCurrentState()->getJointModelGroup(PLANNING_GROUP); - - // Visualization - // ^^^^^^^^^^^^^ - // - // The package MoveItVisualTools provides many capabilities for visualizing objects, robots, - // and trajectories in RViz as well as debugging tools such as step-by-step introspection of a script. - namespace rvt = rviz_visual_tools; - moveit_visual_tools::MoveItVisualTools visual_tools("panda_link0"); - visual_tools.deleteAllMarkers(); - - // Remote control is an introspection tool that allows users to step through a high level script - // via buttons and keyboard shortcuts in RViz - visual_tools.loadRemoteControl(); - - // RViz provides many types of markers, in this demo we will use text, cylinders, and spheres - Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity(); - text_pose.translation().z() = 1.75; - visual_tools.publishText(text_pose, "MoveGroupInterface Demo", rvt::WHITE, rvt::XLARGE); - - // Batch publishing is used to reduce the number of messages being sent to RViz for large visualizations - visual_tools.trigger(); - - // Getting Basic Information - // ^^^^^^^^^^^^^^^^^^^^^^^^^ - // - // We can print the name of the reference frame for this robot. - ROS_INFO_NAMED("tutorial", "Planning frame: %s", move_group.getPlanningFrame().c_str()); - - // We can also print the name of the end-effector link for this group. - ROS_INFO_NAMED("tutorial", "End effector link: %s", move_group.getEndEffectorLink().c_str()); - - // We can get a list of all the groups in the robot: - ROS_INFO_NAMED("tutorial", "Available Planning Groups:"); - std::copy(move_group.getJointModelGroupNames().begin(), move_group.getJointModelGroupNames().end(), - std::ostream_iterator<std::string>(std::cout, ", ")); - - // Start the demo - // ^^^^^^^^^^^^^^^^^^^^^^^^^ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to start the demo"); - - // Planning to a Pose goal - // ^^^^^^^^^^^^^^^^^^^^^^^ - // We can plan a motion for this group to a desired pose for the - // end-effector. - geometry_msgs::Pose target_pose1; - target_pose1.orientation.w = 1.0; - target_pose1.position.x = 0.28; - target_pose1.position.y = -0.2; - target_pose1.position.z = 0.5; - move_group.setPoseTarget(target_pose1); - - // Now, we call the planner to compute the plan and visualize it. - // Note that we are just planning, not asking move_group - // to actually move the robot. - moveit::planning_interface::MoveGroupInterface::Plan my_plan; - - bool success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS); - - ROS_INFO_NAMED("tutorial", "Visualizing plan 1 (pose goal) %s", success ? "" : "FAILED"); - - // Visualizing plans - // ^^^^^^^^^^^^^^^^^ - // We can also visualize the plan as a line with markers in RViz. - ROS_INFO_NAMED("tutorial", "Visualizing plan 1 as trajectory line"); - visual_tools.publishAxisLabeled(target_pose1, "pose1"); - visual_tools.publishText(text_pose, "Pose Goal", rvt::WHITE, rvt::XLARGE); - visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group); - visual_tools.trigger(); - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); - - // Moving to a pose goal - // ^^^^^^^^^^^^^^^^^^^^^ - // - // Moving to a pose goal is similar to the step above - // except we now use the move() function. Note that - // the pose goal we had set earlier is still active - // and so the robot will try to move to that goal. We will - // not use that function in this tutorial since it is - // a blocking function and requires a controller to be active - // and report success on execution of a trajectory. - - /* Uncomment below line when working with a real robot */ - move_group.move(); - - // Planning to a joint-space goal - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // - // Let's set a joint space goal and move towards it. This will replace the - // pose target we set above. - // - // To start, we'll create an pointer that references the current robot's state. - // RobotState is the object that contains all the current position/velocity/acceleration data. - moveit::core::RobotStatePtr current_state = move_group.getCurrentState(); - // - // Next get the current set of joint values for the group. - std::vector<double> joint_group_positions; - current_state->copyJointGroupPositions(joint_model_group, joint_group_positions); - - // Now, let's modify one of the joints, plan to the new joint space goal and visualize the plan. - joint_group_positions[0] = -1.0; // radians - move_group.setJointValueTarget(joint_group_positions); - - // We lower the allowed maximum velocity and acceleration to 5% of their maximum. - // The default values are 10% (0.1). - // Set your preferred defaults in the joint_limits.yaml file of your robot's moveit_config - // or set explicit factors in your code if you need your robot to move faster. - move_group.setMaxVelocityScalingFactor(0.05); - move_group.setMaxAccelerationScalingFactor(0.05); - - success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS); - ROS_INFO_NAMED("tutorial", "Visualizing plan 2 (joint space goal) %s", success ? "" : "FAILED"); - - // Visualize the plan in RViz - visual_tools.deleteAllMarkers(); - visual_tools.publishText(text_pose, "Joint Space Goal", rvt::WHITE, rvt::XLARGE); - visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group); - visual_tools.trigger(); - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); - - // Planning with Path Constraints - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // - // Path constraints can easily be specified for a link on the robot. - // Let's specify a path constraint and a pose goal for our group. - // First define the path constraint. - moveit_msgs::OrientationConstraint ocm; - ocm.link_name = "panda_link7"; - ocm.header.frame_id = "panda_link0"; - ocm.orientation.w = 1.0; - ocm.absolute_x_axis_tolerance = 0.1; - ocm.absolute_y_axis_tolerance = 0.1; - ocm.absolute_z_axis_tolerance = 0.1; - ocm.weight = 1.0; - - // Now, set it as the path constraint for the group. - moveit_msgs::Constraints test_constraints; - test_constraints.orientation_constraints.push_back(ocm); - move_group.setPathConstraints(test_constraints); - - // We will reuse the old goal that we had and plan to it. - // Note that this will only work if the current state already - // satisfies the path constraints. So we need to set the start - // state to a new pose. - robot_state::RobotState start_state(*move_group.getCurrentState()); - geometry_msgs::Pose start_pose2; - start_pose2.orientation.w = 1.0; - start_pose2.position.x = 0.55; - start_pose2.position.y = -0.05; - start_pose2.position.z = 0.8; - start_state.setFromIK(joint_model_group, start_pose2); - move_group.setStartState(start_state); - - // Now we will plan to the earlier pose target from the new - // start state that we have just created. - move_group.setPoseTarget(target_pose1); - - // Planning with constraints can be slow because every sample must call an inverse kinematics solver. - // Lets increase the planning time from the default 5 seconds to be sure the planner has enough time to succeed. - move_group.setPlanningTime(10.0); - - success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS); - - move_group.move(); - - ROS_INFO_NAMED("tutorial", "Visualizing plan 3 (constraints) %s", success ? "" : "FAILED"); - - // Visualize the plan in RViz - visual_tools.deleteAllMarkers(); - visual_tools.publishAxisLabeled(start_pose2, "start"); - visual_tools.publishAxisLabeled(target_pose1, "goal"); - visual_tools.publishText(text_pose, "Constrained Goal", rvt::WHITE, rvt::XLARGE); - visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group); - visual_tools.trigger(); - visual_tools.prompt("next step"); - - // When done with the path constraint be sure to clear it. - move_group.clearPathConstraints(); - - // Cartesian Paths - // ^^^^^^^^^^^^^^^ - // You can plan a Cartesian path directly by specifying a list of waypoints - // for the end-effector to go through. Note that we are starting - // from the new start state above. The initial pose (start state) does not - // need to be added to the waypoint list but adding it can help with visualizations - std::vector<geometry_msgs::Pose> waypoints; - waypoints.push_back(start_pose2); - - geometry_msgs::Pose target_pose3 = start_pose2; - - target_pose3.position.z -= 0.2; - waypoints.push_back(target_pose3); // down - - target_pose3.position.y -= 0.2; - waypoints.push_back(target_pose3); // right - - target_pose3.position.z += 0.2; - target_pose3.position.y += 0.2; - target_pose3.position.x -= 0.2; - waypoints.push_back(target_pose3); // up and left - - // We want the Cartesian path to be interpolated at a resolution of 1 cm - // which is why we will specify 0.01 as the max step in Cartesian - // translation. We will specify the jump threshold as 0.0, effectively disabling it. - // Warning - disabling the jump threshold while operating real hardware can cause - // large unpredictable motions of redundant joints and could be a safety issue - moveit_msgs::RobotTrajectory trajectory; - const double jump_threshold = 0.0; - const double eef_step = 0.01; - double fraction = move_group.computeCartesianPath(waypoints, eef_step, jump_threshold, trajectory); - ROS_INFO_NAMED("tutorial", "Visualizing plan 4 (Cartesian path) (%.2f%% acheived)", fraction * 100.0); - - // Visualize the plan in RViz - visual_tools.deleteAllMarkers(); - visual_tools.publishText(text_pose, "Cartesian Path", rvt::WHITE, rvt::XLARGE); - visual_tools.publishPath(waypoints, rvt::LIME_GREEN, rvt::SMALL); - for (std::size_t i = 0; i < waypoints.size(); ++i) - visual_tools.publishAxisLabeled(waypoints[i], "pt" + std::to_string(i), rvt::SMALL); - visual_tools.trigger(); - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to continue the demo"); - - // Cartesian motions should often be slow, e.g. when approaching objects. The speed of cartesian - // plans cannot currently be set through the maxVelocityScalingFactor, but requires you to time - // the trajectory manually, as described [here](https://groups.google.com/forum/#!topic/moveit-users/MOoFxy2exT4). - // Pull requests are welcome. - - // You can execute a trajectory by wrapping it in a plan like this. - moveit::planning_interface::MoveGroupInterface::Plan cartesian_plan; - cartesian_plan.trajectory_ = trajectory; - move_group.execute(cartesian_plan); - - // Adding/Removing Objects and Attaching/Detaching Objects - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // - // Define a collision object ROS message. - moveit_msgs::CollisionObject collision_object; - collision_object.header.frame_id = move_group.getPlanningFrame(); - - // The id of the object is used to identify it. - collision_object.id = "box1"; - - // Define a box to add to the world. - shape_msgs::SolidPrimitive primitive; - primitive.type = primitive.BOX; - primitive.dimensions.resize(3); - primitive.dimensions[0] = 0.4; - primitive.dimensions[1] = 0.1; - primitive.dimensions[2] = 0.4; - - // Define a pose for the box (specified relative to frame_id) - geometry_msgs::Pose box_pose; - box_pose.orientation.w = 1.0; - box_pose.position.x = 0.4; - box_pose.position.y = -0.2; - box_pose.position.z = 1.0; - - collision_object.primitives.push_back(primitive); - collision_object.primitive_poses.push_back(box_pose); - collision_object.operation = collision_object.ADD; - - std::vector<moveit_msgs::CollisionObject> collision_objects; - collision_objects.push_back(collision_object); - - // Now, let's add the collision object into the world - ROS_INFO_NAMED("tutorial", "Add an object into the world"); - planning_scene_interface.addCollisionObjects(collision_objects); - - // Show text in RViz of status - visual_tools.publishText(text_pose, "Add object", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - // Wait for MoveGroup to receive and process the collision object message - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object appears in RViz"); - - // Now when we plan a trajectory it will avoid the obstacle - move_group.setStartState(*move_group.getCurrentState()); - geometry_msgs::Pose another_pose; - another_pose.orientation.w = 1.0; - another_pose.position.x = 0.4; - another_pose.position.y = -0.4; - another_pose.position.z = 0.9; - move_group.setPoseTarget(another_pose); - - success = (move_group.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS); - ROS_INFO_NAMED("tutorial", "Visualizing plan 5 (pose goal move around cuboid) %s", success ? "" : "FAILED"); - - // Visualize the plan in RViz - visual_tools.deleteAllMarkers(); - visual_tools.publishText(text_pose, "Obstacle Goal", rvt::WHITE, rvt::XLARGE); - visual_tools.publishTrajectoryLine(my_plan.trajectory_, joint_model_group); - visual_tools.trigger(); - visual_tools.prompt("next step"); - - // Now, let's attach the collision object to the robot. - ROS_INFO_NAMED("tutorial", "Attach the object to the robot"); - move_group.attachObject(collision_object.id); - - // Show text in RViz of status - visual_tools.publishText(text_pose, "Object attached to robot", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - /* Wait for MoveGroup to receive and process the attached collision object message */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object attaches to the " - "robot"); - - // Now, let's detach the collision object from the robot. - ROS_INFO_NAMED("tutorial", "Detach the object from the robot"); - move_group.detachObject(collision_object.id); - - // Show text in RViz of status - visual_tools.publishText(text_pose, "Object dettached from robot", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - /* Wait for MoveGroup to receive and process the attached collision object message */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object detaches to the " - "robot"); - - // Now, let's remove the collision object from the world. - ROS_INFO_NAMED("tutorial", "Remove the object from the world"); - std::vector<std::string> object_ids; - object_ids.push_back(collision_object.id); - planning_scene_interface.removeCollisionObjects(object_ids); - - // Show text in RViz of status - visual_tools.publishText(text_pose, "Object removed", rvt::WHITE, rvt::XLARGE); - visual_tools.trigger(); - - /* Wait for MoveGroup to receive and process the attached collision object message */ - visual_tools.prompt("Press 'next' in the RvizVisualToolsGui window to once the collision object disapears"); - - // END_TUTORIAL - - ros::shutdown(); - return 0; -} diff --git a/src/util/MqttUtil.cpp b/src/util/MqttUtil.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0f9459fa0ccc20a67564d14e0ad6fe943a74a09 --- /dev/null +++ b/src/util/MqttUtil.cpp @@ -0,0 +1,59 @@ +// +// Created by Johannes Mey on 01.06.20. +// + +#include "MqttUtil.h" + +#include "ros/ros.h" + +bool MqttUtil::connect() { + try { + if (!client.is_connected()) { + ROS_INFO_NAMED("MqttUtil", "Initializing MQTT"); + mqtt::connect_options connOpts; + connOpts.set_keep_alive_interval(20); + connOpts.set_clean_session(false); + ROS_INFO_NAMED("MqttUtil", "MQTT initialized. Connecting..."); + auto rsp = client.connect(connOpts); + if (!rsp.is_session_present()) { + client.subscribe(topics); + return true; + } + ROS_INFO_NAMED("MqttUtil", "Connection established."); + } else { + ROS_WARN_NAMED("MqttUtil", "Client is already connected."); + return true; + } + } catch (const mqtt::exception &) { std::this_thread::sleep_for(std::chrono::seconds(1)); } + return false; +} + +bool MqttUtil::ensureConnection() { + constexpr int N_ATTEMPT = 30; + + if (!client.is_connected()) { + ROS_WARN_STREAM_NAMED("MqttUtil", "Lost connection. Reconnecting..."); + for (int i = 0; i < N_ATTEMPT && !client.is_connected(); ++i) { + try { + auto rsp = client.reconnect(); + if (!rsp.is_session_present()) { + client.subscribe(topics); + } + ROS_WARN_STREAM_NAMED("MqttUtil", "Reconnection succeeded!"); + return true; + } catch (const mqtt::exception &) { std::this_thread::sleep_for(std::chrono::seconds(1)); } + } + ROS_ERROR_STREAM_NAMED("MqttUtil", "Reconnection failed!"); + return false; + } + return true; +} + +const mqtt::string_collection &MqttUtil::getTopics() const { return topics; } + +void MqttUtil::addTopic(std::string topic) { topics.push_back(topic); } + +MqttUtil::MqttUtil(std::string client_id, std::string server) : topics(), client(server, client_id) {} + +MqttUtil::~MqttUtil() { client.disconnect(); } +mqtt::client &MqttUtil::getClient() { return client; } diff --git a/src/util/MqttUtil.h b/src/util/MqttUtil.h new file mode 100644 index 0000000000000000000000000000000000000000..81fe1749a3e0941876014e06e12bff37af9e5e1b --- /dev/null +++ b/src/util/MqttUtil.h @@ -0,0 +1,32 @@ +// +// Created by Johannes Mey on 01.06.20. +// + +#ifndef PANDA_MQTT_CONNECTOR_MQTTUTIL_H +#define PANDA_MQTT_CONNECTOR_MQTTUTIL_H + +#include <mqtt/async_client.h> +#include <mqtt/client.h> + +const std::string DEFAULT_SERVER_ADDRESS{"tcp://localhost:1883"}; + +class MqttUtil { + +private: + mqtt::client client; + mqtt::string_collection topics; + +public: + MqttUtil(std::string client_id, std::string server = DEFAULT_SERVER_ADDRESS); + const mqtt::string_collection &getTopics() const; + void addTopic(std::string topic); + + mqtt::client &getClient(); + + bool connect(); + + bool ensureConnection(); + virtual ~MqttUtil(); +}; + +#endif // PANDA_MQTT_CONNECTOR_MQTTUTIL_H