方法要解决什么问题
传统 Vision-Language-Action(VLA) 策略主要依赖视觉、语言指令和机器人本体状态来生成动作。它们适合处理许多开放任务,但在接触密集的操作里会遇到两个问题:

视觉看不到物体的内部或接触属性,例如芒果软硬、海绵粗糙度、杯子是否装水。
基础 VLA 生成的动作块可能在宏观方向上正确,但接触阶段需要更精细的实时修正,例如抓取力度、末端位姿和贴近物体时的轨迹微调。
VLA-Touch 的核心思想是:不直接重新训练一个触觉版大 VLA,而是在基础 VLA 外面加两层触觉反馈。

第一层是高层规划反馈:把触觉观测转成语言或语义属性,反馈给视觉语言规划器,让它决定下一步该触摸、比较、抓取还是放置。

第二层是低层执行反馈:基础 VLA 先产生一个未来动作块,然后触觉条件控制器把这个动作块修正成更接近专家执行轨迹的动作块。

因此,VLA-Touch 是一个双层触觉增强框架:

高层:视觉 + 任务目标 + 触觉语义反馈 -> 下一条原子操作指令
低层:视觉 + 机器人状态 + 触觉力/位移 + VLA动作块 -> refined动作块
2. 总体架构
一个完整闭环由四类模型或算法组成:

基础 VLA 策略

输入:当前/历史视觉图像、语言指令、机器人状态。
输出:未来一段时间的动作块。
在本项目里基础策略沿用 RDT 风格的 diffusion transformer,动作表示为末端位姿、6D 旋转和夹爪等 10 维量。
触觉语义模型或触觉反馈接口

输入:GelSight 触觉图像序列、属性值或低维力向量。
输出:硬度、粗糙度、重量/力大小等语义反馈。
对规划器来说,这些反馈最终以自然语言或结构化文本进入上下文。
VLM 任务规划器

输入:初始场景图像、任务目标、历史动作和触觉反馈。
输出:下一条简短、可执行的原子动作指令。
每次只规划一步,执行后等待反馈,再继续规划。
触觉条件动作修正器

输入:基础 VLA 的动作块、当前图像、当前机器人状态、触觉低维信号。
输出:修正后的动作块。
它不替代基础 VLA,而是学习从“VLA 动作分布”桥接到“专家动作分布”。
整体数据流如下:

任务目标 g + 场景图像 s_t
|
v
VLM planner 生成原子指令 I_k
|
v
基础 VLA: pi(a_t | s_t, I_k) 生成动作块 a_t
|
v
触觉条件插值控制器: pi_I(a_hat_t | s_t, a_t, m_t) 修正动作块
|
v
机器人执行 a_hat_t 的若干步
|
v
GelSight 触觉反馈 o^m_t
|
±-> 高层:转成语言/属性 L^m_t,反馈给 VLM planner
|
±-> 低层:转成 force/displacement m_t,条件化动作修正器
3. 高层触觉反馈:用触觉补足视觉无法判断的信息
高层模块解决的是“该做什么”的问题。

许多任务不能只靠视觉一步完成。例如:

在两块海绵中选择更光滑的一块,需要触摸后判断粗糙度。
在两个芒果中选择更熟的一颗,需要触摸后判断软硬。
判断杯子是否装水,可以通过抓取或移动时的力反馈推断重量。
VLA-Touch 把这些触觉信息放进规划闭环。规划器不是一次性输出完整长程计划,而是像交互式机器人一样,每次输出一个原子动作:

触摸左侧海绵以判断粗糙度
执行后,系统把触觉反馈返回给规划器:

左侧海绵触觉反馈:粗糙度较低,表面较光滑
然后规划器继续输出下一步:

触摸右侧海绵以判断粗糙度
直到信息足够,再生成最终操作:

抓取更光滑的左侧海绵
3.1 触觉语义反馈的形式
项目中支持几种反馈形式,它们本质上都服务于同一个接口:让规划器获得视觉之外的物理属性。

触觉图像反馈

