moveit_msgs::RobotTrajectory

  • DOF(Degree Of Freedom)。自由度。

Ros用moveit_msgs::RobotTrajectory封装发向机器人的路径控制,对当中每个路点,表示它的有关节状态(positions)、相对于起始路点的时间戳(time_from_start)等。

C:\Windows\System32>rosmsg show moveit_msgs/RobotTrajectory
trajectory_msgs/JointTrajectory joint_trajectory
  std_msgs/Header header
    uint32 seq
    time stamp
    string frame_id
  string[] joint_names
  trajectory_msgs/JointTrajectoryPoint[] points
    float64[] positions
    float64[] velocities
    float64[] accelerations
    float64[] effort
    duration time_from_start
trajectory_msgs/MultiDOFJointTrajectory multi_dof_joint_trajectory
  std_msgs/Header header
    uint32 seq
    time stamp
    string frame_id
  string[] joint_names
  trajectory_msgs/MultiDOFJointTrajectoryPoint[] points
    geometry_msgs/Transform[] transforms
      geometry_msgs/Vector3 translation
        float64 x
        float64 y
        float64 z
      geometry_msgs/Quaternion rotation
        float64 x
        float64 y
        float64 z
        float64 w
    geometry_msgs/Twist[] velocities
      geometry_msgs/Vector3 linear
        float64 x
        float64 y
        float64 z
      geometry_msgs/Vector3 angular
        float64 x
        float64 y
        float64 z
    geometry_msgs/Twist[] accelerations
      geometry_msgs/Vector3 linear
        float64 x
        float64 y
        float64 z
      geometry_msgs/Vector3 angular
        float64 x
        float64 y
        float64 z
    duration time_from_start

moveit_msgs::RobotTrajectory就是trajectory_msgs::JointTrajectory和trajectory_msgs::MultiDOFJointTrajector的struct,JointTrajectory发向机器人中那些单自由度关节,MultiDOFJointTrajector则是多自由度关节。

 

一、robot_trajectory::RobotTrajectory转成moveit_msgs::RobotTrajectory

  • @trajectory[OUT]。要转换出的moveit_msgs::RobotTrajectory类型的路径轨迹。
  • @joint_filter[IN]。额外的关节值筛选器。当不是空时,存储时认为有效的关节名称,像a、b、c。路径中要关节需要是它们中的一种,它会认为有效,才会加入要生成的路径。默认空。
