实验05:陀螺仪精确转向
这个实验做完你会得到什么
点一个按钮,小车精确转 90 度然后停下 —— 不管电池满不满、地面滑不滑,角度都准。 再让它自己走一个正方形。
前面用时间控制转向(转 600 毫秒)根本不准:电池电量、地面摩擦、负载轻重都会影响。 这一篇改成闭环控制 —— 一边转一边看陀螺仪,到角度就停。
| 项目 | 说明 |
|---|---|
| 难度 | ★★★☆☆ |
| 用时 | 约 45 分钟 |
| 前置 | 实验02:差速小车遥控 |
一、器材与接线
| 器材 | 数量 | 接到 |
|---|---|---|
| EV3 主机 + 两个大型马达 | 1 | 马达接 B、C |
| EV3 陀螺仪传感器 | 1 | 传感器接 S2 |
陀螺仪要装平(和地面平行),装歪了测出来的不是水平转角。
二、两种模式
| 模式 | 设置方法 | 读到的是 |
|---|---|---|
| 角度模式 | SetAngleMode() |
累计转过的角度(度),会一直累加 |
| 速率模式 | SetRateMode() |
当前角速度(度/秒) |
本篇用角度模式。
⚠️ 陀螺仪会漂移:静止不动时读数也会慢慢变化,这是这类传感器的固有特性。 每次转向前重新读一次基准角,用差值而不是绝对值,就能把漂移的影响降到最低。
三、界面组件
| 组件 | 命名 | 关键属性 |
|---|---|---|
| 标签 | 标签_角度 |
字号 40,文本「0°」 |
| 按钮 | 按钮_归零 / 按钮_读角度 |
「角度归零」「读一次」 |
| 按钮 | 按钮_转90 |
文本「右转 90°」 |
| 按钮 | 按钮_走方形 |
文本「走一个正方形」 |
| 计时器 | 计时器1 |
计时器启用取消勾选、间隔 50 |
| EV3陀螺仪传感器 | EV3陀螺仪传感器1 |
BluetoothClient = 蓝牙客户端1、SensorPort = 2 |
| EV3马达 | EV3马达1 |
BluetoothClient = 蓝牙客户端1、MotorPorts = BC |
四、分步搭代码块
第 1 步:先看角度在不在动
when 按钮_归零.Click() {
EV3陀螺仪传感器1.SetAngleMode()
标签_角度.Text = "0°"
标签_状态.Text = "已归零"
}
when 按钮_读角度.Click() {
标签_角度.Text = join(EV3陀螺仪传感器1.GetSensorValue(), "°")
}
中途验证:点「归零」,然后用手把车转 90 度,点「读一次」应该显示 ±90 左右。
读数不变就别往下做 —— 检查 SensorPort 和 BluetoothClient。
顺时针是正还是负,取决于陀螺仪的安装方向。先转一下看符号。 本文的判断用了绝对值,正负都成立。
第 2 步:闭环转 90 度
global 目标角 = 90
global 起始角 = 0
when 按钮_转90.Click() {
EV3陀螺仪传感器1.SetAngleMode()
global 起始角 = EV3陀螺仪传感器1.GetSensorValue()
global 目标角 = 90
EV3马达1.RotateSyncIndefinitely(30, 100)
计时器1.TimerEnabled = true
标签_状态.Text = "转向中…"
}
when 计时器1.Timer() {
var 已转 = abs(EV3陀螺仪传感器1.GetSensorValue() - 起始角)
标签_角度.Text = join(round(已转), "°")
if 已转 >= 目标角 - 3 {
EV3马达1.Stop(true)
计时器1.TimerEnabled = false
标签_状态.Text = join("完成,实际转了 ", round(已转), "°")
}
}
中途验证:点「右转 90°」,车原地转四分之一圈后停下。用地砖缝对齐着看,误差应在几度内。
- 3是提前量:从发现”到了”到马达真正停下有延迟(蓝牙往返 + 机械惯性), 不提前一点会转过头。转速越快提前量要越大 —— 功率 30 时 3 度左右合适, 功率 50 就要提前 8~10 度。用
abs(当前 - 起始)而不是直接读绝对值:这样不管陀螺仪之前累计到多少、 也不管转向正负,逻辑都成立。
第 3 步:走一个正方形
global 边数 = 0
global 起始角 = 0
when 按钮_走方形.Click() {
global 边数 = 0
走一条边()
}
procedure 走一条边() {
EV3马达1.RotateSyncInDistance(40, 40, 0, true)
EV3陀螺仪传感器1.SetAngleMode()
global 起始角 = EV3陀螺仪传感器1.GetSensorValue()
EV3马达1.RotateSyncIndefinitely(30, 100)
计时器1.TimerEnabled = true
}
when 计时器1.Timer() {
var 已转 = abs(EV3陀螺仪传感器1.GetSensorValue() - 起始角)
标签_角度.Text = join(round(已转), "°")
if 已转 >= 87 {
EV3马达1.Stop(true)
计时器1.TimerEnabled = false
global 边数 = 边数 + 1
标签_状态.Text = join("已完成 ", 边数, " 条边")
if 边数 < 4 {
走一条边()
}
}
}
中途验证:车走出一个大致方正的正方形,最后回到出发点附近。
RotateSyncInDistance是阻塞式的:走完 40 厘米(该方法的距离单位是 cm)才继续往下执行, 所以直线段和转向段自然分开,不用自己加延时。回不到原点很正常 —— 轮子打滑、直线段本身有偏差,误差会累积。 这正是竞赛机器人要不断用传感器重新校正的原因,而不是一路盲走。
五、排错表
| 现象 | 原因与处理 |
|---|---|
| 角度读数一直是 0 | ① SensorPort 不对;② BluetoothClient 没设;③ 传感器线松 |
| 读到 -1 | 组件文档:读不到时返回 -1。检查接线,别让 -1 参与角度计算 |
| 静止时角度慢慢变 | 陀螺仪漂移,正常。每次转向前重新取基准角 |
| 每次转的角度都不一样 | 提前量没调好;或功率太高惯性大,降到 30 |
| 转过头很多 | 提前量太小,或计时器间隔太大(50 毫秒较合适) |
| 转不到位就停 | 提前量太大 |
| 走方形越走越歪 | 误差累积,正常。要闭合得靠外部参照(巡线、超声波测墙距) |
| 转向时车在原地画圈而不是转 | 转向比不是 100。原地转必须用 ±100 |
六、下一步
- 实验06:屏幕表情与音效 —— 让机器人有点性格
- 实验07:NXT 对照篇 —— 手上是上一代砖头的话看这篇
扫码添加客服咨询