datetime:2025/01/23 16:15
author:nzb

机器人模型和机器人状态

功能目录

  • 获取关节值
  • 关节限位检查
  • 正向运动学
  • 逆运动学
  • 获取雅可比矩阵

概念

  • 机器人模型(RobotModel)类和机器人状态(RobotState)类是可以访问机器人运动学的核心类。

    • 机器人模型(RobotModel)类包含所有链接和关节之间的关系,包括从 URDF 加载的关节限位属性。 RobotModel 还将机器人的链接和关节分成 SRDF 中定义的规划组。 有关 URDF 和 SRDF 的单独教程,请点击此处: URDF和SRDF教程
    • 机器人状态(RobotState)包含机器人在某个时间点的信息,存储关节位置矢量,以及可选的速度和加速度矢量。 这些信息可用于获取依赖于机器人当前状态的运动学信息,例如末端效应器的雅各布因子。 RobotState 还包含一些辅助函数,用于根据末端效应器的位置(笛卡尔姿态)设置手臂位置和计算笛卡尔轨迹。

实例:ros2 launch moveit2_tutorials robot_model_and_robot_state_tutorial.launch.py

代码解读

#include <moveit/robot_model_loader/robot_model_loader.h>
#include <moveit/robot_model/robot_model.h>
#include <moveit/robot_state/robot_state.h>