void RobotTrajectory::getRobotTrajectoryMsg(moveit_msgs::RobotTrajectory& trajectory,
                                            const std::vector<std::string>& joint_filter) const
{
  trajectory = moveit_msgs::RobotTrajectory();
  if (waypoints_.empty())
    return;
  const std::vector<const moveit::core::JointModel*>& jnts =
      group_ ? group_->getActiveJointModels() : robot_model_->getActiveJointModels();

  std::vector<const moveit::core::JointModel*> onedof;
  std::vector<const moveit::core::JointModel*> mdof;

  trajectory.joint_trajectory.joint_names.clear();
  trajectory.multi_dof_joint_trajectory.joint_names.clear();

  for (const moveit::core::JointModel* active_joint : jnts)
  {
    // only consider joints listed in joint_filter
    if (!joint_filter.empty() &&
        std::find(joint_filter.begin(), joint_filter.end(), active_joint->getName()) == joint_filter.end())
      continue;

    if (active_joint->getVariableCount() == 1)
    {
      trajectory.joint_trajectory.joint_names.push_back(active_joint->getName());
      onedof.push_back(active_joint);
    }
    else
    {
      trajectory.multi_dof_joint_trajectory.joint_names.push_back(active_joint->getName());
      mdof.push_back(active_joint);
    }
  }

  if (!onedof.empty())
  {
    trajectory.joint_trajectory.header.frame_id = robot_model_->getModelFrame();
    trajectory.joint_trajectory.header.stamp = ros::Time(0);
    trajectory.joint_trajectory.points.resize(waypoints_.size());
  }

  if (!mdof.empty())
  {
    trajectory.multi_dof_joint_trajectory.header.frame_id = robot_model_->getModelFrame();
    trajectory.multi_dof_joint_trajectory.header.stamp = ros::Time(0);
    trajectory.multi_dof_joint_trajectory.points.resize(waypoints_.size());
  }
图1 机械臂有3个单自由度关节:a、b、c

onedof:存储着此个规划组中单自由度关节信息。示例中有3个。

mdof:存储着此此个规划组多自由度关节信息。示例中有0个。

  static const ros::Duration ZERO_DURATION(0.0);
  double total_time = 0.0;
  for (std::size_t i = 0; i < waypoints_.size(); ++i)
  {
    if (duration_from_previous_.size() > i)
      total_time += duration_from_previous_[i];
 
    if (!onedof.empty())
    {
      trajectory.joint_trajectory.points[i].positions.resize(onedof.size());
      trajectory.joint_trajectory.points[i].velocities.reserve(onedof.size());
 
      for (std::size_t j = 0; j < onedof.size(); ++j)
      {
        trajectory.joint_trajectory.points[i].positions[j] =
            waypoints_[i]->getVariablePosition(onedof[j]->getFirstVariableIndex());
        // if we have velocities/accelerations/effort, copy those too
        if (waypoints_[i]->hasVelocities())
          trajectory.joint_trajectory.points[i].velocities.push_back(
              waypoints_[i]->getVariableVelocity(onedof[j]->getFirstVariableIndex()));
        if (waypoints_[i]->hasAccelerations())
          trajectory.joint_trajectory.points[i].accelerations.push_back(
              waypoints_[i]->getVariableAcceleration(onedof[j]->getFirstVariableIndex()));
        if (waypoints_[i]->hasEffort())
          trajectory.joint_trajectory.points[i].effort.push_back(
              waypoints_[i]->getVariableEffort(onedof[j]->getFirstVariableIndex()));
      }
      // clear velocities if we have an incomplete specification
      if (trajectory.joint_trajectory.points[i].velocities.size() != onedof.size())
        trajectory.joint_trajectory.points[i].velocities.clear();
      // clear accelerations if we have an incomplete specification
      if (trajectory.joint_trajectory.points[i].accelerations.size() != onedof.size())
        trajectory.joint_trajectory.points[i].accelerations.clear();
      // clear effort if we have an incomplete specification
      if (trajectory.joint_trajectory.points[i].effort.size() != onedof.size())
        trajectory.joint_trajectory.points[i].effort.clear();
 
      if (duration_from_previous_.size() > i)
        trajectory.joint_trajectory.points[i].time_from_start = ros::Duration(total_time);
      else
        trajectory.joint_trajectory.points[i].time_from_start = ZERO_DURATION;
      SDL_Log("[%i/%i]{onedof}, duration_from_previous_[%i/%i]: %.5f, total_time: %.5f, time_from_start: %.5f, positions: %s", 
          (int)i, (int)waypoints_.size() - 1, (int)i, (int)duration_from_previous_.size() - 1, duration_from_previous_[i], total_time, 
          trajectory.joint_trajectory.points[i].time_from_start.toSec(), vector_double_DebugString(trajectory.joint_trajectory.points[i].positions).c_str());

为理解,增加了SDL_log,底下有对图1的一次运行时输出。

    }
    if (!mdof.empty())
    {
      trajectory.multi_dof_joint_trajectory.points[i].transforms.resize(mdof.size());
      for (std::size_t j = 0; j < mdof.size(); ++j)
      {
        geometry_msgs::TransformStamped ts = tf2::eigenToTransform(waypoints_[i]->getJointTransform(mdof[j]));
        trajectory.multi_dof_joint_trajectory.points[i].transforms[j] = ts.transform;
        // TODO: currently only checking for planar multi DOF joints / need to add check for floating
        if (waypoints_[i]->hasVelocities() && (mdof[j]->getType() == moveit::core::JointModel::JointType::PLANAR))
        {
          const std::vector<std::string> names = mdof[j]->getVariableNames();
          const double* velocities = waypoints_[i]->getJointVelocities(mdof[j]);
 
          geometry_msgs::Twist point_velocity;
 
          for (std::size_t k = 0; k < names.size(); ++k)
          {
            if (names[k].find("/x") != std::string::npos)
            {
              point_velocity.linear.x = velocities[k];
            }
            else if (names[k].find("/y") != std::string::npos)
            {
              point_velocity.linear.y = velocities[k];
            }
            else if (names[k].find("/z") != std::string::npos)
            {
              point_velocity.linear.z = velocities[k];
            }
            else if (names[k].find("/theta") != std::string::npos)
            {
              point_velocity.angular.z = velocities[k];
            }
          }
          trajectory.multi_dof_joint_trajectory.points[i].velocities.push_back(point_velocity);
        }
      }
      if (duration_from_previous_.size() > i)
        trajectory.multi_dof_joint_trajectory.points[i].time_from_start = ros::Duration(total_time);
      else
        trajectory.multi_dof_joint_trajectory.points[i].time_from_start = ZERO_DURATION;
    }
  }
}

