ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

动态运动基元DMP:机器人轨迹规划中的学习与泛化核心技术

2026/8/30 18:49:26 拓冰建站 浏览量
动态运动基元DMP:机器人轨迹规划中的学习与泛化核心技术 简介本资源是一套面向机器人控制与智能运动规划方向的MATLAB实现代码包聚焦动态运动基元DMP在六自由度轻型冗余机械臂LWR上的轨迹建模与执行适用于机器人学初学者、研究生及算法工程师开展基于示教学习的运动控制实验。压缩包共6个.m文件总大小仅3KB涵盖DMP核心建模DMP.m、轨迹获取GetTraj.m、姿态-位置联合规划flow2oq映射逻辑、LWR机器人模型调用、轨迹回放Recall.m及可视化Plot.m等关键环节另含故障响应模块Fai.m提升工程鲁棒性。已有727人学习下载代码结构清晰、模块职责明确无需额外依赖即可运行演示从鼠标手绘轨迹输入→DMP学习→姿态-位置协同生成→机器人模型仿真→结果可视化全流程是理解DMP理论落地与实际机器人轨迹规划衔接的精简实用范例。1. 从轨迹到“基元”为什么DMP是机器人运动规划的革命性工具如果你在机器人、无人机或者机械臂领域摸爬滚打过一阵子肯定对“轨迹规划”这四个字又爱又恨。爱的是它直接决定了你的机器人动作是否流畅、精准、高效恨的是这事儿太复杂了。尤其是在面对动态变化的环境或者需要模仿人类演示的灵巧动作时传统的规划方法——比如多项式插值、样条曲线甚至是更高级的优化算法——常常显得力不从心。它们要么计算量大到实时性堪忧要么生成的轨迹僵硬不自然要么对环境变化的适应性极差。这时候动态运动基元就该登场了。我第一次接触DMP这个概念是在尝试让一个六轴机械臂学习老师傅的打磨动作时。老师傅的动作行云流水力度和速度的变化非常精妙。我们用高精度的运动捕捉设备记录下了轨迹但如何让机械臂“学会”并“复现”这个轨迹同时还能适应不同大小、不同位置的工件传统的“示教-回放”只能死板地重复换个条件就抓瞎。而DMP恰恰解决了“学习”与“泛化”这个核心痛点。简单来说你可以把DMP理解为一个“运动配方”。它不像录像机一样记录轨迹上每一个点的位置而是去学习驱动这个轨迹背后的“动力学规律”。它把复杂的轨迹分解成一组简单的、可叠加的“基元”每个基元都由一个稳定的动态系统通常是二阶弹簧阻尼系统来刻画。这样一来机器学会的不是“点”而是“生成点的规则”。这个规则是稳健的所以当目标点改变、时间尺度拉伸、或者需要绕过突然出现的障碍时系统能自动地、平滑地调整出新的、合理的轨迹而无需重新进行复杂的全局规划。网络上热门的“复杂静态环境与动态障碍物下的无人机实时轨迹规划框架”、“机械臂轨迹规划算法”等搜索词其核心挑战都在于实时性、适应性和自然性。DMP因其计算高效、易于修改参数目标点、时长以及能产生类人的平滑运动成为了应对这些挑战的利器。而“DMP库移植”、“dmp文件分析工具”这些词则反映了工程师们正积极地将这套理论工具化、工程化。本文我就结合自己从理论摸索到工程落地的经历拆解DMP的核心原理、实现步骤并分享几个在机械臂和无人机场景中真实踩过的坑和解决技巧。2. DMP的核心机理弹簧阻尼系统如何“学会”一条轨迹理解DMP关键在于拆解它的数学模型。它巧妙地将一个非线性项耦合到一个线性动态系统中从而实现了对复杂轨迹的学习与再现。2.1 基础模型二阶系统的“吸引力”DMP最常用的模型是一个改造后的二阶质量-弹簧-阻尼系统。对于一个一维的轨迹比如关节的一个角度或者末端执行器的一个坐标其基本方程如下$$ \tau^2 \ddot{y} \alpha_y (\beta_y (g - y) - \tau \dot{y}) f(x) $$别被符号吓到我们来逐一拆解y,ẏ,ÿ分别代表系统的位置、速度、加速度。这就是我们要规划或生成的轨迹。g目标点。这是系统最终要稳定到达的位置。α_y,β_y增益系数。它们共同决定了这个二阶系统的动态特性如收敛速度、阻尼比。通常设置为α_y 4β_y来构成一个临界阻尼系统保证平滑、无超调地收敛到目标。τ时间常数。它缩放整个系统的时间。τ越大运动越慢τ越小运动越快。这让我们能轻松地拉伸或压缩动作的时间。f(x)这就是核心的非线性强迫项。它负责塑造轨迹的形状使其偏离简单的指数收敛曲线去拟合我们演示的复杂轨迹。这个公式的前半部分α_y (β_y (g - y) - τ ẏ)是一个标准的PD控制器它让系统像一个被拉向目标g的弹簧一样产生一个指向目标的“吸引力”。如果只有这部分系统从起点y0到目标g的轨迹将是一条单调、平滑的指数曲线非常乏味。2.2 非线性强迫项f(x)轨迹形状的“雕刻师”f(x)的作用就是在上述单调收敛的“基底”上添加必要的“力道”让轨迹呈现出我们想要的任何复杂形状——比如画一个圆或者写一笔书法。为了让f(x)的影响随时间衰减保证系统最终能稳定在目标点g我们引入一个相位变量x。它由一个一阶系统生成$$ \tau \dot{x} -\alpha_x x $$其中α_x是一个正常数。这个方程的解是指数衰减的x从1运动开始衰减到0运动结束。f(x)被设计成x的函数因此它的影响力也会随着x衰减到0而消失。这就保证了无论f(x)在中间过程如何“折腾”最终系统都会被基础的弹簧阻尼项拉回目标保证了系统的全局稳定性这是DMP一个非常优雅且重要的特性。那么f(x)具体是什么通常它用一组径向基函数来逼近$$ f(x) \frac{\sum_{i1}^{N} \psi_i(x) w_i}{\sum_{i1}^{N} \psi_i(x)} x (g - y_0) $$ψ_i(x)第i个径向基函数例如高斯函数ψ_i(x) exp(-h_i (x - c_i)^2)。c_i是中心在相位x上均匀分布h_i决定宽度。w_i需要学习的权重。这就是DMP“学习”的本质。(g - y_0)一个缩放因子使得学习到的形状能适应不同的运动幅度。分母的求和用于归一化确保权重w_i的缩放不受基函数分布密度的影响。注意这里的f(x)公式是经典形式之一。在实际中为了更精确地学习轨迹特别是当起点和目标点很接近时有时会采用另一种称为“位移系统”的变体其强迫项形式略有不同但核心思想一致。2.3 学习与再现两步走策略DMP的工作流程清晰分为两步学习阶段从演示轨迹中提取权重输入一条演示轨迹[y_demo, ẏ_demo, ÿ_demo]及其时长T。过程首先根据演示轨迹的时间数值积分出对应的相位变量x的序列。然后我们倒推将演示的加速度ÿ_demo、速度ẏ_demo和位置y_demo代入DMP动力学方程反解出在每个时间点对应每个x上需要多大的强迫项f_target才能产生这条演示轨迹。计算f_target τ^2 ÿ_demo - α_y (β_y (g - y_demo) - τ ẏ_demo)。目标找到一组权重w_i使得由RBF网络生成的f(x)尽可能逼近计算出的f_target序列。这通常通过局部加权回归等算法求解是一个标准的监督学习问题。再现/泛化阶段生成新轨迹输入新的起始点y0_new、新的目标点g_new、新的时间常数τ_new。过程初始化系统状态(y, ẏ) (y0_new, 0)和相位x1。然后开始数值积分如欧拉法、龙格-库塔法求解DMP微分方程。在每一步积分中根据当前x计算f(x)然后计算加速度ÿ再更新速度和位置。输出积分得到的一条全新的轨迹[y, ẏ, ÿ]。这条轨迹会“神似”演示轨迹的形状但完美地适应了新的起点、终点和速度要求。这个机制的强大之处在于一旦权重w_i从演示中学得它就编码了运动的“风格”或“形状”。改变g,y0,τ就像调节旋钮可以轻松地生成一系列相似但不同的运动而无需重新学习。3. 工程实现手把手构建一个可运行的DMP模块理论可能有些抽象我们直接上干货。下面我将用一个Python示例展示如何从零实现一个一维DMP的学习与再现。我们会使用numpy进行核心计算。3.1 环境准备与DMP类定义首先我们定义DMP的核心参数和结构。import numpy as np import matplotlib.pyplot as plt class DMP: def __init__(self, n_bfs100, alpha_y25.0, beta_y6.25, alpha_x1.0): 初始化DMP参数。 :param n_bfs: 径向基函数的数量。越多拟合能力越强但也可能过拟合。 :param alpha_y, beta_y: 弹簧阻尼系统的增益。通常保持 alpha_y 4 * beta_y 为临界阻尼。 :param alpha_x: 相位系统衰减系数。 self.n_bfs n_bfs self.alpha_y alpha_y self.beta_y beta_y self.alpha_x alpha_x # 径向基函数中心和宽度 self.c np.exp(-self.alpha_x * np.linspace(0, 1, self.n_bfs)) # 在相位空间均匀分布中心 self.h np.ones(self.n_bfs) * (self.n_bfs ** 1.5) / self.c # 宽度与中心间距相关 # 待学习的权重 self.w np.zeros(self.n_bfs) # 学习时的目标轨迹参数用于缩放 self.y0 0.0 self.g 1.0 self.tau 1.03.2 学习阶段从一条演示轨迹中提取权重假设我们有一条演示轨迹它可能来自运动捕捉、人工示教或者一条规划好的路径。def learn(self, y_demo, t_demo): 从演示轨迹中学习权重 w。 :param y_demo: 演示的位置序列 (N,) :param t_demo: 对应的时间序列 (N,) # 1. 设置参考参数 self.y0 y_demo[0] self.g y_demo[-1] self.tau t_demo[-1] # 假设时间从0开始总时长即最后的时间 # 2. 数值微分计算演示轨迹的速度和加速度这里使用简单差分实际可用更光滑的方法 dt np.mean(np.diff(t_demo)) dy_demo np.gradient(y_demo, dt) ddy_demo np.gradient(dy_demo, dt) # 3. 计算相位变量 x 的序列 x np.exp(-self.alpha_x / self.tau * t_demo) # 4. 计算目标强迫项 f_target f_target (self.tau ** 2) * ddy_demo - self.alpha_y * (self.beta_y * (self.g - y_demo) - self.tau * dy_demo) # 5. 局部加权回归 (LWR) 学习权重 w # 构造设计矩阵 Phi Phi np.zeros((len(x), self.n_bfs)) for i in range(self.n_bfs): Phi[:, i] np.exp(-self.h[i] * (x - self.c[i]) ** 2) # 归一化 Phi Phi / (np.sum(Phi, axis1, keepdimsTrue) 1e-10) # 考虑到 f 公式中的 x(g-y0) 因子我们在回归时将其剔除 # 即我们学习的是 f_canonical f / (x * (g - y0)) scale x * (self.g - self.y0) # 避免除零 scale[scale 0] 1e-10 f_canonical f_target / scale # 使用岭回归求解权重增加一点正则化防止过拟合 A Phi.T Phi 1e-8 * np.eye(self.n_bfs) b Phi.T f_canonical self.w np.linalg.solve(A, b) # 可选计算并返回拟合误差 f_pred (Phi self.w) * scale error np.mean((f_target - f_pred) ** 2) print(f学习完成均方误差: {error:.6f}) return error3.3 再现阶段给定新条件生成轨迹现在我们可以用学到的权重来生成适应新条件的轨迹。def generate(self, y0_new, g_new, tau_new, dt0.001): 根据学习到的权重从新的初始条件生成轨迹。 :param y0_new: 新的起始位置 :param g_new: 新的目标位置 :param tau_new: 新的时间常数 :param dt: 积分步长 :return: 时间序列 t位置序列 y速度序列 dy加速度序列 ddy # 初始化 T tau_new n_steps int(T / dt) t np.linspace(0, T, n_steps) # 初始化状态 y np.zeros(n_steps) dy np.zeros(n_steps) ddy np.zeros(n_steps) y[0] y0_new dy[0] 0.0 # 相位变量 x np.exp(-self.alpha_x / tau_new * t) # 数值积分欧拉法简单演示。实际应用建议用更高阶方法 for i in range(n_steps - 1): # 计算径向基函数激活和强迫项 psi np.exp(-self.h * (x[i] - self.c) ** 2) psi_sum np.sum(psi) 1e-10 f (np.dot(psi, self.w) / psi_sum) * x[i] * (g_new - y0_new) # 计算加速度 ddy[i] (self.alpha_y * (self.beta_y * (g_new - y[i]) - tau_new * dy[i]) f) / (tau_new ** 2) # 更新速度和位置 dy[i 1] dy[i] ddy[i] * dt y[i 1] y[i] dy[i 1] * dt # 或用 dy[i]*dt此为半隐式欧拉 # 最后一步的加速度 psi np.exp(-self.h * (x[-1] - self.c) ** 2) psi_sum np.sum(psi) 1e-10 f (np.dot(psi, self.w) / psi_sum) * x[-1] * (g_new - y0_new) ddy[-1] (self.alpha_y * (self.beta_y * (g_new - y[-1]) - tau_new * dy[-1]) f) / (tau_new ** 2) return t, y, dy, ddy3.4 实战演示让DMP学习并重现一条复杂轨迹让我们用一个具体的例子来测试上面的代码。# 1. 生成一条演示轨迹例如一个带有波动的最小加加速度轨迹 T_demo 2.0 # 2秒 dt_demo 0.01 t_demo np.arange(0, T_demo, dt_demo) y_demo np.sin(2 * np.pi * t_demo / T_demo) * (1 - np.exp(-5*t_demo)) * 0.5 0.5 # 从0.5开始振荡收敛到1.0 # 2. 创建DMP并学习 dmp DMP(n_bfs50) dmp.learn(y_demo, t_demo) # 3. 再现改变目标点和时间 t1, y1, dy1, ddy1 dmp.generate(y0_new0.0, g_new2.0, tau_new3.0, dt0.01) # 起点0终点2用时3秒 t2, y2, dy2, ddy2 dmp.generate(y0_new1.0, g_new0.5, tau_new1.0, dt0.01) # 起点1终点0.5用时1秒 # 4. 绘图 fig, axes plt.subplots(3, 1, figsize(10, 8)) axes[0].plot(t_demo, y_demo, b-, label演示轨迹, linewidth2) axes[0].plot(t1, y1, r--, label再现: 0-2, 3s) axes[0].plot(t2, y2, g-., label再现: 1-0.5, 1s) axes[0].set_ylabel(位置) axes[0].legend() axes[0].grid(True) axes[1].plot(t1, dy1, r--, label速度 0-2) axes[1].plot(t2, dy2, g-., label速度 1-0.5) axes[1].set_ylabel(速度) axes[1].legend() axes[1].grid(True) axes[2].plot(t1, ddy1, r--, label加速度 0-2) axes[2].plot(t2, ddy2, g-., label加速度 1-0.5) axes[2].set_xlabel(时间 (s)) axes[2].set_ylabel(加速度) axes[2].legend() axes[2].grid(True) plt.suptitle(DMP学习与泛化演示) plt.tight_layout() plt.show()运行这段代码你会看到DMP成功学习了那条正弦衰减的演示轨迹。在再现时尽管起点、终点和时间都发生了巨大变化生成的新轨迹依然保持了原始演示的“振荡收敛”风格并且速度、加速度曲线连续平滑。这就是DMP泛化能力的直观体现。实操心得在实际机器人控制中我们更关心加速度的连续性与力矩/力直接相关。DMP生成的速度和加速度曲线天生是平滑的这得益于其底层是微分方程。相比之下单纯对位置轨迹进行多项式插值再求导得到的速度和加速度可能包含高频抖动对执行器不友好。4. 从一维到多维机械臂与无人机中的DMP应用实战单个关节或单个坐标的一维DMP是基础。在机器人中我们需要协调多个自由度。对于机械臂每个关节可以独立用一个DMP来控制对于无人机的空间位置x, y, z每个轴也可以独立用一个DMP。这就是多DMP并行的策略它们共享同一个相位系统x从而在时间上保持同步。4.1 机械臂关节空间轨迹规划假设我们有一个6轴机械臂我们通过示教器记录了一段末端执行器完成“拾取-放置”动作时6个关节角度的轨迹q_demo(t)维度6xN。class MultiDMP: def __init__(self, n_dof, n_bfs100, **kwargs): self.n_dof n_dof self.dmps [DMP(n_bfsn_bfs, **kwargs) for _ in range(n_dof)] def learn(self, Y_demo, t_demo): Y_demo: 形状为 (n_dof, N) 的演示轨迹 for i in range(self.n_dof): self.dmps[i].learn(Y_demo[i, :], t_demo) def generate(self, Y0_new, G_new, tau_new, dt0.001): Y0_new, G_new: 形状为 (n_dof,) 的起点和目标点 trajectories [] for i in range(self.n_dof): t, y, dy, ddy self.dmps[i].generate(Y0_new[i], G_new[i], tau_new, dt) trajectories.append((y, dy, ddy)) # 将列表转换为数组方便使用 Y np.array([traj[0] for traj in trajectories]) # (n_dof, N) dY np.array([traj[1] for traj in trajectories]) ddY np.array([traj[2] for traj in trajectories]) return t, Y, dY, ddY这样我们就得到了关节空间下同步的轨迹Y(t)。控制器只需要跟踪这些关节角度、角速度、角加速度指令即可。优势保持姿态在关节空间学习再现时能较好地保持末端执行器的姿态如果起点/终点姿态与演示相似。避免奇异性规划在关节空间进行避开了笛卡尔空间下的奇异性问题。动力学兼容生成的关节加速度平滑有利于底层力矩控制。劣势泛化能力局限如果新的起点/终点导致机械臂构型与演示时差异巨大单纯关节空间的泛化可能不理想甚至导致碰撞。此时需要与碰撞检测结合。4.2 无人机笛卡尔空间轨迹规划对于无人机我们更关心其质心在三维空间中的位置p [x, y, z]。我们可以为每个坐标轴建立一个DMP。# 假设我们记录了无人机一段起飞-盘旋-降落的轨迹 p_demo(t) (3, N) multi_dmp_xyz MultiDMP(n_dof3, n_bfs50) # 学习 multi_dmp_xyz.learn(p_demo, t_demo) # 规划一条从新起点到新终点的轨迹时间延长 p0_new np.array([0.0, 0.0, 0.0]) # 新起点 pg_new np.array([5.0, 3.0, 2.0]) # 新目标点 t_new, p_gen, v_gen, a_gen multi_dmp_xyz.generate(p0_new, pg_new, tau_new4.0)生成的p_gen,v_gen,a_gen就是无人机位置、速度、加速度的参考指令可以直接输入给底层的位置控制器或速度控制器。与动态障碍物交互DMP的另一个强大特性是可以在线修改目标点g或添加耦合项。例如当无人机传感器检测到前方有动态障碍物时可以将障碍物的排斥力作为一个额外的项C加入到DMP的加速度方程中τ² ÿ α_y (β_y (g - y) - τ ẏ) f(x) C其中C可以是基于距离的斥力场函数。这样DMP在保持原计划运动“风格”的同时能实时地、局部地避障。这就是“复杂静态环境与动态障碍物下的无人机实时轨迹规划框架”中常用的思路之一DMP提供全局的、类人的运动模板局部避障模块提供实时扰动。两者结合既保证了效率又增加了鲁棒性。踩坑实录在无人机项目中我们曾直接将DMP生成的位置指令给到PID控制器。但在高速飞行时发现跟踪误差较大。原因是DMP生成的是“开环”的期望轨迹没有考虑模型误差和风扰。解决方案是采用“分层控制”DMP作为规划层生成平滑的参考轨迹p_ref, v_ref, a_ref。设计一个模型预测控制器MPC或非线性控制器作为控制层它不仅跟踪位置还跟踪速度和加速度参考并将无人机动力学模型考虑在内。这样DMP负责“造路”MPC负责“开车”两者结合效果显著提升。DMP的平滑输出为MPC提供了一个非常好的、动力学可行的初始猜测降低了MPC在线优化的计算负担。5. 进阶话题与避坑指南让DMP在实际系统中真正跑起来理论完美代码跑通离上真机还有距离。下面分享几个关键进阶点和避坑经验。5.1 参数选择与调优不是越多越好径向基函数数量n_bfs这是最需要调优的参数之一。太少拟合能力不足学不到细节欠拟合太多会过度拟合演示轨迹中的噪声导致泛化时轨迹产生不合理的抖动过拟合。经验法则从20-30开始尝试根据轨迹的复杂程度增减。对于非常平滑的轨迹10个可能就够了对于包含高频细节的复杂轨迹如写字可能需要50-100个。可以通过观察f_target和学到的f的拟合情况来判断。基函数宽度h_i宽度决定了每个基函数的影响范围。通常让宽度与基函数中心的间距成反比以保证在相位空间x上覆盖均匀。上面的代码示例中h (n_bfs**1.5)/c是一种启发式设置效果不错。也可以手动设置一个统一的值。α_y和β_y保持α_y 4β_y以确保临界阻尼。α_y的值影响系统的“刚度”。值越大系统对目标点的“吸引力”越强对外部扰动如耦合项C的抵抗也越强但可能显得“僵硬”。典型值范围在20-50之间。α_x决定相位x衰减的速度间接影响强迫项f(x)的作用时长。通常设为1.0。如果你想改变运动的时间结构比如让动作前半段加速后半段减速可以设计更复杂的相位系统而不是简单的指数衰减。5.2 演示轨迹的质量与预处理垃圾进垃圾出DMP的学习效果极度依赖于演示轨迹的质量。平滑性如果演示轨迹是从传感器如视觉、IMU直接获取的很可能包含噪声。直接用它来学习DMP会连噪声一起学进去。必须预处理使用低通滤波器如巴特沃斯滤波器或平滑样条对位置数据进行滤波然后通过解析求导或滤波后差分得到平滑的速度和加速度。记住f_target的计算依赖于加速度加速度对噪声极其敏感。时间对齐确保演示轨迹是从动作开始t0到动作结束tT的完整片段。有时需要手动截取或通过速度阈值检测起止点。起点与终点演示轨迹的起点和终点速度、加速度最好为零或接近零这样DMP再现时也能从静止开始平滑地停止。如果不是可以在预处理时进行修正。5.3 高维姿态空间的DMP四元数与旋转矩阵对于机械臂末端执行器的姿态规划情况更复杂。因为姿态空间SO(3)不是欧几里得空间不能简单地对三个欧拉角分别用DMP否则会导致奇异性和不自然的插值。主流解决方案是使用单位四元数。四元数DMP的推导更复杂但其核心思想类似定义一个在球面流形上的动态系统其“吸引子”是目标四元数强迫项在四元数的切空间即角速度空间中作用。已有成熟的库如pyquaternion结合DMP扩展实现了这一点。如果你需要规划姿态强烈建议直接使用这些经过验证的库而不是自己从头推导。5.4 实时性与嵌入式部署C与优化Python适合原型验证但真正部署到机器人实时控制系统如ROS下的控制器、嵌入式飞控时通常需要C实现。库的选择可以考虑Eigen库进行矩阵运算它高效且易于使用。将DMP的核心类用C重写。积分器实时控制中对计算速度要求高。欧拉法虽然简单但精度低可能需更高级的单步法如RK4。需要平衡精度与计算开销。在线参数修改确保你的DMP类能在线、线程安全地更新目标点g、时间常数τ或耦合项C以适应动态环境。“DMP库移植”的挑战将研究代码移植到稳定、可复用的库需要良好的接口设计、内存管理和测试。一个常见的坑是数值稳定性比如在计算RBF激活或归一化时除以零。务必添加小的 epsilon如1e-10进行保护。5.5 当DMP效果不佳时问题排查清单再现轨迹振荡或发散检查α_y和β_y是否满足临界阻尼条件α_y是否太小强迫项权重w_i是否过大可能因演示轨迹噪声导致尝试增加α_y或对权重施加L2正则化。检查数值积分步长dt是否太大尝试减小步长或使用更稳定的积分方法。泛化轨迹形状怪异检查n_bfs是否过少或过多可视化一下学到的强迫项f(x)和目标强迫项f_target看拟合效果。检查演示轨迹的起点/终点速度非零但DMP默认假设为零。这会导致起点/终点附近轨迹扭曲。可以在学习前对演示轨迹进行时间规整使其起止速度为零。无法精确到达目标点检查这是DMP的一个特性。由于强迫项f(x)在末期衰减为零最终收敛由线性项保证理论上能精确到达。如果看到微小误差可能是数值积分累积误差或α_y/β_y设置导致收敛过慢。可以适当增大α_y或在动作结束后切换到一个小范围的PID控制器进行最终精调。DMP不是一个“一劳永逸”的魔术黑盒它是一套强大而灵活的工具。理解其原理仔细处理数据合理选择参数并根据具体任务如是否需要避障、是否在姿态空间进行扩展你才能让它在你手中的机器人上跳出优雅的舞蹈。从简单的点到点运动到复杂的行为序列组合DMP为我们提供了一种连接“学习”与“控制”的优美桥梁。本文还有配套的精品资源点击获取