int main(int argc, char** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::NodeOptions node_options;
  // This enables loading undeclared parameters
  // best practice would be to declare parameters in the corresponding classes
  // and provide descriptions about expected use
  node_options.automatically_declare_parameters_from_overrides(true);
  auto node = rclcpp::Node::make_shared("robot_model_and_state_tutorial", node_options);
  const auto& LOGGER = node->get_logger();

  // BEGIN_TUTORIAL
  // Start
  // ^^^^^
  // Setting up to start using the RobotModel class is very easy. In
  // general, you will find that most higher-level components will
  // return a shared pointer to the RobotModel. You should always use
  // that when possible. In this example, we will start with such a
  // shared pointer and discuss only the basic API. You can have a
  // look at the actual code API for these classes to get more
  // information about how to use more features provided by these
  // classes.
  //
  // We will start by instantiating a
  // `RobotModelLoader`_
  // object, which will look up
  // the robot description on the ROS parameter server and construct a
  // :moveit_codedir:`RobotModel<moveit_core/robot_model/include/moveit/robot_model/robot_model.hpp>` for us to use.
  //
  // .. _RobotModelLoader:
  //     https://github.com/moveit/moveit2/blob/main/moveit_ros/planning/robot_model_loader/include/moveit/robot_model_loader/robot_model_loader.hpp
  robot_model_loader::RobotModelLoader robot_model_loader(node);
  const moveit::core::RobotModelPtr& kinematic_model = robot_model_loader.getModel();
  RCLCPP_INFO(LOGGER, "Model frame: %s", kinematic_model->getModelFrame().c_str());

  // Using the :moveit_codedir:`RobotModel<moveit_core/robot_model/include/moveit/robot_model/robot_model.hpp>`, 
  // we can construct a :moveit_codedir:`RobotState<moveit_core/robot_state/include/moveit/robot_state/robot_state.hpp>` that maintains the configuration of the robot. We will set all joints in the state to their default values. We can then get a :moveit_codedir:`JointModelGroup<moveit_core/robot_model/include/moveit/robot_model/joint_model_group.hpp>`, which represents the robot model for a particular group, e.g. the "panda_arm" of the Panda robot.
  // 使用机器人模型,我们可以构建一个机器人状态(RobotState)来维护机器人的配置。 我们将把状态中的所有关节设置为默认值。 然后,我们可以得到一个关节模型组(JointModelGroup),它代表某个特定组的机器人模型,例如熊猫机器人的 "熊猫臂"(panda_arm)。
  moveit::core::RobotStatePtr robot_state(new moveit::core::RobotState(kinematic_model));
  robot_state->setToDefaultValues();
  const moveit::core::JointModelGroup* joint_model_group = kinematic_model->getJointModelGroup("panda_arm");

  const std::vector<std::string>& joint_names = joint_model_group->getVariableNames();

  // Get Joint Values
  // ^^^^^^^^^^^^^^^^
  // We can retrieve the current set of joint values stored in the state for the Panda arm.
  std::vector<double> joint_values;
  robot_state->copyJointGroupPositions(joint_model_group, joint_values);
  for (std::size_t i = 0; i < joint_names.size(); ++i)
  {
    RCLCPP_INFO(LOGGER, "Joint %s: %f", joint_names[i].c_str(), joint_values[i]);
  }

  // Joint Limits
  // ^^^^^^^^^^^^
  // setJointGroupPositions() 本身不会强制执行关节限制,但调用 enforceBounds() 可以实现。
  /* Set one joint in the Panda arm outside its joint limit */
  joint_values[0] = 5.57;
  robot_state->setJointGroupPositions(joint_model_group, joint_values);

  /* Check whether any joint is outside its joint limits */
  RCLCPP_INFO_STREAM(LOGGER, "Current state is " << (robot_state->satisfiesBounds() ? "valid" : "not valid"));

  /* Enforce the joint limits for this state and check again*/
  robot_state->enforceBounds();
  RCLCPP_INFO_STREAM(LOGGER, "Current state is " << (robot_state->satisfiesBounds() ? "valid" : "not valid"));

  // Forward Kinematics
  // ^^^^^^^^^^^^^^^^^^
  // Now, we can compute forward kinematics for a set of random joint
  // values. Note that we would like to find the pose of the
  // "panda_link8" which is the most distal link in the
  // "panda_arm" group of the robot.
  robot_state->setToRandomPositions(joint_model_group);
  const Eigen::Isometry3d& end_effector_state = robot_state->getGlobalLinkTransform("panda_link8");

  /* Print end-effector pose. Remember that this is in the model frame */
  RCLCPP_INFO_STREAM(LOGGER, "Translation: \n" << end_effector_state.translation() << "\n");
  RCLCPP_INFO_STREAM(LOGGER, "Rotation: \n" << end_effector_state.rotation() << "\n");

  // Inverse Kinematics
  // ^^^^^^^^^^^^^^^^^^
  // We can now solve inverse kinematics (IK) for the Panda robot.
  // To solve IK, we will need the following:
  //
  //  * The desired pose of the end-effector (by default, this is the last link in the "panda_arm" chain):
  //    end_effector_state that we computed in the step above.
  //  * The timeout: 0.1 s
  double timeout = 0.1;
  bool found_ik = robot_state->setFromIK(joint_model_group, end_effector_state, timeout);

  // Now, we can print out the IK solution (if found):
  if (found_ik)
  {
    robot_state->copyJointGroupPositions(joint_model_group, joint_values);
    for (std::size_t i = 0; i < joint_names.size(); ++i)
    {
      RCLCPP_INFO(LOGGER, "Joint %s: %f", joint_names[i].c_str(), joint_values[i]);
    }
  }
  else
  {
    RCLCPP_INFO(LOGGER, "Did not find IK solution");
  }

  // Get the Jacobian
  // ^^^^^^^^^^^^^^^^
  // We can also get the Jacobian from the
  // :moveit_codedir:`RobotState<moveit_core/robot_state/include/moveit/robot_state/robot_state.hpp>`.
  Eigen::Vector3d reference_point_position(0.0, 0.0, 0.0);
  Eigen::MatrixXd jacobian;
  robot_state->getJacobian(joint_model_group, robot_state->getLinkModel(joint_model_group->getLinkModelNames().back()),
                           reference_point_position, jacobian);
  RCLCPP_INFO_STREAM(LOGGER, "Jacobian: \n" << jacobian << "\n");
  // END_TUTORIAL

  rclcpp::shutdown();
  return 0;
}

输出

