eefocus_3891719 发表于 前天 01:19

【欧时RS x Arduino】04 AI控制风扇

# 背景

经过前面的铺垫,熟悉了AI手势识别,并且在MCU侧实现了电机档位控制,现在只需要把两者结合起来就可以了。

目的是:Arduino Uno Q 通过 USB Hub 接入 USB 摄像头,运行 Edge Impulse 本地识别手势,然后通过 Bridge 发送消息通知 MCU 侧控制电机,例如启动、停止、切换档位。

# 模型介绍

这个 hand\-gestures 模型来自 https://studio\.edgeimpulse\.com/public/842271/live 这个项目。这是一个轻量级的视觉项目,摄像头目标识别4种手势:

- nestral fist
- thumbs\-up \(good\)
- V\-sign \(peace\)
- open hand \(five\)

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011754hk497clg8zc1tz84.png)

# 流程介绍

首先,给程序添加一个 Brick,如下图所示,video\_object\_detection,对应的模型选择 hand\-gestures

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011806dcjcm6s1ut519sss.png)

## 主流程

- Linux 侧初始化摄像头、手势识别模型、网页界面和通信服务
- 摄像头持续采集画面,由本地模型进行推理,输出手势类别以及置信度
- 识别回调将结果推送到网页,同时保存最新识别结果,供主循环读取
- 主循环对识别结果进行置信度过滤和连续确认,再将手势映射为风扇档位:neut 对应停转,good/peace/five 分别对应1/2/3档
- 只有识别结果满足确认条件、目标档位发生变化切达到指令发送间隔时,Linux 才通过 Bridge 下发 fan\_set 指令;否则继续识别,风扇保持原档位
- MCU接收到指令后,将档位限制在0\~3范围内,再转换为对应的PWM值,通过 TB6612FNG 驱动模块控制风扇停止或调整转速

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011816f0rdohdrp05htt5d.png)

## 交互图

- Linux 侧的识别模块首先将手势类别、置信度和事件序号交给档位决策模块
- 决策模块完成连续确认、档位去重以及发送节流后,调用 Bridge\.notify\("fan\_set", level\) 将目标档位发送给MCU
- MCU通过已注册的 cmd\_fan\_set\(\) 回调接受指令,并调用电机控制函数,将档位转换为PWM输出。PWM值依次分别是 \{0, 120, 170, 255\},对应停转以及3个运行档位,最终由驱动模块作用于电机

整个交互过程中,图像采集、AI推理和控制决策都在 Linux 侧完成,MCU 负责确定性的硬件控制。两侧传递的是档位数值,无需传输图像。 notify 不等待执行回执,因此该交互表示指令下发和执行路径,不包含实际转速反馈。

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011825dpfpz2fq8j93ofyl.png)

# 关键代码

## 初始化摄像头与识别器

```Plain
camera = Camera(
    resolution=CAMERA_RESOLUTION,
    fps=CAMERA_FPS,
)

detector = VideoObjectDetection(
    camera=camera,
    confidence=GESTURE_CONFIDENCE,
    debounce_sec=GESTURE_DEBOUNCE_S,
    camera_preview=False,
)

gestures.attach(detector)
```

Linux 侧采集摄像头画面,使用工程配置的 hand\-gestures 模型进行本**理;置信度门槛和回调间隔由配置控制。

## 接收识别结果

```Python
def handler(detections):
    best = None

    for label, items in (detections or {}).items():
      confidence = (
            float(items.get("confidence", 0.0))
            if items else 0.0
      )

      if best is None or confidence > best:
            best = (label, confidence)

    if best is not None:
      self._record(best, best)

detector.on_detect_all(handler)
```

回调从识别结果中选出置信度最高的类别,并保存到“最新结果”槽位,交给主循环处理。

## 手势映射为风扇档位

```Python
GESTURE_TO_LEVEL = {
    "neut":0,# 握拳:停转
    "good":1,# 大拇指:1档
    "peace": 2,# 剪刀手:2档
    "five":3,# 张开手掌:3档
}
```

采用绝对档位映射,同一手势始终对应同一档位。

## 连续确认和档位去重

```Python
level = GESTURE_TO_LEVEL.get(label)
if level is None:
    return

required = (
    NEUT_CONFIRM_COUNT
    if label == "neut"
    else GESTURE_CONFIRM_COUNT
)

if self._candidate is not None and level == self._candidate:
    self._candidate = (level, self._candidate + 1)
else:
    self._candidate = (level, 1)

if self._candidate < required:
    return

if level == self._current_level:
    return

self._pending = (level, label, confidence)
```

同一目标档位达到确认次数后才进入带发送状态;档位未变化则不重复发送。完整实现还包含 neut 专用置信度门槛、确认过期和发送间隔控制。

## 通过Bridge下发指令

```Python
class FanController:
    def set_level(self, level):
      level = max(LEVEL_STOP, min(LEVEL_MAX, int(level)))
      Bridge.notify(RPC_FAN_SET, level)
      return level
```

将档位限制到合法范围,通过 fan\_set 通知 MCU。 notify\(\) 不等待执行结果。

## MCU 注册并处理指令

```Plain
// 初始化时注册
Bridge.provide_safe(RPC_FAN_SET, cmd_fan_set);

void cmd_fan_set(int level)
{
    motor_set_level(level);
}
```

MCU 暴露 fan\_set\(\) 接口,收到 Linux 指令后执行电机控制函数。 provide\_safe\(\) 让回调在安全的主循环上下文执行。

## 档位转换为 PWM

```Plain
const int DUTY_FOR_LEVEL = {
    0, 120, 170, 255
};

void motor_set_level(int level)
{
    if (level < 0)
      level = 0;

    if (level > FAN_LEVEL_MAX)
      level = FAN_LEVEL_MAX;

    analogWrite(MOTOR_PIN_PWMA, DUTY_FOR_LEVEL);
    matrix_display_set_level(level);
}
```

档位 0\~3 分别转换为对应 PWM,经 TB6612FNG 驱动风扇。最后一行同步更新点阵侠士,不参与电机调速。

# 主循环持续驱动

```Plain
def loop():
    service.tick()       # 心跳与通信检测
    reporter.tick()      # MCU启动回执
    control_tick()       # AI模式的阈值更新与手势决策
    time.sleep(LOOP_SLEEP_S)

App.run(user_loop=loop)
```

识别回调负责提供结果,主循环持续完成控制决策,两者分工执行。

# 实物演示

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011902hohbh7a2x2d3bkxc.png)

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011907jvb8rbh9egg9z8m9.png)

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011911doa4fl4p4c96l7f0.png)

!(//m.qjumbo.com/forum/data/attachment/forum/202611/01/011916clun9j4524i52njj.png)

视频演示

<iframe src="//player.bilibili.com/player.html?isOutside=true&aid=117496715679056&bvid=BV15RHT6NEJV&cid=43022814171&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>

页: [1]
查看完整版本: 【欧时RS x Arduino】04 AI控制风扇

Baidu
map