取触摸前和触摸后的 GelSight 图像。
让多模态模型分析两张图像差异。
输出类似“更硬”“更软”“更粗糙”“更光滑”的描述。
属性回归反馈

触觉视频帧进入 ViFiCLIP/CLIP 风格编码器。
时间维特征平均池化,经过 adapter。
属性回归头输出硬度和粗糙度两个连续值。
再用阈值或相对比较转成任务可用语义。
力向量反馈

GelSight marker 位移被转换成低维力向量。
杯子任务中,较大的力幅值可作为“更重/更可能装水”的证据。
反馈文本中可包含参考阈值,例如空杯和满杯的大致力幅值范围。
3.2 高层规划伪代码
def tactile_planning_loop(scene_image, task_goal):
# messages 保存完整交互上下文:初始任务、历史动作、历史触觉反馈。
# VLM planner 每次都基于这个上下文决定下一步,而不是一次性写完整计划。
messages = [
system_prompt(
"You are a robot planner. Output one primitive action at a time. "
“Use tactile feedback to retrieve unknown physical properties.”
),
user_prompt(task_goal, image=scene_image),
]

while not task_done:
    # 规划器只输出一个原子动作,例如“触摸左侧海绵”。
    # 这样可以先主动获取未知物理属性,再决定最终操作。
    primitive_action = vlm_planner(messages)

    # 该动作可以由机器人真实执行,也可以在离线实验中由用户输入反馈模拟。
    execution_result = execute_or_request_action(primitive_action)

    if execution_result.has_tactile_images:
        # 触觉图像用于判断粗糙度、软硬等视觉不可见属性。
        # before/after 的差异通常比单帧更能体现接触形变。
        tactile_feedback = tactile_model.describe(
            before_image=execution_result.tactile_before,
            after_image=execution_result.tactile_after,
            query=property_query_for_task(task_goal),
        )
    elif execution_result.has_force_vector:
        # 对杯子重量等任务,低维力向量比触觉图像更直接。
        # reference 给规划器一个任务相关阈值或经验范围。
        tactile_feedback = format_force_feedback(
            magnitude=execution_result.force_magnitude,
            direction=execution_result.force_xy_direction,
            reference=task_specific_force_reference,
        )
    elif execution_result.has_property_values:
        # 如果触觉编码器已经输出硬度/粗糙度数值,直接转成文本反馈。
        tactile_feedback = format_property_feedback(
            hardness=execution_result.hardness,
            roughness=execution_result.roughness,
        )
    else:
        # 兜底情况:使用人工文本反馈或执行状态反馈。
        tactile_feedback = execution_result.text_feedback

    # 把本轮动作和触觉反馈写回上下文,下一轮规划会使用这些信息。
    messages.append(assistant_message(primitive_action))
    messages.append(user_message(tactile_feedback))

# 最终可以返回完成动作,也可以保存整段交互日志用于评估。
return final_action_or_session_log

这里的关键不是具体使用哪个 VLM API,而是闭环结构:

规划一步 -> 执行/触摸 -> 得到触觉反馈 -> 更新上下文 -> 再规划一步
4. 低层触觉反馈:把 VLA 动作修正成专家动作
低层模块解决的是“怎么做得更准”的问题。

基础 VLA 已经能根据视觉和语言输出一个动作块:

a_vla = [a_t, a_{t+1}, …, a_{t+H-1}]
其中每个动作大致是 10 维:

[eef_pos_x, eef_pos_y, eef_pos_z, eef_rotation_6d, gripper]
但是在接触场景下,基础 VLA 的动作可能缺少触觉响应。VLA-Touch 不让低层控制器从零生成动作,而是让它学习一个条件变换:

VLA 动作块 -> 专家动作块
这个变换由 Stochastic Interpolants / bridge diffusion 实现。直观理解是:把 VLA 动作当作起点,把专家动作当作终点,在两者之间训练一条可采样的随机桥。推理时,从 VLA 动作起点出发,沿着学到的桥走若干步,得到更接近专家分布的 refined 动作。

