线驱连续型机器人建模:从常曲率运动学到微重力辨识
2026/9/18 13:52:40 网站建设 项目流程

简介:面向航天在轨服务场景的线驱连续型机器人建模研究资料,是一份可复现的博士学位论文节选,适合机器人研究人员、自动化工程专家及航天技术学者参考。内容聚焦多节段线驱连续型机器人的数学建模,在分段常曲率假设下给出位置级与速度级运动学映射,并基于刚体等效思想采用拉格朗日方法建立动力学模型,同时结合具体两节段机器人参数完成工作空间仿真与受力分析。PDF全文包含详细的坐标系变换、齐次变换矩阵推导及模型构造过程,并提供关键物理参数,可直接用于后续运动规划与控制算法验证,便于读者复现实验。资料以单个PDF文件打包,大小约1.65MB,便于下载与离线阅读。目前已有48人学习使用,对于从事柔性机器人、空间操作任务研究的读者具有直接参考价值。

1. 线驱连续型机器人在航天应用里为什么难建模,难在哪

线驱连续型机器人在地面实验室里绕得再顺,进了航天器工况还是得重新建模,这跟刚性机械臂那套D-H参数加牛顿-欧拉递推的流程完全是两条技术路线。这类机器人依靠电机牵引穿过臂体的缆绳改变弯曲形态,结构轻、可收纳、能伸入狭小舱段,常被列为航天在轨服务和舱内操作的一种候选执行机构。控制它之前必须回答两个问题:缆绳长度怎么映射到末端位置,驱动力又如何变成末端加速度。前者是运动学建模,后者是动力学建模;落到工程上还要考虑微重力下重力项消失、摩擦和线缆迟滞反而变主导的差别。下面按建模顺序,给出常曲率假设下的运动学推导、拉格朗日动力学方程和一组按可复现标准整理的参考代码,适合正在做连续体机器人仿真、或者准备评估这条路线能不能上星的工程师。整个流程先以仿真数据验证再迁移到样机,哪一步对不上,把数值发散时的状态量和积分器设置发给我,可以从现象反推模型问题。

2. 线驱连续型机器人运动学建模:空间映射与常曲率正逆解

2.1 三个空间的映射关系:驱动长度、构型参数与末端位姿

处理线驱连续体机器人时,我习惯先把坐标系拆成三个空间。驱动空间放三根缆绳的长度,构型空间放描述中心线弯曲的曲线参数,任务空间放末端位置。把一个机器人上的三种量分开,后面换驱动器或者换末端工具时,不用重推整套模型。

空间典型变量物理含义维度
驱动空间l1, l2, l3三根驱动缆绳的长度3
构型空间θ, φ弯曲角与弯曲平面角2
任务空间x, y, z末端位置(或姿态)3~6

驱动空间到构型空间的映射是连续体机器人区别于刚性机械臂的第一处关键差异。假设三根缆绳在臂截面上按120°均布,缆绳所在圆周半径为r_d,第i根的圆周角β_i=0、2π/3、4π/3。中心线弯曲成圆弧后,第i根缆绳与中心线的径向偏移方向不同,其弧长也会变化。在常曲率假设下,这个变化可以用简洁的几何关系写出:

l_i = L - r_d θ cos(φ - β_i)

其中L是中心线长度。注意这里的负号表示缆绳在弯曲内侧时会缩短,外侧会伸长;如果习惯把“伸长量”当作驱动量,把负号去掉即可。这个公式不是泰勒近似,而是圆弧等距线长度的精确表达,前提是缆绳始终贴合中心线、截面不发生椭圆化。这个“贴合”假设就是后面所有模型误差的主要来源之一。

这种把三个驱动量压缩成两个构型参数的思路,和麦克纳姆轮底盘做运动学解算时把四轮转速映射成底盘速度是同类问题,只是连续体机器人的中间量是曲线参数而不是速度。可以把上面的公式视为“连续体版的逆运动学”:已知目标构型求缆绳长度。反过来,已知三根缆绳长度求θ、φ,则是从三组方程里解两个未知数,通常用最小二乘或取其中两路做解析求解;工程上更常见的是直接用第2.3节的末端位置逆解后,再用该公式反算缆绳长度,形成一条完整的解算链。

2.2 常曲率正运动学推导与Python实现

正运动学回答的是“给定θ和φ,末端在哪”。把中心线看成一段半径为r = L/θ的圆弧,弧上距基座弧长为s的点的坐标为:

