灵巧手与精细操作

多指运动学、欠驱动机构、触觉传感器、力闭合分析——连杆机构+材料力学的经验在这里发挥到极致。

3-4周
7 个章节
代码示例
验收实验

本阶段目录

  1. 多指灵巧手运动学
  2. 触觉与软体抓取

1. 多指灵巧手运动学与力闭合

机械背景

多指手是并联+串联机构的混合系统。你设计过连杆机构、分析过自由度——这些直觉直接适用。Allegro Hand有16个独立关节,手指间协同约束才是难点。

欠驱动与腱绳驱动

大多数灵巧手使用腱绳驱动——一根电机同时驱动多个关节,产生天然的"包络效应"。本质上是一种机械自适应,用弹簧和连杆就能实现,不需要复杂控制算法

力闭合分析

$\mathbf{G} \mathbf{f} = -\mathbf{w}_{ext}$

$\mathbf{G}$是抓取矩阵,力闭合条件:存在$\mathbf{f} > 0$使$\mathbf{G}\mathbf{f} = 0$——手指可以用纯正压力抵抗任意外力。

验收标准

  • 分析Allegro/Shadow Hand运动学链(至少3指),计算工作空间
  • 实现力闭合检测器:给定接触点判断抓取是否稳定
  • 设计多指抓取策略并在PyBullet中仿真验证

2. 触觉传感器与软体抓取

触觉传感器

类型原理机械类比
GelSight光学+弹性体粗糙度仪
BioTac液体填充+电极力传感器阵列
压阻阵列压阻材料压力纸

软体抓取

柔性材料(硅胶、气动)制造的被动适应手指——用材料层面的柔顺性替代精确力控。你做过橡胶密封圈的有…元分析,把同样方法应用到软体手指就能预测抓取力分布。

3. 抓取质量评估——从力闭合到任务导向

力闭合的数学定义

力闭合:存在一组纯正压力(手指只能推不能拉),使得它们可以抵抗任意方向的外力旋量。判断条件:抓取矩阵G的列向量正线性张成整个力旋量空间

$\mathbf{G} \mathbf{f} = -\mathbf{w}_{ext}, \quad f_i \geq 0$

力闭合检测算法

def is_force_closure(contact_points, contact_normals, mu=0.5):
    """检测给定抓取是否为力闭合"""
    n_contacts = len(contact_points)
    G = np.zeros((6, n_contacts * 3))  # 6D wrench space
    
    for i, (p, n) in enumerate(zip(contact_points, contact_normals)):
        # 法向力分量
        G[0:3, i*3] = n
        G[3:6, i*3] = np.cross(p, n)
        # 切向力分量(摩擦锥近似,2个方向)
        t1 = np.array([-n[1], n[0], 0])
        t1 /= np.linalg.norm(t1)
        t2 = np.cross(n, t1)
        for j, t in enumerate([t1, t2]):
            G[0:3, i*3+j+1] = mu * t
            G[3:6, i*3+j+1] = mu * np.cross(p, t)
    
    # 力闭合 ⇔ 存在严格正解f使Gf=0
    # 等价于: 原点在G列向量的凸包内部
    from scipy.spatial import ConvexHull
    try:
        hull = ConvexHull(G.T)
        return hull.find_simplex(np.zeros(6)) >= 0
    except:
        return False
🔧 工程连接:力闭合分析本质上就是静力学平衡——你做的每一个力学分析都在回答"这个夹紧方案能不能抵抗外力"。把夹具设计经验转移到多指抓取,就是你的跨领域优势。

验收标准

  • 实现力闭合检测器,在标准物体(球/圆柱/方块)上测试
  • 对比3指/4指/5指抓取的力闭合成功率

4. 抓取分类学——从人类手到机器手

Cutkosky抓取分类法(33种抓取)

人类手有33种不同的抓取模式。Cutkosky将它们按力需求精度需求分为两大类:

大类子类描述接触点数机械类比
Power Grasp
(力抓取)
圆柱抓取手指包裹圆柱体全掌+多指手握扳手
球状抓取手指包裹球体全掌+指尖手握门把手
钩状抓取手指弯曲成钩(无拇指)2-4指提手提箱
Precision Grasp
(精度抓取)
指尖捏取拇指 vs 食指指尖2拿螺丝
三指夹持拇指+食指+中指3握笔
侧捏拇指面 vs 食指侧2拿钥匙
五指尖全部指尖汇聚5拧瓶盖
Intermediate
(中间抓取)
自适应包裹手掌+部分手指3-4欠驱动自适应

机械工程师的抓取直觉

你设计夹具时考虑的是定位点(定位面)+夹紧力(夹紧面)的6点定位原理。多指抓取完全一致——每个手指接触点提供一个法向力(推)两个切向力(摩擦),多个接触点合力抵抗外力旋量。