a、b、c三个单自由度关节,图1显示了此时相关变量值。

[0/41]{onedof}, duration_from_previous_[0/41]: 0, total_time: 0, time_from_start: 0, positions: (0, 0, 0)
[1/41]{onedof}, duration_from_previous_[1/41]: 0.02009, total_time: 0.02009, time_from_start: 0.02009, positions: (4.71548e-05, 5.65878e-05, -6.60183e-05)
[2/41]{onedof}, duration_from_previous_[2/41]: 0.18117, total_time: 0.20127, time_from_start: 0.20127, positions: (0.0128202, 0.0153849, -0.0179488)
[3/41]{onedof}, duration_from_previous_[3/41]: 0.07927, total_time: 0.28054, time_from_start: 0.28054, positions: (0.0256405, 0.0307697, -0.0358975)
[4/41]{onedof}, duration_from_previous_[4/41]: 0.06426, total_time: 0.34481, time_from_start: 0.34481, positions: (0.0384607, 0.0461546, -0.0538463)
[5/41]{onedof}, duration_from_previous_[5/41]: 0.07131, total_time: 0.41612, time_from_start: 0.41612, positions: (0.051281, 0.0615394, -0.0717951)
...
[37/41]{onedof}, duration_from_previous_[37/41]: 0.07131, total_time: 2.98264, time_from_start: 2.98264, positions: (0.461529, 0.553855, -0.646156)
[38/41]{onedof}, duration_from_previous_[38/41]: 0.06426, total_time: 3.04690, time_from_start: 3.04690, positions: (0.474349, 0.56924, -0.664105)
[39/41]{onedof}, duration_from_previous_[39/41]: 0.07927, total_time: 3.12618, time_from_start: 3.12618, positions: (0.487169, 0.584625, -0.682053)
[40/41]{onedof}, duration_from_previous_[40/41]: 0.18117, total_time: 3.30735, time_from_start: 3.30735, positions: (0.499942, 0.599953, -0.699936)
[41/41]{onedof}, duration_from_previous_[41/41]: 0.02009, total_time: 3.32745, time_from_start: 3.32745, positions: (0.499989, 0.600009, -0.700002)

对生成的time_from_start,值等于total_time,

 

二、moveit_msgs::RobotTrajectory发向机器人

moveit四大插件之一的控制器(MoveItControllerManager)负责把moveit_msgs::RobotTrajectory发向机器人。这里以默认的控制器插件MoveItFakeControllerManager为例,它支持三种方式,先择当中的ViaPointController。

  • ViaPointController。每个点有个time_from_start字段,指示该point要发送到机器人的时刻。选择这种时,时间必须已到这个时刻,才把原值为作为js发送向关节。
