0.前言

我在上一篇博文07轨迹规划仿真中实现PTP的轨迹规划,并且把圆弧轨迹规划的坑挖好了,但是我一直很难受的地方就是终端的轨迹显示,我之前解释了我实习UR10moveit控制的方式,是使用官方panda的教程进行修改,但是panda的教程是可以用绿色轨迹线显示轨迹的,这篇blog我想处理一下这个问题。

感谢博主的文章,激发我的灵感

https://blog.csdn.net/gophae/article/details/108514336

1.解读参考博客的代码

#include <ros/ros.h>
#include <ros/console.h>
#include <nav_msgs/Path.h>
#include <std_msgs/String.h>
#include <geometry_msgs/Quaternion.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/PointStamped.h>
#include <tf/transform_broadcaster.h>
#include <tf/tf.h>
#include <cstdlib>

main(int argc, char **argv)
{
    ros::init(argc, argv, "showpath");
    ros::NodeHandle ph;
    ros::Publisher path_pub = ph.advertise<nav_msgs::Path>("trajectory", 1, true);//关键代码1  出现轨迹
    ros::Publisher point_pub = ph.advertise<geometry_msgs::PointStamped>("point", 1, true);//关键代码2  出现point点
    //这三行貌似是处理时间问题,我觉得他和我的轨迹轨迹时间戳需要共用
    ros::Time current_time, last_time;
    current_time = ros::Time::now();
    last_time = ros::Time::now();

    nav_msgs::Path path;//定义path

    //nav_msgs::Path path
    path.header.stamp = current_time;
    path.header.frame_id = "odom";

    double x = 0.0;
    double y = 0.0;
    double z = 0.0;
    double th = 0.0;
    double vx = 0.1 + 0.2 * rand() / double(RAND_MAX);
    double vy = -0.1 + 0.2 * rand() / double(RAND_MAX);
    double vth = 0.1;

    ros::Rate loop_rate(10);
    while (ros::ok())
    {

        current_time = ros::Time::now();
        //compute odometry in a typical way given the velocities of the robot
        double dt = 1;
        double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
        double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
        double delta_th = vth * dt;

        x += delta_x;
        y += delta_y;
        z += 0.005;
        th += delta_th;

        geometry_msgs::PoseStamped this_pose_stamped;
        geometry_msgs::PointStamped this_point_stamped;

        this_pose_stamped.pose.position.x = x;
        this_pose_stamped.pose.position.y = y;
        this_pose_stamped.pose.position.z = z;

        this_point_stamped.header.stamp = current_time;
        this_point_stamped.header.frame_id = "odom";
        this_point_stamped.point.x = x;
        this_point_stamped.point.y = y;
        this_point_stamped.point.z = z;
        ROS_INFO("current_x: %f", x);
        ROS_INFO("current_y: %f", y);
        geometry_msgs::Quaternion goal_quat = tf::createQuaternionMsgFromYaw(th);
        this_pose_stamped.pose.orientation.x = goal_quat.x;
        this_pose_stamped.pose.orientation.y = goal_quat.y;
        this_pose_stamped.pose.orientation.z = goal_quat.z;
        this_pose_stamped.pose.orientation.w = goal_quat.w;

        this_pose_stamped.header.stamp = current_time;
        this_pose_stamped.header.frame_id = "odom";
        path.poses.push_back(this_pose_stamped);//关键代码
        path_pub.publish(path);//关键代码
        point_pub.publish(this_point_stamped);
        ros::spinOnce(); // check for incoming messages

        last_time = current_time;
        loop_rate.sleep();
    }

    return 0;
}

2.设置rviz界面

实时显示轨迹的中心思想:就是在代码中publish一个/trajectory 的topic ,然后在rviz中将其调用显示
设置rviz的界面流程参考:
//一定要去看

https://blog.csdn.net/gophae/article/details/108514336
和上文是同一个博客

tip:这个位置我打开了rviz面板功能的新世界的大门!我之前想看joint数组要去终端用rostopic 我真是~笨死了!

3.更改UR10轨迹规划的cpp文件

插曲:我思考了一下,更改cpp的目的,就是想要一个topic,包含末端位置和时间戳,我觉得moveit肯定发布了这个话题,只不过我没有合理使用他,所以我打算试一下

cd ~/ws_moveit
source ./devel/setup.bash
roslaunch ur10_moveit_config demo.launch
新的tab
cd ~/ws_moveit
source ./devel/setup.bash
roslaunch moveit_tutorials move_group_interface_tutorial.launch
新的tab
rqt_graph
然后查看这些话题谁最“可疑”
我最后选定了
rostopic echo /place/status
运行结果:
header:
seq: 2068
stamp:
secs: 1613531538
nsecs: 409575573
frame_id: ‘’
status_list: []
我发现只有时间戳,没有位置信息
对比一下参考博客中的/trajectory
header:
seq: 0
stamp:
secs: 1613533245
nsecs: 30911903
frame_id: “odom”
pose:
position:
x: -1.75693075225
y: 4.34585964254
z: 1.465
orientation:
x: -0.0
y: 0.0
z: 0.87135797221
w: -0.490647821015

#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 <ros/ros.h>
#include <ros/console.h>
#include <nav_msgs/Path.h>
#include <std_msgs/String.h>
#include <geometry_msgs/Quaternion.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/PointStamped.h>
#include <tf/transform_broadcaster.h>
#include <tf/tf.h>
#include <cstdlib>