🔧 工程连接:夹具设计的核心——"定位决定精度,夹紧决定刚度"——直接适用于多指抓取。定位点分布→接触点分布,夹紧力方向→手指力方向,过约束→冗余手指。你不需要重新学习力闭合理论——你已经在车间里实践了好几年。

5. Allegro Hand IK求解器——16自由度的逆运动学

Allegro Hand的运动学结构

Allegro Hand:4根手指×4个关节=16自由度。每根手指是4R串联链。与6轴机械臂不同,手指的工作空间小(指尖工作空间半径约120mm),且IK解不唯一(冗余度极高)。

手指IK求解——解析法

4个关节的串联手指,指定指尖位置后剩余2个冗余自由度。常用约束:

  1. MCP侧摆关节(第1个)尽量小——避免手指侧偏
  2. 关节角度尽可能居中——距离关节限位远,灵活性好
import numpy as np
from scipy.optimize import minimize

class FingerIK:
    """Allegro单指4-DOF IK求解器"""
    
    def __init__(self, link_lengths=[0.035, 0.045, 0.025, 0.025]):
        self.link_lengths = np.array(link_lengths)
        self.joint_limits = [
            (-0.3, 0.3),    # MCP侧摆: ±17°
            (-1.57, 0.0),   # MCP弯曲: 0°~90°
            (-1.57, 0.0),   # PIP弯曲: 0°~90°
            (-1.57, 0.0),   # DIP弯曲: 0°~90°
        ]
    
    def forward_kinematics(self, joint_angles):
        """前向运动学:关节角度 → 指尖位置(相对MCP基座)"""
        pos = np.array([0.0, 0.0, 0.0])
        cumulative_angle = 0
        
        for i, theta in enumerate(joint_angles):
            cumulative_angle += theta
            
            if i == 0:  # MCP侧摆 (YZ平面)
                pos[1] += self.link_lengths[i] * np.sin(theta)
                pos[2] -= self.link_lengths[i] * np.cos(theta)
            else:      # 弯曲关节 (XZ平面)
                pos[0] += self.link_lengths[i] * np.sin(cumulative_angle - theta)
                pos[2] -= self.link_lengths[i] * np.cos(cumulative_angle - theta)
        
        return pos
    
    def solve_ik(self, target_pos):
        """逆运动学:最小化关节偏离中性位置 → 找到到达目标位置的关节角"""
        
        def objective(angles):
            pos = self.forward_kinematics(angles)
            pos_error = np.sum((pos - target_pos) ** 2)
            # 正则化:远离关节限位
            regularization = 0.01 * np.sum(angles ** 2)
            return pos_error + regularization
        
        # 初始猜测:手指微微弯曲
        init_guess = np.array([0.0, -0.5, -0.5, -0.3])
        
        bounds = self.joint_limits
        
        result = minimize(objective, init_guess, method='L-BFGS-B',
                         bounds=bounds, options={'maxiter': 100})
        
        if result.success and np.sqrt(result.fun) < 0.005:  # < 5mm acceptable
            return result.x
        return None

四指协同IK

指定目标物体形状和抓取点后,每个手指独立求解IK,但需要检查指间碰撞手指-物体碰撞

def solve_hand_ik(hand, target_grasp_points):
    """四指协同IK + 碰撞检测"""
    solutions = {}
    for finger_name, target in target_grasp_points.items():
        angles = hand.fingers[finger_name].solve_ik(target)
        if angles is None:
            return None  # 有手指无法到达
        solutions[finger_name] = angles
    
    # 碰撞检测:检查手指是否互相干涉
    if hand.check_self_collision(solutions):
        return None
    
    return solutions

验收标准

  • 实现单根手指的IK求解器(SCIPY优化),精度 < 5mm
  • 实现四指协同IK,给定12个目标接触点→输出48个关节角
  • 可视化手指的运动范围(工作空间点云),对比不同连杆长度的影响

6. 触觉伺服——用触觉反馈闭环控制抓取

什么是触觉伺服

视觉伺服用相机反馈控制运动,触觉伺服用触觉传感器反馈控制抓取力。就像你闭着眼睛也能稳稳拿起一个鸡蛋——因为你手指感受到了压力和滑动。

触觉伺服的闭环控制回路

传感器(GelSight/BioTac读取接触力分布) → 特征提取(接触面积/压力中心/剪切力方向) → 控制器(调整手指力/位置) → 执行(手指电机) → 传感器(重新读取)

class TactileServoController:
    """触觉伺服——保持稳定接触力,检测并防止滑动"""
    
    def __init__(self, target_normal_force=2.0, slip_threshold=0.05):
        self.target_force = target_normal_force
        self.slip_threshold = slip_threshold
        self.Kp_force = 0.5   # 力控制增益
        self.Kp_slip = 1.0    # 防滑控制增益
    
    def control(self, tactile_reading):
        """给定触觉传感器读数,输出手指力调整量"""
        
        # 1. 提取当前法向接触力
        current_force = np.sum(tactile_reading.normal_pressure)
        
        # 2. 检测是否有滑动迹象
        #    滑动表现为剪切力急剧增加或接触面积突然变化
        shear_magnitude = np.linalg.norm(tactile_reading.shear_force)
        is_slipping = shear_magnitude > self.slip_threshold
        
        # 3. 力控制 + 防滑叠加
        force_error = self.target_force - current_force
        force_adjustment = self.Kp_force * force_error
        
        if is_slipping:
            # 加大法向力来抑制滑动(摩擦基本原理:法向力↑→最大静摩擦力↑)
            slip_adjustment = self.Kp_slip * shear_magnitude
            force_adjustment += slip_adjustment
        
        return np.clip(force_adjustment, -1.0, 3.0)

# 触觉伺服的工程实现细节
class GelSightSimulator:
    """仿真环境中的触觉传感器模拟"""
    
    def __init__(self, resolution=(320, 240)):
        self.resolution = resolution
    
    def read(self, contact_points, contact_normals, contact_forces):
        """将仿真中的接触点转换为GelSight式读数"""
        # 将3D接触点投影到触觉传感器平面
        pressure_map = np.zeros(self.resolution)
        for point, normal, force in zip(contact_points, contact_normals, contact_forces):
            # 投影到传感器成像平面
            u = int((point[0] + 0.02) / 0.04 * self.resolution[0])
            v = int((point[1] + 0.015) / 0.03 * self.resolution[1])
            if 0 <= u < self.resolution[0] and 0 <= v < self.resolution[1]:
                pressure = force * np.abs(np.dot(normal, [0,0,1]))
                pressure_map[v, u] = max(pressure_map[v, u], pressure)
        
        return TactileReading(
            normal_pressure=pressure_map,
            shear_force=np.array([np.sum(pressure_map[:, 1:]) - np.sum(pressure_map[:, :-1]),
                              np.sum(pressure_map[1:, :]) - np.sum(pressure_map[:-1, :])]),
            contact_area=np.sum(pressure_map > 0)
        )
🔧 工程连接:触觉伺服的防滑控制和你在螺栓拧紧中使用的扭矩-角度控制是一回事——当扭矩(剪切力)开始异常变化时,增加预紧力(法向力)来防止松动。

7. 软体手与欠驱动自适应——机械设计的终极体现

为什么用欠驱动

全驱动灵巧手(如Shadow Hand,24个电机)价格$100K+、控制极复杂。欠驱动手指用一个电机 + 弹簧/腱绳联动驱动多个关节——手指单方向闭合时,各关节按预定的耦合比弯曲,直到任一关节碰到物体。这就是机械自适应——不需要算法感知和决策。

腱绳驱动力学模型

$$\tau = \mathbf{P}(q) \mathbf{f}_t$$

$\mathbf{P}(q)$是腱绳路径雅可比——腱绳张力$\mathbf{f}_t$到关节力矩$\tau$的映射。你设计连杆机构时的力传递比就是$\mathbf{P}(q)$的物理含义。

软体手设计的三要素(机械工程师强项)

软体抓取的有限元分析

# 使用FEniCS/FEBio进行软体手指接触仿真
# 你的Abaqus/ANSYS经验直接适用
import fenics as fe

# 定义材料:Neo-Hookean超弹性(硅胶)
class SoftFingerFEA:
    def __init__(self, mesh_file, young_modulus=500e3, poisson=0.49):
        self.mesh = fe.Mesh(mesh_file)
        self.V = fe.VectorFunctionSpace(self.mesh, 'P', 2)
        # 超弹性材料参数
        mu = young_modulus / (2 * (1 + poisson))
        self.material = fe.NeoHookeanMaterial(mu)
    
    def simulate_grasp(self, object_mesh, actuation_pressure):
        """仿真软体手指以给定气压抓取物体"""
        # 施加气动压力、接触约束、求解非线性问题
        # ... FEA求解流程 ...
        return {
            'contact_force': contact_force,
            'deformation_field': displacement,
            'stress_distribution': stress,
        }

验收标准

  • 实现完整的抓取分类检测器:输入接触点→输出抓取类型和力闭合判断
  • 实现Allegro Hand四指协同IK + 自碰撞检测
  • 实现触觉伺服闭环控制器,防止物体在抓取中滑动
  • 用FEA分析软体手指在不同气压下的接触力分布
  • 对比3指/4指/5指抓取的力闭合成功率(> 3指实现 > 90%闭合率)