void ViaPointController::execTrajectory(const moveit_msgs::RobotTrajectory& t)
{
  ROS_INFO("Fake execution of trajectory");
  sensor_msgs::JointState js;
  js.header = t.joint_trajectory.header;
  js.name = t.joint_trajectory.joint_names;

  // publish joint states for all intermediate via points of the trajectory
  // no further interpolation
  int at = 0;
  ros::Time start_time = ros::Time::now();

start_time是发送零路点的真实时刻,“ros::Time::now() - start_time”指现在离零路点真实过了多少时间,“理论应该相隔的时间-实际时间相隔了时间”wait_time就是希望再等待时间。

  for (std::vector<trajectory_msgs::JointTrajectoryPoint>::const_iterator via = t.joint_trajectory.points.begin(),
                                                                          end = t.joint_trajectory.points.end();
       !cancelled() && via != end; ++via)
  {
    js.position = via->positions;
    js.velocity = via->velocities;
    js.effort = via->effort;

    ros::Duration wait_time = via->time_from_start - (ros::Time::now() - start_time);
    if (wait_time.toSec() > std::numeric_limits<float>::epsilon())
    {
      ROS_INFO("Fake execution: waiting %0.5fs for next via point, %ld remaining", wait_time.toSec(), end - via);
      wait_time.sleep();
    }
    js.header.stamp = ros::Time::now();
    ROS_INFO("[%i/%i]via->time_from_start: %.5f, pre pub_.publish(%s)", 
        at ++, (int)t.joint_trajectory.points.size() - 1, via->time_from_start.toSec(), vector_double_DebugString(js.position).c_str());
    pub_.publish(js);
  }
  ROS_DEBUG("Fake execution of trajectory: done");
}

执行示例后的输出日志。

[1653911981.900536500]: Fake execution of trajectory
[1653911981.900794100]: [0/41]via->time_from_start: 0.00000, pre pub_.publish((0, 0, 0))
[1653911981.900984700]: Fake execution: waiting 0.01990s for next via point, 41 remaining
[1653911981.921961500]: [1/41]via->time_from_start: 0.02010, pre pub_.publish((4.71548e-05, 5.65878e-05, -6.60183e-05))
[1653911981.922242000]: Fake execution: waiting 0.17981s for next via point, 40 remaining
[1653911982.095091900]: scene update 2.09506 robot stamp: 2.09449
[1653911982.102515300]: [2/41]via->time_from_start: 0.20127, pre pub_.publish((0.0128202, 0.0153849, -0.0179488))
[1653911982.102970500]: Fake execution: waiting 0.07838s for next via point, 39 remaining
[1653911982.183268800]: [3/41]via->time_from_start: 0.28055, pre pub_.publish((0.0256405, 0.0307697, -0.0358975))
[1653911982.183629300]: Fake execution: waiting 0.06197s for next via point, 38 remaining
[1653911982.246102600]: [4/41]via->time_from_start: 0.34481, pre pub_.publish((0.0384607, 0.0461546, -0.0538463))
[1653911982.246325800]: Fake execution: waiting 0.07059s for next via point, 37 remaining
[1653911982.296290700]: scene update 2.29626 robot stamp: 2.29493
[1653911982.317920100]: [5/41]via->time_from_start: 0.41613, pre pub_.publish((0.051281, 0.0615394, -0.0717951))
[1653911982.318311000]: Fake execution: waiting 0.08092s for next via point, 36 remaining
...
[1653911984.813651100]: Fake execution: waiting 0.06977s for next via point, 5 remaining
[1653911984.884144800]: [37/41]via->time_from_start: 2.98264, pre pub_.publish((0.461529, 0.553855, -0.646156))
[1653911984.884487100]: Fake execution: waiting 0.06320s for next via point, 4 remaining
[1653911984.949513200]: [38/41]via->time_from_start: 3.04691, pre pub_.publish((0.474349, 0.56924, -0.664105))
[1653911984.949882000]: Fake execution: waiting 0.07708s for next via point, 3 remaining
[1653911985.028742400]: [39/41]via->time_from_start: 3.12618, pre pub_.publish((0.487169, 0.584625, -0.682053))
[1653911985.029164100]: Fake execution: waiting 0.17897s for next via point, 2 remaining
[1653911985.051992700]: scene update 5.05192 robot stamp: 4.99531
[1653911985.209224100]: [40/41]via->time_from_start: 3.30736, pre pub_.publish((0.499942, 0.599953, -0.699936))
[1653911985.209493500]: Fake execution: waiting 0.01874s for next via point, 1 remaining
[1653911985.229174200]: [41/41]via->time_from_start: 3.32745, pre pub_.publish((0.499989, 0.600009, -0.700002))

按规则,最后一个路点[41]发布时刻应该约等于发布[0]路点时刻(1653911981.900794100)加上路点[41]的time_from_start(3.32745)。

全部评论: 0

    写评论: