turtlebot3-burger_150.png
turtlebot3-waffle-pi_150.png
turtlebot3-arm_150.png
walking-y2_150.png
turbot3-multi_150.png
turbot3-dl-ros1_150.png
turbot3-ai.png
turbot3-dl-ros2_150.png
turbot3-slam_150.png
turbot3-arm_150.png
turtlebot4-lite_150.png
turtlebot4-pro_150.png
turbot4-dl_150.png
turbot4-ai_150.png
aidriving-racebot_150.png
aidriving-autodrive_150.png
turtlebot-arm_150.png
openmanipulator-x_150.png
Home » OpenDuckMini强化学习框架入门教程 » OpenDuckMini强化学习框架入门教程-参考运动生成

OpenDuckMini强化学习框架入门教程-参考运动生成

纠错,疑问,交流: 请进入讨论区请点击进入页面,扫码加入微信群或Q群进行交流

获取最新文章: 扫一扫加入“创客智造”公众号

欢迎加入我们的openduckmini交流群,微信扫描右侧二维码立即进群交流

群二维码

参考运动生成

  • 理解参考运动及生成,包含PolyReferenceMotion 类,速度到索引的映射,多项式采样,参考运动包含的维度和索引,可视化测试,与推理系统的交互和生成自己的参考运动等

概述

参考运动生成系统使用多项式拟合方法,将预定义的关节轨迹压缩为多项式系数,在训练和推理过程中实时解码。这种方式避免了存储大量原始运动数据,同时支持不同速度命令下的运动插值。

PolyReferenceMotion 类

定义在 playground/common/poly_reference_motion.py(JAX 版本,用于训练)和 playground/common/poly_reference_motion_numpy.py(NumPy 版本,用于推理)。

初始化

class PolyReferenceMotion:
    def __init__(self, polynomial_coefficients: str):
        data = pickle.load(open(polynomial_coefficients, "rb"))
        self.process(data)

输入文件为 pickle 格式,包含多个运动参数组合的多项式系数。

数据结构

参考运动数据按速度命令组织:

polynomial_coefficients.pkl
│
├── "dx_dy_dtheta"          ← 键: "0.0_0.0_0.0"
│   ├── period              ← 运动周期 (s)
│   ├── fps                 ← 帧率 (Hz)
│   ├── frame_offsets       ← 帧偏移
│   ├── startend_double_support_ratio  ← 双足支撑期比例
│   ├── coefficients        ← 多项式系数 (每维[左腿5, 头4, 天线2, 右腿5])
│   │   ├── dim_0: [c0, c1, c2, ...]  ← 关节位置拟合多项式系数
│   │   ├── dim_1: [...]
│   │   └── ...
│   └── ...
│
├── "0.05_0.0_0.0"          ← 不同速度组合
├── "0.0_0.05_0.0"
└── ...

数据处理

process() 方法将原始数据转换为 JAX 数组:

def process(self, data):
    # 提取速度范围
    self.dx_range = [min_dx, max_dx]
    self.dy_range = [min_dy, max_dy]
    self.dtheta_range = [min_dtheta, max_dtheta]
    
    # 所有速度组合的离散值
    self.dxs = sorted([-0.15, 0, 0.15, ...])   # 前进速度离散点
    self.dys = sorted([-0.2, 0, 0.2, ...])     # 横向速度离散点
    self.dthetas = sorted([-1.0, 0, 1.0, ...])  # 旋转速度离散点
    
    # 构建三维数组: [len(dxs), len(dys), len(dthetas), n_dims, poly_order]
    self.data_array = jp.array(...)
    
    # 运动参数
    self.period = 0.5         # 运动周期 (s)
    self.fps = 50              # 50 Hz
    self.nb_steps_in_period = int(period * fps)  # 每周期步数 (25)
    self.start_offset = ...    # 双足支撑期对应的帧数

速度到索引的映射

由于参考运动只在离散的速度点上采样,需要使用最近邻搜索:

def vel_to_index(self, dx, dy, dtheta):
    # 裁剪到有效范围
    dx = clip(dx, dx_range[0], dx_range[1])
    dy = clip(dy, dy_range[0], dy_range[1])
    dtheta = clip(dtheta, dtheta_range[0], dtheta_range[1])
    
    # 最近邻搜索
    ix = argmin(abs(dxs - dx))
    iy = argmin(abs(dys - dy))
    itheta = argmin(abs(dthetas - dtheta))
    
    return ix, iy, itheta