x(s) = (L/θ) (1 - cos(sθ/L)) cosφ
y(s) = (L/θ) (1 - cos(sθ/L)) sinφ
z(s) = (L/θ) sin(sθ/L)

当s = L时就是末端位置。若θ趋于0,公式退化为直杆,坐标变为[0, 0, s],需要在代码里做分支处理。对应的Python实现如下:

import numpy as np def fk_constant_curvature(theta, phi, s, L=1.0): # 常曲率假设下的正运动学 # theta: 弯曲角(rad), phi: 弯曲平面角(rad) # s: 查询点距基座的弧长, L: 连续体总长 if abs(theta) < 1e-12: # 直构型时避免除零,直接返回直杆坐标 return np.array([0.0, 0.0, s]) radius = L / theta arc_angle = theta * s / L x_curve = radius * (1.0 - np.cos(arc_angle)) z_curve = radius * np.sin(arc_angle) return np.array([ np.cos(phi) * x_curve, np.sin(phi) * x_curve, z_curve ])

代码里的核心操作是先算弯曲平面内的二维圆弧坐标,再绕基座z轴旋转φ。这样写的好处是x和y共享同一个x_curve,不容易出现phi旋转方向不一致的笔误。s参数保留下来,是因为后续动力学里要取段中点位置;只算末端时传s等于L即可。弧度制和长度单位需要在调用前统一,比如统一用米和弧度,不要把毫米和米混着传。

2.3 逆运动学解析解与雅可比矩阵

逆运动学在单段常曲率模型下有解析解。已知末端位置p,先算ρ = sqrt(x² + y²),则φ = atan2(y, x)。θ满足tan(θ/2) = ρ/z,因此:

def ik_closed_form(p, L=1.0): # 常曲率单段模型的解析逆解 # p: 末端位置[x, y, z] x, y, z = p if z < 0: # 单段连续体末端z坐标不可能为负 raise ValueError("目标点在可达空间外") rho = np.hypot(x, y) phi = np.arctan2(y, x) theta = 2.0 * np.arctan2(rho, z) # 由 tan(theta/2)=rho/z 推出 if theta < 0.0 or theta > np.pi: raise ValueError("目标点不在单段可达空间内") return theta, phi

解析逆解虽然快,但对噪声敏感:当z接近0且rho很小时,atan2的两个输入都接近0,θ的数值不稳定,这时应该先判断末端是否落在执行器附近的小邻域内,再决定是否用数值优化兜底。和松灵piper这类刚性关节机械臂运动学不同,连续体机器人的逆解没有明确的关节角可供直接限定,θ和φ的组合还可能多解(比如绕不同平面的对称解),所以引入任务空间约束时,数值法反而比解析法更容易写。

雅可比矩阵用于后续动力学里的速度与质量矩阵计算。末端位置对θ、φ求偏导得到的解析形式如下:

def jacobian_analytic(theta, phi, L=1.0): # 解析形式的末端雅可比,3x2矩阵 st, ct = np.sin(theta), np.cos(theta) sp, cp = np.sin(phi), np.cos(phi) J = np.zeros((3, 2)) J[0, 0] = L / theta**2 * (theta * st - (1.0 - ct)) * cp J[1, 0] = L / theta**2 * (theta * st - (1.0 - ct)) * sp J[2, 0] = L / theta**2 * (theta * ct - st) J[0, 1] = -L / theta * (1.0 - ct) * sp J[1, 1] = L / theta * (1.0 - ct) * cp return J

雅可比在θ=0处存在奇异,这是连续体机器人的固有特性,不是程序写错。控制里需要走阻尼最小二乘或奇异回避;动力学里组装质量矩阵时,如果取多个弧长点并计算该点雅可比,直构型附近的条件数会变得很差,这也是后面仿真发散最常见的原因之一。实际使用中,我给θ设一个下限(比如1e-3弧度),避免求解器频繁穿越奇异邻域。

3. 线驱连续型机器人动力学建模:拉格朗日方程与缆绳广义力

3.1 动力学建模方法选型:为什么选集中质量加常曲率