int main(int argc, char** argv)
{
  
  ros::init(argc, argv, "move_group_interface_ur10_circle");
  ros::NodeHandle node_handle;
  ros::Publisher path_pub = node_handle.advertise<nav_msgs::Path>("trajectory", 1, true);//path
  ros::Time current_time, last_time;//path
  current_time = ros::Time::now();//path
  last_time = ros::Time::now();//path
  nav_msgs::Path path;//path
  //nav_msgs::Path path;
  path.header.stamp = current_time;//path
  path.header.frame_id = "base_link";//path
  double x = 0.0;//path
  int i = 0;//path
  double y = 0.0;//path
  double z = 0.0;//path
  double th = 0.0;//path
  double vx = 0.1 + 0.2 * rand() / double(RAND_MAX);//path
  double vy = -0.1 + 0.2 * rand() / double(RAND_MAX);//path
  double vth = 0.1;//path
  ros::AsyncSpinner spinner(1);
  spinner.start();
  ///将“manipulator”储存在joint_model_group中 
  static const std::string PLANNING_GROUP = "manipulator";
  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
  // ^^^^^^^^^^^^^
  //可视化部分包括对象、机器人、轨迹的显示
  namespace rvt = rviz_visual_tools;
  moveit_visual_tools::MoveItVisualTools visual_tools("base_link");
  visual_tools.deleteAllMarkers();
  //远程控制是一种自省工具,允许用户通过RViz中的按钮和键盘快捷键逐步完成高级脚本
  visual_tools.loadRemoteControl();
  //RViz提供了许多类型的标记,在这个演示中,我们将使用文本、圆柱体和球体
  Eigen::Isometry3d text_pose = Eigen::Isometry3d::Identity();
  text_pose.translation().z() = 1.75;
  visual_tools.publishText(text_pose, "MoveGroupInterface Demo", rvt::WHITE, rvt::XLARGE);

  // 批量发布用于减少发送到RViz的大型可视化消息的数量
  visual_tools.trigger();

   // Getting Basic Information
  // ^^^^^^^^^^^^^^^^^^^^^^^^^
  //得到基本信息
  // 批量发布用于减少发送到RViz的大型可视化消息的数量
  ROS_INFO_NAMED("tutorial", "Planning frame: %s", move_group.getPlanningFrame().c_str());

  // 我们还可以打印此组的末端效应器链接的名称
  ROS_INFO_NAMED("tutorial", "End effector link: %s", move_group.getEndEffectorLink().c_str());

  //我们可以得到机器人中所有组的列表:
  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.
  //把当前状态设置为运动的初始状态
  current_time = ros::Time::now();//path
  moveit::core::RobotStatePtr current_state = move_group.getCurrentState();
  robot_state::RobotState start_state(*move_group.getCurrentState());
  
  geometry_msgs::Pose start_pose2;
  start_pose2.orientation.w = 1.0;
  start_pose2.position.x = 0.52;
  start_pose2.position.y = -0.02;
  start_pose2.position.z = 0.2;
  start_state.setFromIK(joint_model_group, start_pose2);
  move_group.setStartState(start_state);
  std::vector<geometry_msgs::Pose> waypoints;
  //waypoints.push_back(start_pose2);
  geometry_msgs::Pose target_pose3 = start_pose2;
  geometry_msgs::PoseStamped this_pose_stamped;//path
  while (i<70)
    {
        i++;
        current_time = ros::Time::now();
        //compute odometry in a typical way given the velocities of the robot
        double dt = 1;
        double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
        double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
        double delta_th = vth * dt;         
        x += delta_x;
        y += delta_y;
        z += 0.005;
        th += delta_th;
       
	
        geometry_msgs::PoseStamped this_pose_stamped;
        geometry_msgs::PointStamped this_point_stamped;
        this_pose_stamped.pose.position.x = x*0.1+0.5;
        this_pose_stamped.pose.position.y = y*0.1;
        this_pose_stamped.pose.position.z = z*0.1+0.2;
		target_pose3.position.x =  this_pose_stamped.pose.position.x;
		target_pose3.position.y =  this_pose_stamped.pose.position.y;
		target_pose3.position.z =  this_pose_stamped.pose.position.z;
		waypoints.push_back(target_pose3);// 1
    	geometry_msgs::Quaternion goal_quat =          
    	tf::createQuaternionMsgFromYaw(th);
    	this_pose_stamped.pose.orientation.x = goal_quat.x;
    	this_pose_stamped.pose.orientation.y = goal_quat.y;
		this_pose_stamped.pose.orientation.z = goal_quat.z;
    	this_pose_stamped.pose.orientation.w = goal_quat.w;
    	this_pose_stamped.header.stamp = current_time;
    	this_pose_stamped.header.frame_id = "base_link";
   		path.poses.push_back(this_pose_stamped);

        path_pub.publish(path);
       
        ros::spinOnce(); // check for incoming messages

        last_time = current_time;
        //loop_rate.sleep();
    }

 
  move_group.setMaxVelocityScalingFactor(0.1);
 
  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); 
 
  visual_tools.publishText(text_pose, "Joint Space Goal", 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");
   // We can also visualize the plan as a line with markers in RViz.
  ros::shutdown();
  return 0;
}



简单说一下这个代码,在我上一篇博客中也写到,其实就是实现圆弧轨迹规划,然后定义圆弧差值,之后把每个插值点同时做两件事:
①赋值给path点,然后发布到/trajectory上

②赋值target_pose3 进行轨迹规划
这样随着机械臂实现这个圆弧轨迹,也会看到/trajectory话题的轨迹曲线
在这里插入图片描述
最后我发现这个代码有点问题,就是显示的轨迹是我们的目标轨迹,假如实际情况只可以实现80%,绿色轨迹还是会出现100%,我觉得不太对头,后续改进~