[INFO] [launch]: All log files can be found below /home/blues/.ros/log/2025-01-23-17-20-02-828828-pasture-10-43955
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [robot_model_and_robot_state_tutorial-1]: process started with pid [43956]
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.910483504] [moveit_rdf_loader.rdf_loader]: Loaded robot model in 0.000824903 seconds
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.910503727] [moveit_robot_model.robot_model]: Loading robot model 'panda'...
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.914986406] [robot_model_and_state_tutorial]: Model frame: world
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915039339] [robot_model_and_state_tutorial]: Joint panda_joint1: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915043593] [robot_model_and_state_tutorial]: Joint panda_joint2: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915045723] [robot_model_and_state_tutorial]: Joint panda_joint3: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915047573] [robot_model_and_state_tutorial]: Joint panda_joint4: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915049343] [robot_model_and_state_tutorial]: Joint panda_joint5: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915051178] [robot_model_and_state_tutorial]: Joint panda_joint6: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915053132] [robot_model_and_state_tutorial]: Joint panda_joint7: 0.000000
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915055745] [robot_model_and_state_tutorial]: Current state is not valid
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915058370] [robot_model_and_state_tutorial]: Current state is valid
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915082856] [robot_model_and_state_tutorial]: Translation: 
[robot_model_and_robot_state_tutorial-1]  0.416676
[robot_model_and_robot_state_tutorial-1]  0.501069
[robot_model_and_robot_state_tutorial-1] -0.138612
[robot_model_and_robot_state_tutorial-1] 
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915090614] [robot_model_and_state_tutorial]: Rotation: 
[robot_model_and_robot_state_tutorial-1]  -0.674875   0.296534  -0.675731
[robot_model_and_robot_state_tutorial-1]   0.437197   0.898365 -0.0424092
[robot_model_and_robot_state_tutorial-1]   0.594477  -0.324048  -0.735928
[robot_model_and_robot_state_tutorial-1] 
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915132218] [robot_model_and_state_tutorial]: Joint panda_joint1: 0.727893
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915134928] [robot_model_and_state_tutorial]: Joint panda_joint2: 1.756749
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915136823] [robot_model_and_state_tutorial]: Joint panda_joint3: 0.214201
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915138709] [robot_model_and_state_tutorial]: Joint panda_joint4: -0.585159
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915140541] [robot_model_and_state_tutorial]: Joint panda_joint5: 0.239392
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915142356] [robot_model_and_state_tutorial]: Joint panda_joint6: 1.741185
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915144255] [robot_model_and_state_tutorial]: Joint panda_joint7: -2.066926
[robot_model_and_robot_state_tutorial-1] [INFO] [1737624002.915166286] [robot_model_and_state_tutorial]: Jacobian: 
[robot_model_and_robot_state_tutorial-1]   -0.501069   -0.352095   -0.215715    0.313214  -0.0409505    0.121742 -2.1684e-17
[robot_model_and_robot_state_tutorial-1]    0.416676   -0.313763    0.268989    0.163938   0.0735211    0.065999 1.38778e-17
[robot_model_and_robot_state_tutorial-1]           0   -0.644442   0.0952036    0.337704   0.0333641  0.00398945  1.9082e-17
[robot_model_and_robot_state_tutorial-1]           0   -0.665298    0.733707    0.620754     0.45903    0.452348   -0.675731
[robot_model_and_robot_state_tutorial-1]           0    0.746578    0.653829   -0.755662    0.566316   -0.812129  -0.0424092
[robot_model_and_robot_state_tutorial-1]           1 4.89664e-12   -0.184883   -0.208902   -0.684527   -0.368547   -0.735928
[robot_model_and_robot_state_tutorial-1] 
[INFO] [robot_model_and_robot_state_tutorial-1]: process has finished cleanly [pid 43956]

启动文件

from launch import LaunchDescription
from launch_ros.actions import Node
from moveit_configs_utils import MoveItConfigsBuilder


def generate_launch_description():
    moveit_config = MoveItConfigsBuilder("moveit_resources_panda").to_moveit_configs()

    tutorial_node = Node(
        package="moveit2_tutorials",
        executable="robot_model_and_robot_state_tutorial",
        output="screen",
        parameters=[
            moveit_config.robot_description,
            moveit_config.robot_description_semantic,
            moveit_config.robot_description_kinematics,
        ],
    )

    return LaunchDescription([tutorial_node])

results matching ""

    No results matching ""