教程 · 中级 · 阅读约 35 分钟

一个经得起失败的拾取与放置状态机

接近、抓取、验证、抬起、放置——把这些步骤写成一台状态机,其中的验证步骤能把一次演示变成可以放心无人值守运行的系统。

为什么演示行、系统不行

人人的第一版取放都是一串 delay() 调用。走到这,合爪,走到那,张爪。拍视频行,台架上一百次成八十次,感觉接近完成了。

离完成还远,因为二十次失败全是静默的:夹爪合了个空,手臂抱着空气过桌子,在料盒上空张开。零件稍歪,没夹起来反而撞倒。抬到一半舵机欠压复位,控制器重启进未知位形还合着爪。

把这些灾难变成可恢复的只有一样:抓取和抬起之间的验证步骤,以及验证失败时有处可去的状态机。这就是本文的全部主题。

状态

取放循环九个状态,值得全命名,不合并。

状态 做什么 退出条件
IDLE 等活 取件请求到达
APPROACH 走到物体上方位形,夹爪张开 手臂稳定
DESCEND 直线下到抓取位形 到深度,或接触传感器触发
GRASP 合爪,再停留 停留结束
VERIFY 检查真夹到东西了 夹到→LIFT,落空→RECOVER
LIFT 直线退回接近位形 手臂稳定
TRANSFER 走到放置目标上方 手臂稳定
PLACE 下降、张开、停留、撤退 撤退完成
RECOVER 张爪、撤退、计数,重试或放弃 重试→APPROACH,放弃→带故障回 IDLE

两个设计点干了大部分活。

接近和撤退位形是独立状态,在物体上方。 夹爪从任意方向直扑零件会撞倒它,沿曲线抬起会在脱离前横向拖拽。永远从正上方(或沿插入轴)走一小段直线进出。

VERIFY 是状态,不是一行代码。 它是循环里机器唯一发现现实与计划是否相符的地方,失败要有处可去。

验证抓取

四种办法,最便宜先行,至少要一种。

爪位检查(免费)

夹爪有串联柔顺时,夹到东西的爪停在比空合更开的位置。能读爪位,对比空合位置,就知道指间有东西。

普通业余级舵机读不到位置——开环。但把舵机电位器抽头引到 ADC 脚,一根线的代价就有这个,改装十分钟。

局限: 只知道有东西,不知道是想要的东西,也不知道夹得牢不牢。

指上微动开关(约 50 便士)

一指内侧装杠杆微动开关,接上拉输入脚。垫块碰到东西即闭合。

这是性价比断层第一,直接用数字回答“指间有没有东西”,皮实耐造,软件三行消抖。装在手指柔顺段,保证以可重复的力可靠触发。

电流检测(约 2 英镑)

舵机供电串分流电阻或霍尔传感器。空合的舵机电流回落到待机,夹到东西的舵机维持高电流。

局限: 噪声大,阈值要标定,电池一下垂就错。想检压坏而不只检夹住时值——电流远超预期意味着零件比预期硬,或打偏夹了夹具。

爪间对射(约 1 英镑)

爪口两侧红外发射加光敏接收,光束断了说明间隙里有东西。

局限: 没夹也看得见,验的是存在而非抓牢,配别的方法用。在视觉搞不定的透明或深色零件机器上是真好用。

写法

套路是普通有限状态机加非阻塞定时,循环里什么都不卡,急停一直灵敏:

enum State { IDLE, APPROACH, DESCEND, GRASP, VERIFY, LIFT, TRANSFER, PLACE, RECOVER };

State state = IDLE;
uint32_t stateEnteredAt = 0;
uint8_t  attempts = 0;

const uint8_t  MAX_ATTEMPTS = 3;
const uint16_t GRASP_DWELL_MS = 350;   // let the compliance settle before you trust it
const uint16_t SETTLE_MS      = 250;

void enter(State next) { state = next; stateEnteredAt = millis(); }
bool elapsed(uint16_t ms) { return millis() - stateEnteredAt >= ms; }

// Debounced: one reading is a glitch, three in a row is a fact.
bool objectHeld() {
  static uint8_t streak = 0;
  streak = digitalRead(GRIP_SWITCH) == LOW ? min(streak + 1, 3) : 0;
  return streak >= 3;
}

