Skip to content

LEGO SPIKE 手势控制三自由度机械臂教案

一、教学目标

1. 知识目标

  • 了解 AI 视觉传感器识别手势的基本原理
  • 理解矩形框中心点 X/Y 坐标的意义
  • 学习 LEGO SPIKE 电机角度控制方法
  • 学习串口通信协议的数据解析方式
  • 初步理解“位置控制”与“PID 控制”的区别

2. 技能目标

  • 能够完成三自由度机械臂的搭建
  • 能够实现手势控制机械臂左右、上下、抓取动作
  • 能够使用 RobotCode App 编写视觉逻辑
  • 能够使用 SPIKE App 编写电机控制程序
  • 能够调试机械臂动作与手势映射关系

3. 思维目标

  • 培养“视觉识别 → 数据协议 → 机械执行”的系统思维
  • 培养 AI + 机器人跨学科综合实践能力
  • 理解人机交互的基本实现方式

二、教学准备

1. 硬件准备

硬件数量说明
LEGO SPIKE 主机1主控制器
AI视觉传感器1接 SPIKE A 口
LEGO 电机3分别接 C、D、E
USB数据线1下载程序
电脑/平板1编程使用

2. 接线说明

设备接口
AI视觉传感器A口
左右旋转电机C口
上下控制电机D口
机械爪电机E口

3. 软件准备

软件作用
LEGO SPIKE App电机控制程序
RobotCode AppAI视觉识别与协议处理

三、教学流程

第一阶段:课程导入

教师演示

教师演示:

  • 手向左移动 → 机械臂向左
  • 手向右移动 → 机械臂向右
  • 手抬高 → 机械臂抬起
  • 五指并拢 → 机械爪抓取

引导学生思考:

“机械臂为什么能理解我们的手势?”


第二阶段:机械臂搭建

搭建要求

机械臂需要具备:

  • 左右旋转自由度(C电机)
  • 上下抬升自由度(D电机)
  • 机械抓取自由度(E电机)

alt text 简单抓取结构参考官方的搭建版本,也可以自行构建


第三阶段:初级编程(位置控制)

教学重点

本阶段:

  • 不使用 PID 算法

  • 直接根据位置控制角度

  • 重点理解:

    • 坐标判断
    • 数据协议
    • 电机动作映射

RobotCode App 逻辑

摄像头分辨率

设置为:

800 宽度分辨率


左右控制逻辑(C电机)

X坐标范围C电机角度
X < 300320°(左)
300 ~ 5000°(中间)
X > 50040°(右)

上下控制逻辑(D电机)

Y坐标D电机角度
Y < 20045°(向上)
Y ≥ 2000°(向下)

抓取判断逻辑(E电机)

判断:

大拇指指尖 与 食指指尖 的 Y 方向距离。

当:

距离 ≤ 50

认为“五指并拢”。

机械爪执行抓取动作。


数据协议设计

协议结构

采用:

百位 + 十位 + 个位


协议含义

位数含义
百位是否抓取
十位D电机状态
个位C电机状态

协议示例

101

表示:

  • 抓取
  • D电机处于下方
  • C电机处于左边

Senrayvar APP 程序逻辑

alt text

SPIKE App 程序逻辑

电机控制逻辑

C电机

状态角度
0
1320°
240°

D电机

状态角度
0
145°

E电机

状态动作
0松开
1抓取

代码示例

alt text


第四阶段:高级编程(P-Control 控制)

高级协议设计

RobotCode App 返回:

  • x = 矩形框中心点X / 10
  • y = 矩形框中心点Y / 50
  • catch = 0 或 1

协议格式

catch * 1000 + y * 100 + x


示例

1642

表示:

  • 抓取
  • y = 6
  • x = 42

senrayvar scratch 代码

alt text

SPIKE Python 核心代码

import distance_sensor
import motor
import runloop
from hub import port
# from app import display

# --- 核心配置参数 ---
GRAB_DEGREE = 350
RELEASE_DEGREE = 25
MOTOR_SPEED = 200

X_CENTER = 40 # 映射后的中点
Y_CENTER = 6 # 映射后Y轴的中点, 不需要向下

X_MULTIPLIER = 2
Y_MULTIPLIER = 5

# --- 丝滑控制参数 (P-Control) ---
GAIN = 6        # 速度增益(灵敏度)。如果电机跟手太慢就调大(如8),如果到位后容易来回晃就调小(如4)
MAX_SPEED = 400 # 限制最高转速,防止动作太猛烈
DEADZONE_C = 2    # 死区(度):误差在这个范围内认为已到达,电机刹车,防止微小数值跳动引发的嗡嗡响
DEADZONE_D = 2

def get_shortest_error(target, current):
    """计算最短路径的角度差 (-180 到 180)"""
    error = target - current
    if error > 180:
        error -= 360
    elif error < -180:
        error += 360
    return error

async def main():
    while True:
        dist_mm = distance_sensor.distance(port.A)

        if dist_mm <= 0:
            # 丢失目标时,让电机失去动力平滑溜车停止,而不是急刹车
            motor.stop(port.C, stop=motor.COAST)
            motor.stop(port.D, stop=motor.HOLD)
            await runloop.sleep_ms(20)
            continue

        dist_cm = dist_mm // 10

        # 解析数据
        x_val = dist_cm % 100
        y_val = (dist_cm // 100) % 10
        action_code = dist_cm // 1000

        # 计算新的理论目标位置 (0-359 范围内)
        target_c = int((x_val - X_CENTER) * X_MULTIPLIER) % 360
        target_d = int(-(y_val - Y_CENTER) * Y_MULTIPLIER)

        # 获取电机当前真实的绝对角度
        current_c = motor.absolute_position(port.C) % 360

        # 计算应该向哪个方向转、转多少度 (最短路径)
        error_c = get_shortest_error(target_c, current_c)

        # display.text(str(target_c) + " " +str(target_d) + " " + str(action_code))

        # ----------------------------------------------------
        # 核心修改:使用比例速度控制替代位置控制
        # ----------------------------------------------------

        # 控制 C 电机 (X轴)
        if abs(error_c) > DEADZONE_C:
            # 距离越远,算出来的速度越大;快到了,速度自动变小
            speed_c = int(error_c * GAIN)
            # 限制速度在 MAX_SPEED 内
            speed_c = max(min(speed_c, MAX_SPEED), -MAX_SPEED)
            # 使用 motor.run 发送持续的速度指令
            motor.run(port.C, speed_c)
        else:
            motor.stop(port.C, stop=motor.COAST)

        # 控制 D 电机 (Y轴)
        if target_d > 5:
            motor.run_to_absolute_position(port.D, 45, MOTOR_SPEED, direction=motor.SHORTEST_PATH)
        else:
            motor.run_to_absolute_position(port.D, 0, MOTOR_SPEED, direction=motor.SHORTEST_PATH)

        # 4. 控制机械爪电机 E (抓和放属于定点动作,依然可以用位置控制)
        if action_code == 1:
            motor.run_to_absolute_position(port.E, GRAB_DEGREE, 1000, direction=motor.SHORTEST_PATH)
        elif action_code == 0:
            motor.run_to_absolute_position(port.E, RELEASE_DEGREE, 1000, direction=motor.SHORTEST_PATH)

        # 刷新频率改为 20ms。5ms 对物理电机响应来说太快了,容易积压指令。20ms(约50fps) 足够视觉上的丝滑了。
        await runloop.sleep_ms(10)


runloop.run(main())

四、演示与测试

测试内容

1. 左右跟随测试

移动手掌: 机械臂是否正确左右旋转。


2. 上下控制测试

抬高手掌: 机械臂是否抬起。


3. 抓取测试

五指并拢: 机械爪是否抓取。


4. 综合测试

连续完成:

  • 左右移动
  • 上下移动
  • 抓取动作

观察机械臂是否稳定。


五、拓展思考

问题1

如果想让机械臂更加丝滑, 除了 P-Control, 还能加入什么算法?

提示:

PID算法。


问题2

如果加入 AI 模型, 机械臂还能识别哪些手势?

例如:

  • OK
  • 点赞
  • 握拳
  • 数字手势

六、教学总结

本节课学习了:

  • AI视觉识别
  • 手势坐标获取
  • 数据协议设计
  • SPIKE 电机控制
  • 三自由度机械臂控制

同学们体验了:

“用自己的手控制机器人”。


七、课堂展示

展示内容

每组同学完成:

  • 手势控制机械臂
  • 完成抓取任务
  • 展示自己的扩展创意

Released under the MIT License.