运动学只解决“指令怎么变成位置”,要回答“驱动力多大才动得起来”就必须进入动力学。连续体动力学建模有三个常见派别:Cosserat杆理论把机器人当成连续弹性杆,完整程度高,但解偏微分方程的计算量对一个实时仿真回路来说通常太大;有限元类方法精度高,却难以直接嵌入控制器;面向控制,我一般偏向用集中质量加常曲率假设的降阶模型——把臂体分成N段,每段仍用常曲率运动学,质量集中在段中点,广义坐标就是每段的θ和φ。N取3到5时,精度和计算量比较平衡;做控制器的快速验证时取N=1也够用。

建模方法离散方式计算复杂度面向控制实时性主要误差来源
Cosserat杆连续场中低边界条件与材料参数
集中质量+常曲率分段常量曲率分段数、截面变形假设
有限元/绝对节点坐标单元离散很高单元类型、接触条件

选择哪一档取决于用途:论文级的变形分析用Cosserat,控制设计用集中质量,机构强度校核用有限元。下面按集中质量法展开。

3.2 动能、势能与缆绳张力引起的广义力

单段模型广义坐标q=[θ, φ]。将臂体分成N个小段,第i个质量点位置由正运动学在s_i处求得,其雅可比为J_i = ∂p_i/∂q。质量点质量m_i = ρA(L/N),其中ρ为等效密度,A为截面积。系统动能可以近似为:

T = 0.5 Σ m_i qdot^T J_i^T J_i qdot

由此得到惯性矩阵M(q) = Σ m_i J_i^T J_i。如果每个小段还需考虑姿态旋转动能,再叠加上对应转动惯量与旋转雅可比内积形成的2x2修正项;对细长臂体,这项一般比平移项小一个量级,可以先不加。

势能分三部分:重力势能V_g = Σ m_i g z_i(q),弯曲弹性势能V_k = 0.5 K_θ (θ-θ0)²,缆绳张力产生的是非保守广义力,不进势能。航天应用里,微重力下g可以置零,但地面样机调试时不能省,所以把g作为开关量保留在方程里。

缆绳张力到广义力的转换是连续体动力学最容易出错的一步。设三条缆绳长度向量l(q),其雅可比J_l = ∂l/∂q是2x3矩阵(两行广义坐标、三列缆绳)。拉力f缩短缆绳,对广义坐标的广义力应取负号:τ_cable = -J_l^T f。这个符号方向在不同论文里有正有负,根源是l_i的定义取“缩短量”还是“伸长量”。工程上我不去背符号,直接在仿真里单独给一根缆绳加张力,看末端是否朝收缩方向运动,反向就翻符号。

3.3 动力学方程组装与Python代码

组装后的动力学方程写成:

M(q) ddot_q + C(q, dq) dq + G(q) + K q + D dq = τ_cable + τ_ext

低速操作时科氏项与离心力项C dq量级很小,可以先用开关控制是否计入,不必一上来就用Christoffel符号把C凑齐。G是重力项,K是弯曲刚度项,D是粘性阻尼。对应代码:

def numerical_jacobian(s, q, L): # 通过正运动学做中心差分,得到弧长s处的3x2雅可比 eps = 1e-6 J = np.zeros((3, 2)) for j in range(2): qp = q.copy() qm = q.copy() qp[j] += eps qm[j] -= eps J[:, j] = (fk_constant_curvature(qp[0], qp[1], s, L) - fk_constant_curvature(qm[0], qm[1], s, L)) / (2 * eps) return J def mass_matrix(q, param): # 集中质量法组装惯性矩阵,单段模型 M = np.zeros((2, 2)) n = param['num_segments'] for i in range(n): s_mid = (i + 0.5) * param['length'] / n J = numerical_jacobian(s_mid, q, param['length']) m_i = param['rho'] * param['area'] * param['length'] / n M += m_i * J.T @ J M += np.diag([param['inertia_theta'], param['inertia_phi']]) return M def cable_generalized_force(q, tension, param): # tension: [f1, f2, f3],缆绳张力 def cable_len(theta, phi): beta = np.array([0.0, 2*np.pi/3, 4*np.pi/3]) return param['length'] - param['cable_radius'] * theta * np.cos(phi - beta) J_l = np.zeros((3, 2)) eps = 1e-6 for j in range(2): qp = q.copy() qm = q.copy() qp[j] += eps qm[j] -= eps lp = cable_len(qp[0], qp[1]) lm = cable_len(qm[0], qm[1]) J_l[:, j] = (lp - lm) / (2 * eps) return -J_l.T @ tension