多项式采样

多项式计算

def sample_polynomial(self, t, coeffs):
    # 对每个维度计算多项式值
    # coeffs 形状: [n_dims, poly_order+1]
    # 返回: [n_dims]
    return vmap(lambda c: jp.polyval(c, t))(coeffs)

使用 jp.polyval(即 Horner 法则)高效计算多项式值。 通过 vmap 在维度间向量化。

参考运动获取

def get_reference_motion(self, dx, dy, dtheta, i):
    # 1. 速度 → 索引
    ix, iy, itheta = self.vel_to_index(dx, dy, dtheta)
    
    # 2. 相位归一化 (0~1)
    t = (i % nb_steps_in_period) / nb_steps_in_period
    t = clip(t, 0.0, 1.0)
    
    # 3. 采样多项式
    ret = self.sample_polynomial(t, self.data_array[ix][iy][itheta])
    return ret  # 形状: [40]

多项式拟合原理

原始运动数据:
  time  →  [joint_1, joint_2, ..., joint_16]
  t=0   →  [pos_1, pos_2, ..., pos_16]
  t=1   →  [...]
  ...

多项式拟合:
  对每个关节维度 j:
    使用最小二乘法拟合多项式 P_j(t)
    使得 P_j(t_i) ≈ pos_j(t_i) 对所有时间点 i

  结果:
    16 个多项式 P_0(t), P_1(t), ..., P_15(t)
    每个多项式 5-7 阶

推理:
  给定时间 t → P_j(t) → 关节 j 的位置

参考运动包含的维度和索引

参考帧(40 维)中各维度的含义:

索引  0:  left_hip_yaw 位置
  1:  left_hip_roll 位置
  2:  left_hip_pitch 位置
  3:  left_knee 位置
  4:  left_ankle 位置
  5:  neck_pitch 位置
  6:  head_pitch 位置
  7:  head_yaw 位置
  8:  head_roll 位置
  9:  left_antenna 位置
 10:  right_antenna 位置
 11:  right_hip_yaw 位置
 12:  right_hip_roll 位置
 13:  right_hip_pitch 位置
 14:  right_knee 位置
 15:  right_ankle 位置
 ─────────────────────────
 16:  left_hip_yaw 速度
 17:  left_hip_roll 速度
 ...
 31:  right_ankle 速度
 ─────────────────────────
 32:  left foot contact
 33:  right foot contact
 ─────────────────────────
 34:  base_linear_vel x
 35:  base_linear_vel y
 36:  base_linear_vel z
 ─────────────────────────
 37:  base_angular_vel x
 38:  base_angular_vel y
 39:  base_angular_vel z

可视化测试

PolyReferenceMotion 包含一个简单的主函数用于可视化测试:

if __name__ == "__main__":
    PRM = PolyReferenceMotion("...data/polynomial_coefficients.pkl")
    vals = []
    for i in range(PRM.nb_steps_in_period):
        vals.append(PRM.get_reference_motion(0.0, -0.05, -0.1, i)[dim])
    
    import matplotlib.pyplot as plt
    ts = np.arange(PRM.nb_steps_in_period)
    plt.plot(ts, vals)
    plt.show()

与推理系统的交互

在推理(mujoco_infer.py)中使用 NumPy 版本:

self.PRM = PolyReferenceMotion(reference_data)
self.imitation_i = 0

# 控制循环中
self.imitation_i = (self.imitation_i + 1) % self.PRM.nb_steps_in_period
self.imitation_phase = np.array([
    cos(self.imitation_i / N * 2 * pi),
    sin(self.imitation_i / N * 2 * pi),
])

相位信息 imitation_phase 作为观测的一部分传递给策略网络,帮助策略感知当前的步态相位。

生成自己的参考运动

参考运动数据需要使用独立的生成工具创建,详见 Open Duck 参考运动生成器 仓库。基本流程:

  1. 录制或设计机器人每个关节的轨迹
  2. 将轨迹分割为不同速度条件下的运动周期
  3. 对每个周期的每维数据进行多项式拟合
  4. 打包为 polynomial_coefficients.pkl 文件

纠错,疑问,交流: 请进入讨论区请点击进入页面,扫码加入微信群或Q群进行交流

获取最新文章: 扫一扫加入“创客智造”公众号

欢迎加入我们的openduckmini交流群,微信扫描右侧二维码立即进群交流

群二维码

标签: OpenDuckMini强化学习框架