SDK 目录结构说明
这份文档帮助你理解 SDK 里每个文件夹是干什么的,就像一本"使用说明书的目录"。
整体结构概览
Panthera-HT_SDK/
├── panthera_cpp/ ← C++ 底层代码(高级用户用)
├── panthera_python/ ← Python 控制代码(你主要用这个)
├── LICENSE ← 开源协议文件
└── README.md ← 快速入门指南
简单理解:
-
panthera_cpp:用 C++ 写的底层驱动,负责和电机通信 -
panthera_python:用 Python 写的控制接口,你写代码主要在这里 -
大部分用户只需要关心
panthera_python目录
panthera_python/ — Python 控制目录(重点)
这是你日常使用的主目录,所有 Python 示例代码都在这里。
panthera_python/
├── scripts/ ← 示例代码(你的学习起点)
├── robot_param/ ← 机械臂配置文件
├── Panthera-HT_description/ ← 机械臂 3D 模型
├── motor_whl/ ← 预编译的电机驱动包
├── images/ ← 文档图片
├── src/ ← Python 绑定源码
├── requirements.txt ← Python 依赖列表
├── README.md ← Python SDK 使用说明
└── CMakeLists.txt ← 编译配置(从源码安装时用)
📂 scripts/ — 示例代码库(你的学习起点)
作用:包含 20+ 个现成的控制示例,从简单到复杂,覆盖所有功能。
目录结构:
scripts/
├── Panthera_lib/ ← 高层控制库(核心代码)
│ ├── Panthera.py ← 机械臂控制类(1619 行核心代码)
│ ├── recorder.py ← 轨迹录制/回放工具
│ └── __init__.py ← 模块初始化
│
├── 0_robot_get_state.py ← 查看机械臂状态(第一个要跑的)
├── 0_robot_set_zero.py ← 设置零位(首次使用必做)
│
├── 1_Joint_PosVel_control.py ← 关节位置+速度控制
├── 1_Joint_Vel_control.py ← 关节纯速度控制
├── 1_Joint_PD_control.py ← 关节底层 PD 控制
├── 1_moveJ_control.py ← 关节空间同步运动
├── 1_forward_kinematics_test.py ← 正运动学测试
├── 1_inverse_kinematics_test.py ← 逆运动学测试
│
├── 2_inv_PosVel_control.py ← 基于 IK 的笛卡尔位置控制
├── 2_gravity_compensation_control.py ← 重力补偿(可拖动)
├── 2_gravity_friction_compensation_control.py ← 重力+摩擦力补偿
├── 2_Jointimpendence_control_with_gra_pd.py ← 关节阻抗控制(重力+PD)
├── 2_Jointimpendence_control_with_gra_fri_pd.py ← 关节阻抗控制(重力+摩擦力+PD)
│
├── 3_interpolation_control_zeroVel.py ← 多项式插值(末速度为零)
├── 3_interpolation_control_nozeroVel.py ← 多项式插值(末速度不为零)
├── 3_sin_trajectory_control.py ← 正弦轨迹跟踪
├── 3_gravity_compensation_with_fk.py ← 重力补偿+FK 实时显示
│
├── 4_impedance_trajectory_control_with_gra_pd.py ← 轨迹级阻抗控制(重力+PD)
│
├── 5_record_trajectory.py ← 拖动示教录制
├── 5_replay_trajectory.py ← 轨迹回放
├── 5_teleop_control.py ← 双臂主从遥操
│
├── 6_moveL_pos_control.py ← 笛卡尔直线运动(位置)
├── 6_moveL_rotate_control.py ← 笛卡尔直线运动(旋转)
│
├── 7_keyboard_cartesian_pos_control.py ← 键盘控制末端位置(IK)
├── 7_keyboard_cartesian_vel_control.py ← 键盘控制末端速度(雅可比)
│
└── motor_example/ ← 底层电机控制示例
├── 01_motor_get_status.py ← 查看单个电机状态
├── 02_position_control.py ← 电机位置控制
├── 03_velocity_control.py ← 电机速度控制
├── 04_torque_control.py ← 电机力矩控制
├── 05_voltage_control.py ← 电机电压控制
├── 06_current_control.py ← 电机电流控制
├── 07_pos_vel_maxtorque_control.py ← 位置+速度+最大力矩控制
├── 08_pos_vel_torque_kp_kd_control.py ← MIT 五参数控制
├── 09_set_zero.py ← 设置电机零位
├── motor_control.py ← 电机控制工具函数
└── motor_README.md
使用建议:
-
第一次使用:先跑
0_robot_get_state.py确认硬件连接正常 -
学习基础控制:按编号顺序跑
1_开头的脚本 -
学习高级功能:跑
2_、3_开头的脚本 -
实战应用:参考
5_、6_、7_开头的脚本 -
一般不直接跑
motor_emample/的脚本,除非发现某个电机出现问题
Panthera_lib/ 子目录:
-
这是封装好的高层控制库,所有示例脚本都用它
-
Panthera.py是核心,包含运动学、动力学、轨迹规划等所有功能 -
你自己写代码时也要
from Panthera_lib import Panthera
🤏 夹爪控制
Panthera-HT 的夹爪是第 7 个电机(索引排在 6 个关节电机之后),由 Panthera_lib 统一管理,和关节控制用同一套接口风格。
夹爪限位(来自 Leader.yaml):
gripper_limits:
lower: 0.0 # 完全闭合(rad)
upper: 2.0 # 完全张开(rad)
常用 API:
| 方法 | 说明 |
|---|---|
gripper_open(pos=1.6, vel=0.5, max_tqu=0.5) |
打开夹爪(默认张开到 1.6 rad) |
gripper_close(pos=0.0, vel=0.5, max_tqu=0.5) |
关闭夹爪(默认闭合到 0.0 rad) |
gripper_control(pos, vel, max_tqu) |
精确控制夹爪位置(位置+速度+最大力矩模式) |
gripper_control_MIT(pos, vel, tqe, kp, kd) |
MIT 五参数模式(用于遥操和轨迹回放) |
get_current_pos_gripper() |
读取当前夹爪角度(rad) |
get_current_vel_gripper() |
读取当前夹爪速度(rad/s) |
get_current_torque_gripper() |
读取当前夹爪力矩(Nm) |
典型用法:
from Panthera_lib import Panthera
robot = Panthera("../robot_param/Leader.yaml")
robot.gripper_open() # 张开
robot.gripper_close() # 闭合
robot.gripper_control(1.0, 0.5, 0.5) # 移动到 1.0 rad,速度 0.5,最大力矩 0.5 Nm
安全机制: 超出 [0.0, 2.0] 范围的指令会被自动拒绝并打印警告,不会下发给电机。
在哪些示例里用到了夹爪:
● 0_robot_get_state.py — 读取并打印夹爪当前位置和速度
● 0_robot_set_zero.py — 显示夹爪状态(设零时参考用)
● 1_Joint_PosVel_control.py / 1_moveJ_control.py — gripper_open() / gripper_close() 基础用法
● 2_gravity_compensation_control.py — 拖动示教时将夹爪锁零(MIT 模式全零参数)
● 5_record_trajectory.py — 录制时同步记录夹爪位置和速度
● 5_replay_trajectory.py — 回放时用 MIT 模式驱动夹爪
● 5_teleop_control.py — 主从遥操时主臂夹爪状态实时映射到从臂
📂 robot_param/ — 机械臂配置文件
作用:存放机械臂的参数配置,比如关节限位、最大力矩、电机 ID 等。
目录结构:
robot_param/
├── Leader.yaml ← 主臂配置(双臂系统的主臂)
├── Follower.yaml ← 从臂配置(双臂系统的从臂)
└── motor_param/ ← 电机底层参数
├── 6dof_Panthera_params_leader.yaml ← 主臂电机参数
├── 6dof_Panthera_params_follower.yaml ← 从臂电机参数
├── motor_1.yaml ← 1 号电机参数
├── motor_6.yaml ← 6 号电机参数
└── robot_config.yaml ← 机器人总配置
配置文件内容示例(Leader.yaml):
robot:
name: "Panthera-HT"
joint_limits: # 关节限位(防止撞到自己)
lower: [-2.4, 0.0, 0.0, -1.6, -1.7, -2.5]
upper: [2.4, 3.2, 4.0, 1.6, 1.7, 2.5]
max_torque: [21, 36, 36, 21, 10, 10] # 最大力矩(Nm)
velocity_limits: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] # 速度限制(rad/s)
acceleration_limits: [2.0, 2.0, 2.0, 2.0, 2.0, 2.0] # 加速度限制(rad/s²)
什么时候需要改:
-
单臂系统:单臂系统:Leader:
end_effector_link = "joint6", Follower:end_effector_link = "tool_link",这会直接影响 IK 计算的末端坐标系,不能混用。 -
双臂系统:主臂用
Leader.yaml,从臂用Follower.yaml -
一般不需要改,除非你想调整安全限位或力矩限制
📂 Panthera-HT_description/ — 机械臂 3D 模型
作用:存放机械臂的 URDF 模型文件,用于运动学和动力学计算。
目录结构:
Panthera-HT_description/
├── urdf/ ← URDF 模型文件
│ ├── Panthera-HT_description_leader.urdf ← 主臂模型
│ └── Panthera-HT_description_follower.urdf ← 从臂模型
├── meshes/ ← 3D 网格文件(.stl/.dae)
│ ├── base_link.stl
│ ├── link1.stl
│ └── ...(每个关节的 3D 模型)
├── config/ ← ROS 配置文件(可选)
└── launch/ ← ROS 启动文件(可选)
URDF 是什么:
-
URDF = Unified Robot Description Format(统一机器人描述格式)
-
它描述了机械臂的"骨架":每个关节的位置、旋转轴、连杆长度、质量等
-
SDK 用它来计算正运动学、逆运动学、重力补偿
你需要关心吗:
-
不需要,SDK 会自动加载
-
除非你想在 RViz(机器人可视化工具)里看 3D 模型
📂 motor_whl/ — 预编译电机驱动包
作用:存放预编译好的 Python 电机驱动包(.whl 文件),直接安装即可使用。
目录结构:
motor_whl/
├── hightorque_robot-1.2.0-cp39-cp39-linux_x86_64.whl ← Python 3.9 (x86_64 PC)
├── hightorque_robot-1.2.0-cp310-cp310-linux_x86_64.whl ← Python 3.10 (x86_64 PC)
├── hightorque_robot-1.2.0-cp311-cp311-linux_x86_64.whl ← Python 3.11 (x86_64 PC)
├── hightorque_robot-1.2.0-cp312-cp312-linux_x86_64.whl ← Python 3.12 (x86_64 PC)
├── hightorque_robot-1.0.0-cp39-cp39-linux_aarch64.whl ← Python 3.9 (ARM,如 Jetson)
├── hightorque_robot-1.0.0-cp310-cp310-linux_aarch64.whl ← Python 3.10 (ARM,如 Jetson)
├── hightorque_robot-1.0.0-cp311-cp311-linux_aarch64.whl ← Python 3.11 (ARM,如 Jetson)
└── hightorque_robot-1.0.0-cp312-cp312-linux_aarch64.whl ← Python 3.12 (ARM,如 Jetson)
安装方法:
pip install motor_whl/hightorque_robot-1.2.0-cp310-cp310-linux_x86_64.whl
这个包是干什么的:
-
它是 C++ 底层驱动的 Python 绑定
-
提供了
hightorque_robot.Robot类,用于和电机通信 -
Panthera_lib就是基于它封装的
📂 images/ — 文档图片
作用:存放 README 里用到的图片。
images/
├── base_joint.png ← 基座坐标系示意图
└── Board.png ← 通信板接线图
用途:帮助你理解硬件连接和坐标系定义。
📂 src/ — Python 绑定源码
作用:C++ 到 Python 的桥梁代码(用 pybind11 写的)。
src/
└── bindings.cpp ← Python 绑定源码
什么时候用:
-
只有从源码编译时才需要
-
如果你用的是预编译 whl 包,不需要关心这个
📄 其他文件
| 文件 | 作用 |
|---|---|
requirements.txt |
Python 依赖列表(pyyaml、pin、scipy) |
README.md |
Python SDK 详细使用说明 |
CMakeLists.txt |
编译配置(从源码安装时用) |
setup.py |
Python 包安装脚本 |
pyproject.toml |
Python 项目配置 |
panthera_cpp/ — C++ 底层代码(高级用户)
这是机械臂的"发动机",用 C++ 写的底层驱动,负责和电机通信。
panthera_cpp/
├── motor_cpp/ ← 电机驱动层(CAN 通信)
├── robot_cpp/ ← 机器人控制层(运动学/动力学)
└── README.md ← C++ SDK 使用说明
你需要关心吗:
-
不需要,除非你想用 C++ 开发
-
Python 用户只需要安装 whl 包即可
📂 motor_cpp/ — 电机驱动层
作用:负责和电机通过 CAN 总线通信,发送控制命令、接收反馈数据。
motor_cpp/
├── include/ ← 头文件
│ ├── motor.hpp ← 电机控制类
│ ├── canport.hpp ← CAN 端口管理
│ ├── robot.hpp ← 机器人类
│ └── ...
├── src/ ← 源文件
│ ├── motor.cpp
│ ├── canport.cpp
│ ├── serial_driver.cpp ← 串口通信驱动
│ └── ...
├── example/ ← C++ 示例代码
├── robot_param/ ← 电机参数配置
├── msg/ ← 消息定义(LCM)
├── third_part/ ← 第三方库
├── CMakeLists.txt ← 编译配置
└── README.md ← 使用说明
核心功能:
-
支持 7 路 CAN 总线,每路最多 30 个电机
-
支持多种控制模式:位置、速度、力矩、MIT 模式
-
支持多种电机型号:M3536、M4538、M5046、M6056 等
📂 robot_cpp/ — 机器人控制层
作用:在电机驱动基础上,提供运动学、动力学、轨迹规划等高层功能。
robot_cpp/
├── include/ ← 头文件
│ └── Panthera.hpp ← Panthera 机器人类
├── src/ ← 源文件
│ └── Panthera.cpp
├── example/ ← C++ 示例代码
├── robot_param/ ← 机器人参数配置
├── Panthera-HT_description/ ← URDF 模型
├── CMakeLists.txt ← 编译配置
└── README.md ← 使用说明
核心功能:
-
正运动学(FK)
-
逆运动学(IK)
-
雅可比矩阵计算
-
重力补偿、摩擦力补偿
-
轨迹插值(五次、七次多项式)
根目录文件
Panthera-HT_SDK/
├── LICENSE ← MIT 开源协议
└── README.md ← 项目总览和快速入门
快速导航:我该看哪个目录?
场景 1:我是 Python 用户,想快速上手
只需要关心:
panthera_python/
├── scripts/ ← 看这里的示例代码
│ ├── 0_robot_get_state.py ← 第一个要跑的
│ ├── 1_Joint_PosVel_control.py ← 学习基础控制
│ └── 5_record_trajectory.py ← 学习拖动示教
├── robot_param/ ← 配置文件(一般不用改)
└── README.md ← 详细使用说明
场景 2:我想理解 SDK 的工作原理
学习路径:
-
先看
panthera_python/scripts/Panthera_lib/Panthera.py(高层封装) -
再看
panthera_cpp/motor_cpp/src/motor.cpp(电机驱动) -
最后看
panthera_cpp/robot_cpp/src/Panthera.cpp(运动学/动力学)
场景 3:我想修改机械臂参数
需要改的文件:
panthera_python/robot_param/
├── Leader.yaml ← 改关节限位、最大力矩
└── motor_param/
└── 6dof_Panthera_params_leader.yaml ← 改电机 ID、CAN 端口
场景 4:我想用 C++ 开发
需要关心:
panthera_cpp/
├── motor_cpp/ ← 电机驱动 API
├── robot_cpp/ ← 机器人控制 API
└── README.md ← C++ 编译和使用说明
目录依赖关系图
你的 Python 脚本
↓ import
Panthera_lib (scripts/Panthera_lib/)
↓ import
hightorque_robot (motor_whl/*.whl)
↓ pybind11 绑定
panthera_cpp/motor_cpp (C++ 电机驱动)
↓ CAN 通信
机械臂硬件
常见问题
Q1:我只想用 Python 控制机械臂,需要编译 C++ 代码吗?
A:不需要,直接安装 motor_whl/ 里的 whl 包即可。
Q2:Panthera_lib 和 hightorque_robot 有什么区别?
A:
-
hightorque_robot:底层电机驱动(C++ 编译的) -
Panthera_lib:高层控制库(Python 写的,基于hightorque_robot封装)
Q3:我该用 Leader.yaml 还是 Follower.yaml?
A:单臂系统:Leader: end_effector_link = "joint6", Follower: end_effector_link = "tool_link",这会直接影响 IK 计算的末端坐标系,不能混用。
双臂系统:主臂用 Leader,从臂用 Follower
Q4:示例代码为什么要在 scripts/ 目录下运行?
A:因为 Panthera_lib 是相对路径导入,必须在 scripts/ 目录下才能找到。
Q5:我想修改示例代码,会影响原文件吗?
A:建议复制一份再改,或者在 scripts/ 目录下新建自己的脚本。
什么是URDF文件?什么是STL文件?这些文件中包含什么,还有什么别的机器人文件??
机器人3D模型与描述文件格式关系说明
1. 概述 (Executive Summary)
在机器人开发与3D仿真(如ROS, MuJoCo, Gazebo)中,模型通常由描述性文件与资产性文件组合而成。XML、URDF、STL、MTL和GLB这五种格式在系统中扮演着截然不同但紧密相连的角色。
简单而言,它们的宏观关系为: XML 是底层语法规范,URDF 基于该规范编写出机器人的逻辑结构(骨架),而 URDF 在渲染外观时,会调用 STL、MTL 或 GLB 这些具体的三维资产(血肉)。
2. 详细格式定义与职责
2.1 XML (eXtensible Markup Language) —— 底层语法
-
角色定义: 数据描述的元语言(语法规则)。
-
技术特性: 纯文本格式,通过自定义的标签(Tags)形成树状层级结构,具备极高的跨平台兼容性和机器可读性。
-
在系统中的作用: 它本身不特指任何物理或三维数据,而是作为 URDF、SDF、MJCF 等机器人规范的底层载体。
2.2 URDF (Unified Robot Description Format) —— 宏观逻辑装配图
-
角色定义: 机器人的运动学与动力学统一描述文件。
-
技术特性: 本质上是基于 XML 语法编写的具体应用文件。包含
<robot>,<link>,<joint>等具有明确物理意义的标签。 -
在系统中的作用: 定义机器人的拓扑结构(连杆与关节的关系)、物理属性(质量、惯性张量)、关节限制(旋转角度、受力极值),并通过
<visual>(视觉)和<collision>(碰撞)标签指向外部的 3D 资产文件。它不包含任何几何图形数据,只包含引用路径。
2.3 STL (Stereolithography) —— 纯粹的三维几何体
-
角色定义: 基础三维网格(Mesh)毛坯文件。
-
技术特性: 仅由空间中的三角形面片(顶点和法线)组成。
-
在系统中的作用: 为 URDF 的
<visual>或<collision>提供最基础的形状数据。致命缺陷是:它不包含任何颜色、材质、纹理、缩放单位信息。
2.4 MTL (Material Template Library) —— 材质与光学属性配方
-
角色定义: 表面视觉属性定义文件。
-
技术特性: 纯文本格式。包含环境光(Ambient)、漫反射(Diffuse)、高光(Specular)参数,以及外部纹理图片(如 .png)的映射路径。
-
在系统中的作用: 通常与
.obj格式的三维网格成对出现。它负责告诉渲染引擎:“该如何给对应的三维毛坯进行上色和光照处理”。
2.5 GLB (GL Transmission Format Binary) —— 现代全栈三维资产
-
角色定义: 包含结构与外观的“一体化”成品模型。
-
技术特性: 基于 glTF 规范的二进制打包文件。
-
在系统中的作用: 将三维网格(替代STL)、PBR 物理渲染材质(替代MTL)和所有纹理贴图(PNG/JPG)打包在单一文件中。在现代机器人仿真开发中,常用于替代繁琐的
STL + 材质定义组合,以实现高效的加载与高度逼真的视觉效果。
3. 系统架构与调用关系图
这五者的关系是一个自上而下的树状调用结构。
[语法层] XML (提供书写规范)
│
▼
[逻辑层] URDF (机器人总装配图,纯代码文件)
│
├── <joint> (定义运动逻辑)
├── <inertial> (定义质量和惯性)
│
└── <visual> / <collision> (定义视觉与物理边界)
│
├─▶ 传统工作流调用:
│ └── .stl (提取形状) + .mtl/内联代码 (提取颜色材质)
│
└─▶ 现代工作流调用:
└── .glb (同时提取形状、材质和纹理)
代码级调用示例 (URDF 内部结构)
以下代码片段展示了 URDF (基于XML) 是如何调用外部三维资产的
<robot name="example_arm">
<link name="base_link">
<visual>
<geometry>
<mesh filename="package://my_robot/meshes/base.glb" />
</geometry>
</visual>
<collision>
<geometry>
<mesh filename="package://my_robot/meshes/base_collision.stl" />
</geometry>
</collision>
</link>
</robot>
4. 选型指南与开发建议 (Best Practices)
| 格式名称 | 本质属性 | 在工程中的建议用法 |
|---|---|---|
| XML | 语法层 | 作为理解 URDF/SDF/MJCF 等文件的基础知识。 |
| URDF | 架构图纸 | 用于定义 ROS 生态中的机器人整体逻辑,必须确保内部路径引用正确。 |
| STL | 基础几何 | 推荐仅用于 <collision>(碰撞计算),因为物理引擎不需要颜色,只需极简的几何体以降低算力消耗。 |
| MTL | 材质库 | 属于历史遗留格式。建议在新的项目中逐渐淘汰分离式的模型+材质工作流,减少文件路径丢失的风险。 |
| GLB | 综合资产 | 强烈推荐用于 <visual>(视觉呈现)。加载快、单文件易于版本控制(Git)、渲染效果(PBR)极佳。 |
注: 在实际排查模型“无法显示”或“全是灰色”的 Bug 时,首先检查 URDF(逻辑图纸)中的路径是否写错,其次检查指向的网格文件是 STL(纯裸模)还是 GLB(带材质)。若是 STL,需在 URDF 内部使用 <material> 标签补充颜色定义。
机器人空间与姿态表示指南
在让机械臂干活之前,我们必须先和它建立一套统一的“空间语言”。否则,你说的“向前走”,机械臂根本不知道是哪个方向。
1. 常用坐标系 (Common Frames of Reference)
在机器人的世界里,没有任何位置是绝对的,所有的位置都是“相对”于某个坐标系而言的。
-
基座坐标系 (Base Frame / World Frame):
-
定义: 建立在机器人底座中心的三维直角坐标系。
-
作用: 它是机器人的“原点”。我们通常把整个环境的世界坐标系与基座坐标系重合。当你发送指令说“移动到 (10,20,30)”时,默认都是相对于基座坐标系。
-
-
关节坐标系 (Joint Frame):
-
定义: 固连在机器人每一个旋转/移动关节上的坐标系。
-
作用: 机械臂在运动时,本质上是上一个关节坐标系带着下一个关节坐标系在旋转。著名的 DH 参数法就是基于关节坐标系建立的。(注:DH参数法不展开讲解,有兴趣可自己查阅(因为随着存储计算压力的降低和现代软件的普及,DH已经没有之前用的那么多了))
-
-
工具中心点坐标系 (TCP Frame / End-Effector Frame):
-
定义: TCP 全称 Tool Center Point。它建立在机器人末端工具(如夹爪、焊枪尖端)上。
-
作用: 机器人真正干活的点。我们平时规划轨迹,其实就是在规划 TCP 坐标系相对于 Base 坐标系的运动。
-
2. 关节空间与笛卡尔空间 (Joint Space vs. Cartesian Space)
理解了坐标系,我们来看机器人学中最核心的“两个世界”。
2.1 关节空间 (Joint Space)
-
视角: 这是“机器人内部”视角的物理真实状态。
-
定义: 用每一个电机的角度(或位移)来描述机器人的状态。
-
数学表示: 对于一个 6 轴机械臂,它的状态是一个 6 维向量:\(q= [\theta_1, \theta_2, \theta_3, \theta_4, \theta_5, \theta_6]^T\)
-
特点: 唯一且绝对。只要这 6 个角度确定了,机械臂的姿态就彻底死死定住了,不存在任何歧义。
2.2 笛卡尔空间 (Cartesian Space / Task Space)
-
视角: 这是“人类外部”视角的直观状态(又称任务空间)。
-
定义: 描述机器人的 TCP 坐标系在三维空间中的位置 (x,y,z) 和 姿态 (朝向)。
-
特点: 符合人类直觉。比如“把杯子水平向前推 5 厘米”,这是在笛卡尔空间下的任务。但是,同一个笛卡尔空间的位姿,机械臂可能有很多种不同的关节角度组合来实现它(比如胳膊肘朝上还是朝下都能摸到同一个杯子)。
3. 欧拉角 (Euler Angles)
位置用 (x,y,z) 描述很简单,但“姿态(朝向)”该怎么描述呢?最符合人类直觉的就是欧拉角。
-
原理: 任何一个三维空间的旋转,都可以分解为绕三个互相垂直的轴(如 X、Y、Z 轴)先后进行的单次旋转。
-
常见标准 (RPY): 航空航天和机器人领域最常用的是 横滚-俯仰-偏航 (Roll-Pitch-Yaw),即依次绕 X、Y、Z 轴旋转:
-
Roll (γ): 绕 X 轴旋转(像飞机左右摇摆翅膀)。
-
Pitch (β): 绕 Y 轴旋转(像飞机机头抬起或低头)。
-
Yaw (α): 绕 Z 轴旋转(像汽车在平地上左右转弯)。
-
-
优点: 极其直观,用三个数字就能看懂物体的朝向。
-
缺点: 旋转顺序极其重要!先绕 X 转再绕 Y 转,与先绕 Y 转再绕 X 转,最终的姿态是完全不同的。此外,它有一个致命的数学缺陷——万向节锁。
4. 万向节锁 (Gimbal Lock)
万向节锁是欧拉角的核心问题。
-
现象: 当中间那个旋转轴(比如 Pitch 俯仰角)旋转了恰好 90∘(或 −90∘)时,机器人的第一根旋转轴和第三根旋转轴会在物理空间上重合。
-
后果: 此时,改变 Roll 和改变 Yaw 产生的动作变成了一模一样的(比如飞机机头直直朝向天空时,原来的“左右转 Yaw”和“自转 Roll”变成了一个动作)。系统在这一瞬间丢失了一个自由度,也就是丢失了在某一个特定方向上的旋转能力。
-
在机器人中的影响: 如果你在笛卡尔空间进行直线插补,恰好经过了万向节锁的奇异点,底层的数学计算会除以零,导致机械臂电机瞬间暴走或卡死。
5. 四元数 (Quaternions)
为了解决万向节锁,数学家发明(或者说引入)了四元数,它是目前几乎所有高级机器人 SDK 和 3D 游戏引擎底层处理旋转的唯一标准。
-
核心思想: 不再拆分成三次旋转,而是定义空间中的一根“任意轴向量” v,然后让物体绕着这根轴一次性旋转一个角度 θ。
-
表示形式: 四元数由一个实部和三个虚部组成,通常记作四维向量:\(q = [w, x, y, z]\)
它的内部数学关系为:\(w = \cos(\frac{\theta}{2}), \quad x = v_x\sin(\frac{\theta}{2}), \quad y = v_y\sin(\frac{\theta}{2}), \quad z = v_z\sin(\frac{\theta}{2})\)
-
优点:
-
彻底免疫万向节锁,没有任何奇异点。
-
计算效率极高,空间插值(Slerp)非常丝滑。
-
-
缺点: 对人类极度不友好。看到一个四元数 [0.707,0,0.707,0],人脑几乎无法直接想象出它的姿态(其实它是绕 Y 轴转了 90∘)。
6. 旋转矩阵 (Rotation Matrix)
除了欧拉角和四元数,在进行严谨的数学推导(如运动学方程)时,我们最常使用的是旋转矩阵。
定义: 用一个 3×3 的矩阵来表示一个坐标系相对于另一个坐标系的朝向。
数学本质: 矩阵内部的每一列,其实就是新的坐标系(X, Y, Z轴)在旧坐标系下的单位向量投影.\(R = \begin{bmatrix} r_{11} & r_{12} & r_{13} \ r_{21} & r_{22} & r_{23} \ r_{31} & r_{32} & r_{33} \end{bmatrix}\)
基本旋转: 比如绕 Z 轴旋转 θ 的矩阵为:\(R_z(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 \ \sin\theta & \cos\theta & 0 \ 0 & 0 & 1 \end{bmatrix}\)
优缺点: 非常适合矩阵运算(组合多次旋转只需把矩阵乘起来)。但它用 9 个数字来表示本来只有 3 个自由度的旋转,数据冗余度太高。
7. 齐次变换矩阵 (Homogeneous Transformation Matrix)
最后,我们要把前面讲的“位置”和“姿态”拼装在一起,这就是大名鼎鼎的齐次变换矩阵。它是机器人学计算的终极武器。
-
为何引入: 纯粹的矩阵乘法只能算旋转,不能算平移(平移是加法)。为了让计算机能通过单一的“矩阵连乘”同时算出旋转和平移,我们在数学上扩充了一个维度。
-
结构: 这是一个 4×4 的矩阵,记为 \(T = \begin{bmatrix} R_{3 \times 3} & p_{3 \times 1} \ 0_{1 \times 3} & 1 \end{bmatrix} = \begin{bmatrix} r_{11} & r_{12} & r_{13} & x \ r_{21} & r_{22} & r_{23} & y \ r_{31} & r_{32} & r_{33} & z \ 0 & 0 & 0 & 1 \end{bmatrix}\)
-
左上角 R: 代表姿态的 3×3 旋转矩阵。
-
右上角 p: 代表位置平移的 3×1 列向量 (x,y,z)。
-
底部行: 固定的 [0,0,0,1],为了维持数学维度的齐次性。
-
它的威力有多大? 假设机械臂有 6 个关节,每个关节的变换矩阵分别是 \(T_1, T_2, \dots, T_6\)。你想知道末端执行器在哪里?极其简单,全部乘起来:
\(T_{TCP} = T_1 \times T_2 \times T_3 \times T_4 \times T_5 \times T_6\)
算出来的\(T_{TCP}\) 矩阵,右上角的三个数就是手端的 (x,y,z),左上角就是它的朝向。
机器人控制进阶篇:雅可比矩阵、插值算法与轨迹平滑
在我们了解了单关节底层的“发力原理”(PD/PID 控制)之后,要想让一个拥有 6 个关节的机械臂像人类手臂一样优雅、丝滑地在空间中干活,我们还面临着三个巨大的挑战:
速度与力的传导__: 电机转速是如何映射成手端移动速度的?
路径的生成__: 给定起点和终点,中间的空白路径该怎么补齐?
消除机械感__: 如何防止机械臂在拐弯时发生剧烈的“抽搐”和抖动?
为了解决这三个问题,机器人学引入了三个极其核心的数学工具:雅可比矩阵 (Jacobian Matrix)、插值算法 (Interpolation) 以及 平滑算法 (Smoothing)。
-
雅可比矩阵 (Jacobian Matrix):跨越两个空间的“无级变速箱”
在稍后的运动学 (FK/IK) 章节中,你会学到如何计算“位置”。但机器人在运动时,我们更关心的是“速度”和“力”。 1.1 什么是雅可比矩阵?
简单来说,雅可比矩阵 J 是一座桥梁,它建立了关节空间速度(各个电机转得有多快)与笛卡尔空间速度(手端在空间中飞得有多快)之间的线性关系。
它的核心数学公式极其简洁:\(\dot{X} = J(q)\dot{q}\)
\(\dot{q}\):关节角速度向量 \([\dot{\theta}_1, \dot{\theta}_2, \dots, \dot{\theta}_6]^T\)(即 6 个电机的瞬时转速)。
\(\dot{X}\):末端执行器在三维空间中的速度向量 \([v_x, v_y, v_z, \omega_x, \omega_y, \omega_z]^T\)(包含 3 个方向的直线速度和 3 个方向的旋转角速度)。
\(J(q)\):雅可比矩阵。对于 6 轴机械臂,它是一个 6×6 的矩阵。
⚠️ 核心注意点: 雅可比矩阵不是固定不变的!公式里的 \(J(q)\) 意味着,机械臂每改变一次姿态 \(q\),雅可比矩阵里面的数字就会瞬间刷新一次。
1.2 通俗比喻:杠杆与变速箱
你可以把雅可比矩阵想象成自行车的“动态变速齿轮”或物理学中的“杠杆”。
当你的手臂完全伸直去挥动一根长棍时(此时对应的 J 矩阵数值很大),你的肩膀只需转动一点点角度(很小的 q˙),棍子尖端就会产生极高的速度(很大的 X˙)。
相反,当你的手臂紧紧缩在胸前时,同样转动肩膀,手端的位移就很小。
雅可比矩阵里的每一个数字,都在精确回答:“在当前这个特定的姿态下,第 i 个电机稍微动一下,手端会在 X/Y/Z 方向上产生多大比例的移动?”
1.3 雅可比矩阵的两大杀手锏
除了算速度,雅可比矩阵在高级控制(如 Panthera-HT 机器人的阻抗控制)中还有两个极其重要的作用:
力的映射(静力学传导)
通过虚功原理,雅可比矩阵的转置 JT 可以将手端受到的外界力,完美转化为每个电机需要输出的扭矩:\(\tau = J^T(q)F\).这就是实现“拖动示教”和“碰撞检测”的核心底层公式。当人手推机械臂末端时,系统测出受力 \(F\),乘上\(J^T\) 就能瞬间算出每个电机该退让多少力矩 \(\tau\)。
奇异点分析 (Singularity):
如果机械臂完全伸直,或者某两个旋转轴在空间中重合了,数学上雅可比矩阵的行列式就会变成零,即 \(\det(J) = 0\)。此时矩阵不可逆,机械臂会瞬间丢失某个方向的运动自由度(无论电机怎么转,手端都无法向某个特定方向移动)。在奇异点附近,极小的末端速度会要求电机爆发出无穷大的转速,导致机械臂暴走停机。高级 SDK 都会利用雅可比矩阵提前预测并避开奇异点。
1.4 机器人的“物理黑洞”:奇异点 (Singularity) 与降秩
数学本质:雅可比矩阵的“降秩” 在线性代数中,矩阵的秩(Rank)代表了它所能掌控的空间维度。对于一台健康的 6 轴机械臂,它的雅可比矩阵 J 是满秩的(Rank = 6),意味着它可以在 3D 空间中自由地进行 6 个方向的移动和旋转。 但是,当机械臂运动到某些特定的几何姿态时,矩阵 J 的某些行或列会变得线性相关,导致行列式变成零 (det(J)=0)。此时,矩阵降秩了(比如 Rank 变成了 5)。
物理表现:自由度的瞬间蒸发 “降秩”在物理世界中的表现极其冷酷:机械臂在这一瞬间,被物理学定律死死地“锁”住了一个维度。 它突然从 6 自由度退化成了 5 自由度。在那个丢失的维度上,无论这 6 个电机怎么疯狂转动,手端都无法移动哪怕 1 毫米。
在工业机械臂上,最容易触发的三大经典奇异点是:
边界奇异 (Boundary Singularity):手臂完全伸直,想够极远的东西。此时它丢失了继续向前平移的能力。
腕部奇异 (Wrist Singularity):第 4 轴和第 6 轴的旋转中心线重合(成一条直线)。此时两个电机的作用互相抵消,彻底丢失了一个让法兰盘横向摆动的旋转自由度。
肩部/肘部奇异 (Shoulder/Elbow Singularity):手腕中心点被拉到了底座的正上方。此时底座电机怎么转,手腕中心都不会平移。
为什么会导致速度爆炸? 结合我们刚才的公式:\(\dot{q} = J^{-1}\dot{X}\)。 因为矩阵降秩不可逆,相当于公式里出现了“除以 0”的绝境。如果此时算法然强行要求手端在那个“丢失的维度”上移动 1 毫米,算法就会疯掉,命令电机:“既然你们的效率趋近于 0,那就用无限大的转速来凑!”这就是导致机械臂暴走的元凶。
-
轨迹插值算法 (Interpolation):如何“连点成线”
在笛卡尔空间中,假设你想让机械臂从 A 点走到 B 点,你不能只给控制器下发两个点。因为计算机很笨,它不知道 A 到 B 之间该走直线、走曲线还是绕圈圈。
插值,就是按照特定的数学规律,在起点和终点之间密密麻麻地塞满中间点(比如在 SDK 中,直线插补 moveL 每隔 2mm 就会切分出一个中间点)。
(注:市面上有许多插值和平滑算法,我们只讲SDK用到的,有兴趣的自行查阅其他)
在三维空间中,“位置”和“姿态”的物理性质完全不同,因此必须使用两套完全不同的插值算法: 2.1 位置插值:线性插值 (LERP, Linear Interpolation)
数学原理: 按照时间比例 t(从 0 到 1),在三维坐标系中等比例分配距离。
公式:\(P(t) = (1 - t)P_{start} + t P_{end}\)
表现: 机械臂末端在空间中画出一条绝对笔直的线,各轴的移动速度是匀速的。
2.2 姿态插值:球面线性插值 (SLERP, Spherical Linear Interpolation)
数学原理: 我们在前面的章节讲过,四元数代表了四维空间超球面上的一个点。SLERP 算法并不是在两点之间直接“穿透”球体画直线,而是沿着球面的大圆弧线(最短路径)匀速滑过去。
公式:\(\frac{\sin((1-t)\theta)}{\sin\theta} q_{start} + \frac{\sin(t\theta)}{\sin\theta} q_{end}\)
夹角 Theta 的点积求法:\(\cos\theta = q_{start} \cdot q_{end} = w_1 w_2 + x_1 x_2 + y_1 y_2 + z_1 z_2\)
变量说明中的数学符号:\(t \in [0, 1]\) \(\cos\theta < 0 -q_{end}\)
表现: 保证了机械臂在从“朝向 A”旋转到“朝向 B”的过程中,角速度是绝对恒定且平滑的,走出了物理空间中最短的旋转路径,且完美避开了万向节锁。
-
轨迹平滑算法 (Smoothing):告别“机械抽搐”
有了 LERP 和 SLERP 算法,我们虽然得到了密密麻麻的路径点,但它们连起来本质上是一条“折线”。 在机器人身上。如果在途经点直接生硬地改变方向,加速度的不连续会导致电机瞬间面临极端的电流尖峰,齿轮会发出打齿的异响,整个机械臂会剧烈震颤。
为了让运动像人类手臂一样柔顺,我们需要用平滑算法把“折线的棱角”磨平。 3.1 三次样条平滑 (Cubic Spline)
Panthera SDK 的 smooth_trajectory_spline 模块使用了经典的三次样条插值技术。
数学原理: 工程师不再用死板的直线去连接途径点,而是用很多段三次多项式方程\(y = a t^3 + b t^2 + c t + d\)把所有的点像缝缝合起来。
极其严苛的数学保证(平滑的三重境界):
位置连续 (C0 连续): 曲线完美穿过所有的途经点,不脱节。
速度连续 (C1 连续): 曲线在任何一点的一阶导数(速度)是平滑过渡的,没有瞬间的速度突变。
加速度连续 (C2 连续): 这是最关键的一点!曲线的二阶导数(加速度)也是连续的,没有突变。
怎么解?:
假设我们有n个点,[\(p_0,p_1.....p_{n-1}\)],那我们就需要\(n-1\)个三次方程(每两个点之间一个),有\(4n-4\)
个位置量,那需要解\(4n-4\)个线性方程:
1.\(n-1\)段曲线,每段都有起点和终点(2 个点)。(\(2n-2\))
2.除了起点和终点,内部有\(n-2\) 个内部连接点(即交接棒的地方)。每一个交接点要求前一段末速度等于后一段初速度。(\(n-2\) )
3.\(n-2\) 个内部连接点加速度连续(\(n-2\) )
4.起点和终点,通常默认加速度为 0(自然边界)(\(2\))
\((2n-2)+(n-2)+(n-2)+2=4n-4\)
Q:为什么要控制加加速度 (Jerk)?
A:加速度连续,意味着加速度的变化率是有上限的。在物理学中,加速度的变化率被称为“冲击度”或“加加速度 (Jerk)”。:过大的 Jerk 就是导致机器人抖动、磨损减速器的元凶。三次样条曲线成功限制了 Jerk。当这段经过平滑处理的轨迹下发给电机的 PD 控制器时,电机接收到的是一条极其丝滑的指令流,机械臂的起步、加速、过弯、减速、停止一气呵成,彻底消除了“机械感”。
机器人关节底层控制原理:PD、前馈与 PID 详解
在机器人关节控制中,为了让机械臂平稳、精准地到达目标位置并输出期望的力矩,底层通常采用基于反馈与前馈结合的控制算法。本文档将详细解析 PD 控制、前馈力矩(Feedforward)以及完整的 PID 控制原理。
1. PD 控制 (Proportional-Derivative Control)
PD 控制是机器人关节中最常用的反馈控制策略(如 MIT 模式的核心)。它由比例(Proportional)和微分(Derivative)两部分组成,通过计算当前状态与目标状态之间的误差来实时调整输出力矩。
1.1 控制公式
关节的输出力矩计算公式如下:
\(\tau_{PD} = K_p e(t) + K_d \dot{e}(t)\)
其中:
-
\(e(t) = \theta_{target} - \theta_{current}\)表示位置误差。
-
\(\dot{e}(t) = \omega_{target} - \omega_{current}\)表示速度误差。
-
\(K_{p}\) 为比例增益(位置刚度)。
-
\(K_{d}\)为微分增益(速度阻尼)。
1.2 物理意义与直观比喻
-
P (Proportional) 比例项 —— 虚拟弹簧
-
原理: 误差越大,输出的修正力矩越大。
-
比喻: 相当于在当前位置和目标位置之间拉了一根弹簧。\(K_{p}\) 就是弹簧的刚度系数。\(K_{p}\) 越大,弹簧越硬,机械臂被拉向目标位置的速度越快,但也越容易产生过冲(越过目标点)。
-
-
D (Derivative) 微分项 —— 虚拟减震器
-
原理: 阻碍误差的变化趋势。当系统快速向目标移动时,它会产生反向阻力以防止过冲。
-
比喻: 相当于在运动方向上安装了一个阻尼器(减震器)。\(K_{d}\) 就是阻尼系数。\(K_{d}\) 越大,系统在高速运动时感受到的“粘滞阻力”越大,能有效抑制震荡,但设置过大会导致系统响应迟钝。
-
2. 前馈力矩 (Feedforward Torque)
单纯依靠 PD 等反馈控制存在一个致命缺陷:只有产生误差,才会输出力矩。 在实际机械臂中,受到重力、摩擦力或外部负载的影响,单纯的 PD 控制会让机械臂在到达目标位置前,由于拉力(P)与重力平衡而停留在半空中(即产生稳态误差)。
前馈力矩(Feedforward Torque, 记作 \(\tau_{ff}\)) 是一种“未卜先知”的开环控制策略。它不依赖传感器的误差反馈,而是根据机器人的动力学模型,提前计算出维持期望运动所需的基础力矩。
2.1 融合控制公式
现代机器人控制通常采用 “前馈 + 反馈” 的复合控制架构:\(\tau_{total} = \tau_{ff} + \tau_{PD}\)
2.2 典型应用场景
-
重力补偿 (Gravity Compensation): 算法提前计算出机械臂当前姿态下受到的重力,并通过 \(\tau_{ff}\)发送等大反向的力矩给电机。此时,电机的 PD 控制器只需要克服惯性去改变位置,实现了“零重力”的拖动示教体验。
-
科里奥利力与离心力补偿: 在高速运动时,提前计算并抵消多关节耦合产生的复杂动力学力。
-
摩擦力补偿: 提前输出刚好能克服关节静摩擦力的前馈力矩,提高系统的微动响应。
3. PID 控制 (Proportional-Integral-Derivative Control)
PID 是工业界最经典、最广泛使用的控制算法。相比于 PD 控制,它多了一个 积分(Integral) 项。
3.1 控制公式
完整的 PID 连续域公式为:\(\tau(t) = K_p e(t) + K_i \int_{0}^{t} e(\tau) d\tau + K_d \frac{de(t)}{dt}\)
3.2 I (Integral) 积分项的意义
-
原理解析: 积分项是对过去所有误差的时间累积。即使当前的位置误差 \(e(t)\) 非常小(小到\(K_p e(t)\) 无法克服静摩擦力),只要这个极小的误差持续存在,积分项 ∫e(t)dt 就会随着时间不断累加,最终输出足够大的力矩推动系统消除最后的误差。
-
核心作用:消除稳态误差 (Steady-state error)。
-
在机器人关节中的局限性: 尽管 PID 在电机底层转速控制或温度控制中极度常见,但在高级机器人的位置/阻抗控制中,通常很少开启积分项(即设 Ki=0)。
-
原因 1(安全): 当机械臂被障碍物卡住时,误差持续存在,积分项会疯狂累加(称为积分饱和,Integral Windup),导致输出极其危险的巨大力矩。
-
原因 2(替代方案): 在机器人领域,通常使用极其精确的动力学模型计算出前馈力矩(Feedforward)来消除稳态误差,而不是依赖具有滞后性且容易导致不稳定的积分项。
-
4. 总结对比表
| 控制策略 / 术语 | 核心作用 | 物理比喻 | 响应特性 | 在机械臂中的典型应用 |
|---|---|---|---|---|
| P (比例) | 根据当前误差提供驱动力 | 弹簧 | 决定系统响应速度与刚度 | 决定阻抗控制中的位置刚度 |
| D (微分) | 抑制误差变化速率 | 减震器 | 消除震荡,提高系统稳定性 | 决定阻抗控制中的粘滞阻尼 |
| I (积分) | 累积历史误差,彻底消除残差 | 执着的推手 | 反应最慢,容易导致系统震荡或危险的力矩饱合 | 通常关闭。极少用于柔顺控制,多用于无前馈的纯工业点位控制 |
| Feedforward (前馈) | 基于动力学模型提前发力 | 预判型助手 | 零延迟响应,主动抵消已知干扰(重力、科氏力等) |
机器人运动学 (FK 与 IK) 及 SDK 底层实现
在理解了底层力矩控制和空间坐标系后,我们需要解决机器人学中最核心的几何路径问题:如何让机械臂在关节空间(电机角度)与笛卡尔空间(三维坐标)之间自由转换。这就是正运动学 (FK) 与逆运动学 (IK) 的任务。
在 Panthera-HT SDK 中,为了保证极致的计算效率与工业级稳定性,底层并未采用手写的低效算法,而是全面接入了目前学界与工业界顶级的刚体动力学计算库 —— Pinocchio。
-
SDK 中的笛卡尔数据格式标准
在调用 FK 和 IK 之前,必须严格遵守 SDK 定义的数据类型与物理单位:
关节角 (Joint Angles): np.ndarray 或 list,长度 6,单位:弧度 (rad)。
位置 (Position): list 或 np.ndarray,格式为 [x, y, z],单位:米 (m)。
姿态 (Rotation): np.ndarray,格式为 3×3 旋转矩阵(彻底抛弃易导致万向节锁的欧拉角)。
完整位姿 (Transform): 内部统一使用 4×4 齐次变换矩阵。
-
正运动学 (Forward Kinematics, FK)
核心概念:“顺藤摸瓜” —— 已知电机的角度,求机械臂末端在哪。
正运动学是一个确定性的计算过程,没有任何歧义。只要给定一组唯一的关节角 \(q=[{\theta}_1, {\theta}_2, \dots, {\theta}_6]^T\),机械臂的末端 (TCP) 就会存在于空间中唯一确定的位姿。它的数学本质就是一系列齐次变换矩阵的连乘: \(T_{TCP} = T_1 \times T_2 \times T_3 \times T_4 \times T_5 \times T_6\)
2.1 Panthera SDK 底层实现解析
当你在代码中调用 fk = robot.forward_kinematics(joint_angles) 时,底层按以下三步极速执行:
数据对齐入库:真实机器人的 URDF 模型可能包含不可动的固定关节。SDK 会遍历查找当前 6 个活动关节的内部 ID,并将输入的角度精准填入 Pinocchio 维护的全局配置向量 q 中。
触发物理引擎:调用 pin.forwardKinematics 和 pin.updateFramePlacements。底层 C++ 代码根据 URDF 文件中定义的关节轴方向和连杆长度,瞬间完成整条运动链的矩阵连乘运算。
提取目标位姿:通过 eef_transform = self.data.oMf[self.end_effector_frame_id] 提取末端执行器相对于基座的原点变换矩阵 (Origin to Frame),并拆分为 position (平移) 和 rotation (旋转) 返回给用户。
-
逆运动学 (Inverse Kinematics, IK)
核心概念:“按图索骥” —— 已知想要到达的目标位置,反推电机该怎么转。
逆运动学是整个运动控制中最复杂的环节。同一个目标位置,机械臂通常有多种不同的姿态可以到达(例如“胳膊肘朝上”或“朝下”),同时在到达极限距离或奇异点时可能面临无解或系统崩溃。
(注:市面上有很多IK解法,这里只讲DLS)
3.1 Panthera SDK 的 DLS 数值解法
Panthera SDK 的 IK 并没有使用传统的解析几何法,而是采用了高度鲁棒的数值迭代算法:自适应阻尼最小二乘法 (Adaptive DLS)。
当调用 robot.inverse_kinematics(...) 时,核心迭代逻辑如下:
李群 SE(3) 误差映射:
为了避免欧拉角减法导致的奇异性,底层使用 iMd = self.data.oMf[frame_id].actInv(oMdes) 计算当前位姿到目标位姿的偏差,并通过 pin.log(iMd).vector 将其映射到李代数空间,生成一个包含线速度与角速度误差的 6 维向量 err:\(\text{err} = [ \Delta x, \Delta y, \Delta z, \Delta \theta_x, \Delta \theta_y, \Delta \theta_z ]^T\)
雅可比矩阵变换:
计算机械臂当前的雅可比矩阵 J。雅可比矩阵是建立关节速度与末端速度之间关系的桥梁。
自适应阻尼引入:\(\Delta q = J^T (J J^T + \lambda^2 I)^{-1} \text{err}\)
这就是 DLS 的核心公式。如果直接对矩阵求逆(即 λ=0 时的伪逆法),在靠近奇异点时数值会爆炸。SDK 引入了自适应阻尼系数 λ:误差大时阻尼小(快速逼近),误差小时阻尼大(精细收敛防震荡)。
多初始值策略 (Multi-init):
为了防止数值迭代陷入局部最优解(死胡同),SDK 会并行或依次启用多组初始猜测点:当前位置、全零位、关节限位中点以及 5 组随机姿态。分别进行迭代求解后,返回误差最小的那一组解,极大提升了求解成功率。
-
终极协同:moveL 笛卡尔直线运动链路
理解了 FK 和 IK,就能彻底看懂 SDK 中最常用的 moveL(笛卡尔直线插补)指令是如何将二者结合运作的:
确定起点 (FK): 引擎先用 FK 算出当前末端的确切位姿作为直线起点。
路径采样 : 在起点与目标点之间,每隔 2mm 采样一个路径点。位置使用线性插值,姿态使用 SLERP(球面线性插值)。
逆解IK (IK): 对生成的每一个离散路径点,利用上述的 DLS IK 算法反推出 6 个关节角度。此时若发现相邻点角度跳变过大(>1.5 rad),则判定触发奇异点,拒绝执行以保护硬件。
曲线平滑 (三次样条): 将算出的离散关节角扔进 scipy.interpolate.CubicSpline 进行三次样条平滑,重采样至 100Hz 的高频控制周期,并同步求导获取速度。
下发执行: 将平滑后的位姿与速度数组,通过 CAN 总线下发给底层电机的 PD 控制器执行。
Q:纯learning的方式已经可以end-to-end比较好地解决action的问题,我为什么还要学习机器人运动学?
-
纯端到端学习,意味着你要让神经网络在成千上万次的试错中,自己去重新“领悟”重力是什么、科氏力是什么、杠杆原理是什么。这不仅极其浪费算力,而且一旦机械臂换了一个夹爪(质量变了),网络可能就得重新训练。
-
传统理论的优雅: 人类花了三百多年建立的牛顿力学、拉格朗日动力学是完美且已知的。既然我们已经有了极其精确的物理方程,为什么要让瞎子去摸象? 聪明的做法是:用已知方程(如动力学前馈、LCP 接触模型)去处理确定的物理规律,只让神经网络去学那些难以建模的东西(比如复杂的摩擦力、视觉特征、高级决策)。
-
在 Isaac Gym 等仿真里,纯 RL 可以训练出飞天遁地的机器狗。但一旦部署到真机上,因为仿真里的电机响应、减速器背隙、柔性变形不可能 100% 还原真实世界,纯 E2E 网络往往一落地就摔倒、疯狂抖动。
-
传统控制的兜底: 传统控制(特别是基于 QP 的 WBC 阻抗控制)天生就具备极强的抗干扰能力和柔顺性。如果你在底层挂一个优秀的 WBC,高层的 RL 网络只需要输出一个“粗糙的意图”,底层控制会自动帮你吸收掉仿真和现实之间的误差。
学习运动/动力学的过程本身就是一种锻炼自己数理能力和逻辑思维的方式,自身数理水平的加强又会反哺到learning的学习之中。