数值雅可比复用了第二章的正运动学函数,这样s可以取任意弧长位置,质量矩阵就能自然覆盖分段情况。算M时每个质量点都要重新算一次,N取5时循环5次,规模很小,没必要优化。注意M的第2行第2列若没有转动惯量修正,可能趋近于0,仿真里会出现高频抖动;给inertia_phi一个经验值(比如0.01)能显著改善数值稳定性,具体数值根据臂径和长度标定。

广义力用数值差分求J_l,比手推解析式省事,也方便后面把缆绳弹性纳入时直接替换cable_len函数。如果缆绳与臂体之间有穿线孔摩擦,可以在cable_len里叠加一个与θ相关的小偏移项,效果上等效于给θ增加一个迟滞阻力,这在第四章的辨识里会体现出来。

4. 面向航天微重力环境的模型修正与参数辨识

4.1 微重力让哪些项消失、哪些项放大

航天器在轨的微重力水平约为10⁻⁶ g,重力项G(q)与地面相比小到可以忽略,但不是说动力学方程可以直接删掉这一项——地面标定时重力是主要外力,不保留就无法与实验数据对齐。我一般在参数结构体里放一个gravity_switch,仿真时置0模拟在轨,地面验证置1。真正的麻烦在于:微重力下缆绳不再需要承担平衡重力的预紧分量,整个系统的初始张力分布和地面完全不同,摩擦、松弛、迟滞对运动的影响比例明显上升,真空中又没有空气阻尼,结构阻尼和缆绳内摩擦成了主要的能量耗散路径。

4.2 需要辨识的参数与激励方式

参数物理含义建议激励可辨识性
弯曲刚度Kθ单位弯曲角对应的弹性恢复力矩准静态张力阶跃
缆绳弹性kc缆绳单位长度拉伸刚度快速张紧松驰
粘性阻尼c广义速度相关阻力正弦扫频
库仑摩擦μ与方向相关的恒定阻力三角波低速驱动

可辨识性低的参数不要放在同一个最小二乘问题里同时解,否则会出现多解,一个实验拟合出好几组参数都对得上。常见的做法是分步辨识:先用准静态实验拟合刚度与几何参数,再做动态扫频拟合阻尼,最后用三角波残差估计库仑摩擦。

4.3 分步辨识代码与残差判断

静态辨识代码:

from scipy.optimize import least_squares def fit_bending_stiffness(theta_data, tau_data): # 模型: tau = k_theta * theta + tau_offset def residual(params): k_theta, offset = params return tau_data - (k_theta * theta_data + offset) result = least_squares(residual, x0=[0.01, 0.0]) return result.x # [k_theta, offset]

使用前要把缆绳张力换算成广义力矩:τ_θ = -J_l[0,:]·f,也就是第三章广义力代码求出的tau的第一个分量。theta_data要取稳定后的平均值,不要用过渡过程的数据,否则粘性阻尼会混进刚度估计。拟合后把残差画出来,如果残差随θ呈现明显的S形或二次趋势,说明线性刚度假设不够,常见处理是加入三次项k3·θ³,并继续用同一个最小二乘框架。

动态辨识时,给机器人叠加多个频率的正弦驱动,记录每个频率下的幅值比与相位差。粘性阻尼主要影响幅值比的峰值位置,而刚度误差主要影响谐振频率。两者在频响曲线上位置不同,可以分开观察。库仑摩擦的辨识更简单:用等速三角波驱动,记录驱动端力与缆绳长度形成的滞回环,环宽的一半就是库仑摩擦的一个近似估计。

验证阶段,把辨识出的参数代入动力学方程,用同一组激励做正向仿真,比较末端轨迹与实测。评判标准不能只看RMSE,还要看残差是否与输入相关:残差与θ强相关说明刚度或几何参数仍有偏;残差与dθ强相关说明阻尼没对准;残差方向在反向运动时突变则是摩擦项没建模。这个相关分析的具体操作方法放在最后一章,它是能把辨识做得闭环的关键一步。

5. 模型复现与排错:从数值仿真到硬件在环验证

5.1 把运动学与动力学串成完整仿真

仿真主流程:

from scipy.integrate import solve_ivp def system_ode(t, state, param): q = state[:2] dq = state[2:] # 控制器返回三段缆绳拉力,这里用一个PD型示例 q_des = param['q_des'] tension = param['kp'] * (q_des - q) - param['kd'] * dq # 张力到广义力 tau = cable_generalized_force(q, tension, param) # 质量矩阵与其余项 M = mass_matrix(q, param) G = param['gravity_switch'] * gravity_vector(q, param) K = param['bending_stiffness'] * np.array([q[0], 0.0]) D = param['viscous_damping'] * dq ddp = np.linalg.solve(M, tau - G - K - D) return np.concatenate([dq, ddp]) sol = solve_ivp(system_ode, [0, 5.0], [0.2, 0.0, 0.0, 0.0], method='RK45', rtol=1e-6, atol=1e-8, max_step=0.01)

state前两个分量是θ和φ,后两个是角速度。这里控制器用PD是为了先让闭环稳定,实际工程里换成力位混合控制即可。把科氏项先去掉,rtol设小一些,避免数值噪声被当作真实动力学。sol收敛后,把sol.y[:2]逐点代入第二章的正运动学函数,就能得到末端轨迹。这一步在可复现流程里作为基准输出。

5.2 数值发散、矩阵奇异与常见解算问题

症状常见原因处理办法
θ在0附近来回跳雅可比奇异邻域给θ加1e-3下限,用阻尼最小二乘
轨迹发散到π以上积分步长太大或M奇异减小max_step,改用Radau,加位形边界势能
质量矩阵条件数剧增分段质量点靠近奇异构型提高N、加转动惯量修正项
缆绳长度出现负值驱动映射里r_d*θ超出范围校验r_d和θ取值范围,限制构型空间

数值发散时不要先调控制器参数,先把积分器换成Radau或LSODA做一次对比;如果换刚性积分器后轨迹正常,说明原RK45步长没有满足稳定性要求。如果换积分器仍然发散,再查M矩阵是否奇异、G和K项的符号是否一致。

提示:数值发散时先固定激励信号,只切换积分器类型做对比,不要同时修改控制器参数;两个变量一起动,很难定位是哪一处破坏了稳定性。

5.3 模型边界:哪些现象别指望单段模型复现

把同一套模型迁到硬件在环时,先明确单段常曲率模型不能覆盖的现象:大弯曲时截面椭圆化、缆绳的松弛与拍击、穿线孔的局部摩擦。航天材料温度范围宽,弹性模量随温度变化,导致Kθ和缆绳弹性离线标定值在轨可能失效。因此模型接口要预留参数更新入口,仿真时把温度、重力开关和摩擦系数作为外部输入,而不是写死在结构体里。硬件在环的另一个习惯做法是先在仿真里把科氏项开关切换对比,确认系统工作速度低到可以忽略后再把它从实时代码里移除,而不是一开始就为了省算力删掉。

6. 用残差相关分析定位连续体机器人模型缺项:一个可复用的校准技巧

6.1 残差-特征相关度:判断该补哪一项

当仿真和实测对不上时,不要急着同时调五六个参数。先用相关分析确定最该补的项。具体分三步:先对同一激励记录一组实测末端轨迹与仿真末端轨迹,得到残差序列e(t) = p_measured - p_sim;再取同一时刻的θ、dθ、sign(dθ)三个特征量;计算e与各特征量的Pearson相关系数,按绝对值大小决定补哪一项。

def residual_correlation(e, theta, dtheta): # e、theta、dtheta均为等间隔采样序列 features = { 'theta': theta, 'dtheta': dtheta, 'sign(dtheta)': np.sign(dtheta), } for name, feat in features.items(): corr = np.corrcoef(e, feat)[0, 1] print(f"{name}: {corr:+.3f}") # 绝对值>0.8表示强相关

相关系数的含义映射如下:

强相关特征优先补的模型项补充验证
θ非线性刚度或几何半径偏差变幅静态加载
粘性阻尼变频扫频
sign(dθ)库仑摩擦三角波低速驱动
都不相关惯性或缆绳弹性阶跃响应

实际使用中,这个分析对采样同步很敏感。e和θ如果不对齐时间戳,相关系数会被时间延迟稀释;做相关分析前先用互相关函数估计时间延迟并补偿,比把控制器响应调快更值得。另一个细节是每次只补一项,补完重新辨识并检查验证集残差。如果同时把刚度和阻尼都调了,模型同样能拟合训练数据,但验证集误差反而可能变大,原因就是参数间存在耦合冗余。

把这段分析脚本固化到每次试验后的后处理流程里,残差绝对值会被快速压缩到模型假设允许的范围内;到那时再纠结要不要换Cosserat模型也不迟。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询