void loop() {
  arm.update();          // non-blocking motion, every pass
  gripper.update();

  switch (state) {
    case IDLE:
      if (jobPending()) { attempts = 0; arm.moveTo(approachPose); enter(APPROACH); }
      break;

    case APPROACH:
      gripper.open();
      if (arm.arrived() && elapsed(SETTLE_MS)) { arm.moveTo(graspPose); enter(DESCEND); }
      break;

    case DESCEND:
      if (arm.arrived()) { gripper.close(); enter(GRASP); }
      break;

    case GRASP:
      // The dwell is not politeness. A compliant finger rings after closing,
      // and reading the switch during the ring gives you a coin flip.
      if (elapsed(GRASP_DWELL_MS)) enter(VERIFY);
      break;

    case VERIFY:
      if (objectHeld()) { arm.moveTo(approachPose); enter(LIFT); }
      else              { enter(RECOVER); }
      break;

    case LIFT:
      if (arm.arrived()) { arm.moveTo(placeApproach); enter(TRANSFER); }
      break;

    case TRANSFER:
      if (arm.arrived()) { arm.moveTo(placePose); enter(PLACE); }
      break;

    case PLACE:
      if (arm.arrived() && elapsed(SETTLE_MS)) {
        gripper.open();
        // Open BEFORE retreating, and retreat straight up, or you drag the part.
        if (elapsed(SETTLE_MS + 200)) { arm.moveTo(placeApproach); enter(IDLE); }
      }
      break;

    case RECOVER:
      gripper.open();
      if (elapsed(SETTLE_MS)) {
        if (++attempts < MAX_ATTEMPTS) { arm.moveTo(approachPose); enter(APPROACH); }
        else { raiseFault("grasp failed after 3 attempts"); enter(IDLE); }
      }
      break;
  }
}

里面三处细节配得上位置:

抓取停留。 柔顺手指合上后振铃两三百毫秒,振铃里读开关等于抛硬币。300–400 ms 通常够;把合爪后一秒的开关打出来量自己的。

消抖验证。 一次读数是毛刺,连续三次是事实,三次只是几百赫兹循环里的三遍。

有界重试。 无限重试就是机器人对着一小时前掉地上的零件空转整晚。三次,之后报人工清除的故障。

重试还不行时

RECOVER 原样只会从同一位形再试,修常见情况够了——零件稍偏,爪拨一下,第二次就中。零件整个不在那就没办法。有用的升级,按顺序:

  1. 挪接近点。 每次重试把抓取位形按小螺旋偏几毫米。三行,挽回率高得意外。
  2. 重感知。 有相机或测距就重新读一次,不信发下来的位形。
  3. 张大点。 按标称零件紧配的开口,零件一转就失败,重试时张大。
  4. 大声放弃。 报出卡在哪个状态、停机待人工,胜过默默往次品箱里填。

不是夹爪的锅的故障

取放不可靠,常不是抓取:

现象 通常原因
只在快速节拍失败 稳定时间不够,手臂按自己的账到了,实际还在振铃
跑二十分钟后失败 舵机发热,见堵转电流——爪可能全程合着回去的
接近时撞倒零件 沿插入轴斜着下,而非直线
搬运途中掉,而非抓取时掉 加速度。抓取按静态保持配的,运动要更大
松开时拖拽零件 爪没全开就撤,或沿曲线撤
循环中途控制器重启 舵机供电欠压,舵机电源轨分开
能跑,越跑越不行 垫脏了。μ 随灰积下降,还没告警

第四行值得多说,因为最像玄学。台架上夹得好好的,抬起 40 ms 就掉——手臂还没看出动作——因为加速度项主导。夹爪模拟器按你的数算出确切时刻,修复通常是放慢曲线而非加力。

下一步

循环可靠之后,按价值排序值得加的:

  1. 循环计数加故障日志。 不量的可靠性没法改进。
  2. 搬运段加正规运动曲线,加速度有界,不再靠加大夹力扛颠簸。
  3. 位形来自感知而非常量,这是从演示到机器的一步。

下一步

探索关联图谱

本教程所属的搭建

包含本教程的项目和学习路线。

延伸阅读

参考资料