4.1 低层控制器输入输出
低层控制器输入:

current_state: 当前机器人末端状态和夹爪状态
front_image: 当前正面相机图像
right_image: 当前右腕/侧视相机图像
tactile_force: GelSight 低维力向量,通常是 [magnitude, dir_x, dir_y]
vla_action_chunk: 基础 VLA 输出的 H 步动作块
低层控制器输出:

refined_action_chunk: H 步修正动作块
条件编码方式:

两路 RGB 图像分别输入 DINOv2,得到视觉特征。
当前机器人状态和触觉力向量拼接。
将 视觉特征1 + 视觉特征2 + 状态 + 触觉 拼接后输入 MLP。
MLP 输出一个条件向量 obs_cond。
obs_cond 条件化 1D U-Net 插值网络,网络在动作序列维度上工作。
obs_cond = MLP([DINO(front), DINO(right), state, tactile_force])
refined_actions = StochasticInterpolants.sample(x_prior=vla_actions, cond=obs_cond)
5. GelSight 低维触觉力如何得到
低层控制器不直接吃完整 GelSight 图像,而是使用 marker tracking 得到的低维触觉信号。

处理过程:

用无接触或初始触觉图像作为校准帧。
在校准帧中检测 GelSight 表面的标记点。
每一帧触觉图像都经过灰度化、模糊、自适应阈值和形态学处理。
通过轮廓检测找到当前标记点中心。
使用最近邻把当前标记点和校准帧标记点匹配。
计算每个 marker 的位移。
对所有 marker 位移求平均,得到整体剪切方向。
平均位移的 L2 范数作为力幅值,单位向量作为方向。
伪代码:

def estimate_gelsight_force(calibration_frame, current_frame):
# calibration_frame 是无接触或初始接触很弱的参考帧。
# 当前帧中的 marker 位移都相对于这个基准来计算。
baseline_markers = detect_markers(preprocess(calibration_frame))
current_markers = detect_markers(preprocess(current_frame))

displacements = []
for marker in current_markers:
    # 用最近邻把当前 marker 匹配回参考帧中的 marker。
    # 这个近似要求相邻帧 marker 位移不要大到发生严重错配。
    nearest_baseline = nearest_neighbor(marker, baseline_markers)
    displacements.append(marker - nearest_baseline)

# 平均位移代表整体剪切方向;局部复杂形变在这里被压缩成低维量。
avg_displacement = mean(displacements)
magnitude = l2_norm(avg_displacement)

if magnitude > 0:
    # 单位方向只描述 xy 平面上的剪切方向。
    direction = avg_displacement / magnitude
else:
    # 没有明显位移时,方向设为零向量,避免除零。
    direction = [0, 0]

# 低层控制器最终使用 3 维触觉信号:[力幅值, x方向, y方向]。
return [magnitude, direction[0], direction[1]]

这个设计的优点是简单、实时、可解释。它牺牲了触觉图像的丰富细节,但给低层控制器提供了稳定的接触强度和方向信号。

  1. 控制器训练数据如何构造
    低层控制器需要成对数据:

(当前观测, VLA动作块, 专家动作块, 触觉信号)
构造方式:

先收集专家演示轨迹,包括相机图像、末端状态、夹爪状态、GelSight 数据和语言指令。
用已训练或微调好的基础 VLA 离线跑每个时间步。
对每个时间步保存基础 VLA 预测出的动作块 vla_action。
专家动作块直接来自演示数据中当前时间之后的真实末端轨迹。
GelSight 图像离线转换成 marker displacement 和 force。
训练样本按滑动窗口切片。
一个训练样本可以表示为:

states = [q_t-C+1, …, q_t, q_{t+1}, …, q_{t+H}]
vla_actions = VLA(s_t, I)[0:H]
expert_actions = [q_{t+1}, …, q_{t+H}]
forces = [m_t-C+1, …, m_t, m_{t+1}, …, m_{t+H}]
images = 当前上下文图像

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