HOW TO – moveit snippets
Warning
this documents needs to be reviewed. The code here could not work, but the overall structure is correct.
Contents
- HOW TO – moveit snippets
- headers and Setup
- A MoveIt OOP pattern for ROS1
- MoveIt – ROS1 C++ snippets
- Move Group Interface Settings
- Just move that!
- Move to a preset pose
- Single Waypoint Path – MoveIt with explicit planning
- Single Waypoint Path – Planning in the Joint Space (first way)
- planning in the joint space (second method)
- Multiple Waypoints Path – Motion using Cartesian Paths
- Movement Constraints
- Easy queries
- Useful Links
headers and Setup
Basic
The most simple set of headers:
#include <ros/ros.h>
#include <moveit/move_group_interface/move_group_interface.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
a more comprehensive set of headers, see also RViz visualization tools:
#include <ros/ros.h>
#include <moveit/move_group_interface/move_group_interface.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit_visual_tools/moveit_visual_tools.h>
#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>
#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>
compile with catkin
just add these dependencies:
find_package(catkin REQUIRED COMPONENTS
roscpp
...
moveit_msgs
moveit_core
moveit_ros_perception
moveit_ros_planning
moveit_ros_planning_interface
)
Init the node with AsyncSpin
It is mandatory in order to call the methods for the robo movement.
// run the node as AsyncSpinner
// ros::init( ... )
// ros::AsyncSpinner spinner( n_threads );
ros::AsyncSpinner spinner(1);
spinner.start( );
// spin becomes...
ros::waitForShutdown( );
Remember to use AsyncSpin!
A MoveIt OOP pattern for ROS1
?? remember to replace ???
with a name suitable for your implementation!
Feel free to structure the workflow of the node using this first model, ready to be tailored to the desired functionalities.
#include "ros/ros.h"
#include <signal.h>
#include <string>
#define NODE_NAME ???
#include <moveit/move_group_interface/move_group_interface.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit_visual_tools/moveit_visual_tools.h>
#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>
#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>
#define LOGSQUARE( str ) "[" << str << "] "
#define OUTLABEL LOGSQUARE( NODE_NAME )
#define TLOG( msg ) ROS_INFO_STREAM( OUTLABEL << msg )
#define TWARN( msg ) ROS_WARN_STREAM( OUTLABEL << "WARNING: " << msg )
#define TERR( msg ) ROS_WARN_STREAM( OUTLABEL << "ERROR: " << msg )
class ???
{
public:
???( std::string group_name ) :
planning_group( group_name )
{
// init MoveIt groups
static const std::string PLANNING_GROUP = "panda_arm";
mgi = move_group_interface(PLANNING_GROUP);
// MoveIt settings
mgi.setPlanningTime(10.0);
// ...
}
void spin( int n_loops_per_sec = 1 )
{
// TODO main functionality (even a simple spin)
/*
ros::spin( )
*/
/*
ros::Rate freq( n_loops_per_sec );
while( ros::ok( ) )
{
// ... do whatever you want
// spin and wait
ros::spin_once( );
freq.sleep( );
}
*/
}
// other ModeIt specific functionalities
// ...
// ...
private:
// ROS node handle
ros::NodeHandle nh;
// moveIt group name
std::string planning_group;
// planning interface
moveit::planning_interface::MoveGroupInterface mgi;
// previously generated plan
moveit::planning_interface::MoveGroupInterface::Plan plan;
// ...
}
void shut_msg( )
{
TLOG( "stopping... " );
ros::shutdown( );
}
int main( int argc, char* argv[] )
{
ros::init( argc, argv, NODE_NAME, ros::init_options::NoSigintHandler );
signal( SIGINT, shut_msg );
ros::NodeHandle nh;
// required by moveIt: run the node as AsyncSpinner
ros::AsyncSpinner spinner(1);
spinner.start( );
TLOG( "starting ... " );
// TODO define here services and topics ...
TLOG( "ready" );
// TODO the functionality of the node ...
( ???( ) ).spin( );
return 0;
}
MoveIt – ROS1 C++ snippets
Feel free to go deeper into the details of code, and to combine the snippets. Each snippet incude a particular feature, which can be joined with the other ones in order to create the entire application.
Move Group Interface Settings
?? You can find many other options here.
Here are only the most common properties you maybe want to explicitly set for the move group interface. Inside the above mentioned page you can find also the getters, as well as many other useful options.
static const std::string PLANNING_GROUP = "your_planning_group";
moveit::planning_interface::MoveGroupInterface group(PLANNING_GROUP);
// also the "get" are available for these methods
group.setEndEffectorLink("end_effector_link");
group.setPoseReferenceFrame("base_link");
group.setPlannerId("RRTstar");
group.setNumPlanningAttempts(10);
group.setPlanningTime(10.0);
group.allowReplanning(true);
group.setGoalJointTolerance(0.0001);
group.setGoalPositionTolerance(0.0001);
group.setGoalOrientationTolerance(0.001);
Just move that!
Notice that .move()
and .execute(my_plan)
are blocking calls, and the snippets here don’t allow to fix a sequence of movements, hence you should manually create a loop for reaching a sequnce of poses.
Also notice that the MoveIt code is often executed by a specific module, hence a blocking call is accettable in many cases, without loosing parallelism between planning and movement. In particular, if you want to have a non-blocking interface, a good idea could be to create a service in another node, and every time ask the state of the robot to it.
In case you really need non-blocking calls, consider to use asyncExecute
.
// STEP 1 -- reference to the group to move
// (the model is loaded from the parameter server)
static const std::string PLANNING_GROUP = "panda_arm";
moveit::planning_interface::MoveGroupInterface move_group_interface(PLANNING_GROUP);
// STEP 2 -- declare the final pose of 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_interface.setPoseTarget(target_pose1);
// AND FINALLY MOVE THAT!
move_group_interface.move(); // blocking
Move to a preset pose
very simple: just use group.setNamedTarget("your_pose_name");
to set the target.
Single Waypoint Path – MoveIt with explicit planning
This snippet doesn’t specify in which space the planner has to work. If you want specifically cartesian planning or joint space planning, go to the other snippets.
// STEP 1 -- ...
// STEP 2 -- ...
// STEP 3 -- planning
moveit::planning_interface::MoveGroupInterface::Plan my_plan;
// you can set a timeout for the planning using .setPlanningTime
// default is 5
move_group_interface.setPlanningTime(10.0);
// plan
bool success = (
move_group_interface.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
// AND FINALLY MOVE THAT!
move_group_interface.execute(my_plan); // blocking
Single Waypoint Path – Planning in the Joint Space (first way)
This piece of code allows to move the group in the neighborhood of the current configuration:
// STEP 1 -- ...
// STEP 2a -- current cofiguration and next configuration
moveit::core::RobotStatePtr current_state = move_group_interface.getCurrentState();
std::vector<double> joint_group_positions;
current_state->copyJointGroupPositions(joint_model_group, joint_group_positions);
// STEP 2b -- set the next configuration
// joint_group_positions[0] = ...
move_group_interface.setJointValueTarget(joint_group_positions);
// STEP 3 -- set movement constraints
move_group_interface.setMaxVelocityScalingFactor(0.05);
move_group_interface.setMaxAccelerationScalingFactor(0.05);
// AND FINALLY MOVE THAT!
// (here you can use move() as well)
moveit::planning_interface::MoveGroupInterface::Plan my_plan;
bool success = (
move_group_interface.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
move_group_interface.execute(my_plan); // blocking
planning in the joint space (second method)
This method explicitly involves the Inverse Kinematin in order to plan the path. It’s preferrable when you want to override any unknown MoveIt settings in the system you’re using for your project, i.e. when you don’t know which default planning is set.
// STEP 1 -- set the starting pose of the tip
geometry_msgs::Pose start_pose;
start_pose.orientation.w = 1.0;
start_pose.position.x = 0.55;
start_pose.position.y = -0.05;
start_pose.position.z = 0.8;
// STEP 2 -- set the target pose
geometry_msgs::Pose target_pose;
// ... setup the target pose ...
// STEP 3a -- setup the IK
const moveit::core::JointModelGroup* joint_model_group =
move_group_interface.getCurrentState()->getJointModelGroup(PLANNING_GROUP);
moveit::core::RobotStatePtr current_joint_state =
*move_group_interface.getCurrentState();
moveit::core::RobotState start_state( current_joint_state );
// STEP 3b -- start pose and target pose
start_state.setFromIK( joint_model_group, start_pose );
move_group_interface.setStartState( start_state ); // the IK is passed to the interface here
move_group_interface.setPoseTarget( target_pose );
// STEP 4 -- explicit planning
// (but I think that even the implicit planning + movement
// should work well here)
move_group_interface.setPlanningTime(10.0); // suggested, not mandatory
success =
(move_group_interface.plan(my_plan) == moveit::planning_interface::MoveItErrorCode::SUCCESS);
ROS_INFO("plan %s", success ? "" : "FAILED");
// AND FINALLY MOVE THAT!
move_group_interface.execute(my_plan);
Multiple Waypoints Path – Motion using Cartesian Paths
The cartesian path allows to move the robot across many waypoints. Each waypoint is a pose message; to express a path, build a std::vector<geometry_msgs::Pose>
and .push_back()
each intermediate waypoint.
// STEP 1 -- waypoints
std::vector<geometry_msgs::Pose> waypoints;
// good practise: always specify the starting pose
geometry_msgs::Pose w0;
// ... .x .y .z
waypoints.push_back( w0 );
// then specify each other waypoint
geometry_msgs::Pose w1;
// ... .x .y .z
waypoints.push_back( w1 );
// STEP 2 -- plan the trajectory
moveit_msgs::RobotTrajectory trajectory;
const double jump_threshold = 0.0;
const double eef_step = 0.01;
double fraction = move_group_interface.computeCartesianPath(
waypoints, eef_step, jump_threshold, trajectory); // trajectory out by reference
// AND FINALLY MOVE THAT!
move_group_interface.execute(trajectory);
Movement Constraints
Adding constraints to the robot movement is quite straightforward: just fill in the message moveit_msgs/Constraints
with the constraints you want for the motion, then set the constraints in the proper set with .push_back( constraint_instance )
and confirm with move_group_interface.setPathConstraints( constraints_msg )
.
Here’s a simple example:
// STEP 1 -- set the constraints as single messages
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;
// STEP 2 -- create the set of constraints
moveit_msgs::Constraints test_constraints;
test_constraints.orientation_constraints.push_back(ocm);
// STEP 3 -- make them effective
move_group_interface.setPathConstraints(test_constraints);
Here are the links to the messages:
The main message: moveit_msgs/Constraints.msg
Every time you need a particular constraint, the method is always the same: just scroll the list above, and select the constraints you want.
Easy queries
// current planning frame
ROS_INFO("Planning frame: %s", move_group_interface.getPlanningFrame().c_str());
// name of the end effector
ROS_INFO("End effector link: %s", move_group_interface.getEndEffectorLink().c_str());
// list of all defined groups
ROS_INFO("Available Planning Groups:");
std::copy(move_group_interface.getJointModelGroupNames().begin(),
move_group_interface.getJointModelGroupNames().end(),
std::ostream_iterator<std::string>(std::cout, ", "));
Useful Links
moveit planning interface reference class here
C++ reference for the class
ros::AsyncSpinner
Official (awful) documentation about MoveIt for ROS1
An example of MoveIt cpp implementation: source code
here the main page of moveit_tutorials on GitHub
Planning error codes
moveit::planning_interface::MoveGroupInterface::setJointValueTarget
-moveit::planning_interface::MoveGroupInterface
for non-blocking
move()
, seeasyncExecute
list of messages in the moveit_msgs package, in particular moveit_msgs/Constraints msg