定位轮(Tracking Wheels)
标 必学 的是所有人必学,标 实战 的是实战进阶(比赛前再学也行),标 深入 的是深入理解(学有余力再看)
必学 为什么需要定位轮?
想象一下:自动阶段,你让机器人前进 100cm,但轮子打滑了,实际只走了 80cm。程序以为到位了,后面所有动作全部偏移。
核心问题:驱动轮会打滑,用驱动轮的编码器算距离不准。
解决方案:装几个不连接电机的小轮子(被动轮),它们只是贴在地上滚动,不会打滑。通过它们的编码器,我们可以精确知道机器人实际走了多远。
这就是定位轮(Tracking Wheels),也叫追踪轮、里程计轮。
必学 一、定位轮是什么?
硬件组成
一套定位轮系统通常包括:
┌─────────────────────────────┐
│ 机器人俯视图 │
│ │
│ ║ ↑ y正(前) ║ │ ← 驱动轮(左右各3个)
│ ║ ┃ ┃ ║ │
│ ║ ┃竖轮 ┃ ║ │ ← 竖轮:测量前后移动
│ ║ ┃(Vertical)┃ ║ │
│ ║ ║ │
│ ║ ━━━━━━━━━━━━━━━━ ║ │ ← 横轮:测量左右移动
│ ║ (Horizontal) ║ │
│ ║ → x正(右) │
│ ║ ║ │
│ [V5 大脑] │
└─────────────────────────────┘
| 部件 | 作用 | 数量 |
|---|---|---|
| 竖轮(Vertical) | 测量前后方向移动距离 | 1 个 |
| 横轮(Horizontal) | 测量左右方向移动距离 | 1 个 |
| 陀螺仪(IMU) | 测量旋转角度 | 1 个 |
| 旋转传感器(Rotation Sensor) | 装在定位轮上,读取旋转角度 | 2 个 |
坐标系约定
在开始之前,必须先统一"方向"的定义,否则后面的公式正负号会乱:
| 约定 | 定义 |
|---|---|
| x 正方向 | 机器人的右边 |
| y 正方向 | 机器人的前方(车头方向) |
| θ 正方向 | 顺时针旋转 |
| 竖轮正方向 | 向前滚 = 正值 |
| 横轮正方向 | 向右滚 = 正值 |
重要:如果你的轮子装反了(向前滚读出负值),在代码里把编码器值取反,或者在传感器设置里 reverse。不要去改公式的正负号。
为什么需要两个轮 + 陀螺仪?
- 竖轮:知道机器人沿车头方向走了多远
- 横轮:知道机器人侧向滑了多远(被撞、万向轮漂移等)
- 陀螺仪:知道机器人转了多少度
三个信息结合,就能算出机器人在场地上的精确坐标 (x, y, θ)。
就像 GPS 告诉你在地图上的位置一样,定位轮告诉机器人在场地上的位置。
必学 二、数学模型(核心思想)
2.1 基本想法
我们要做的事情很简单:
- 每隔很短的时间(5 毫秒),读一次传感器
- 算出这段时间里机器人移动了多少
- 把移动量加到之前的位置上
反复执行这个过程,就能一直知道机器人在哪里。
2.2 直线情况(简单)
如果机器人走直线,没有转弯:
前 (y+)
↑
| 竖轮走了 Δv
|
← ──┼── → (x+)
横轮走了 Δh
Δx = Δh(横向移动 = 横轮走的距离)Δy = Δv(纵向移动 = 竖轮走的距离)
这很直觉。但机器人大部分时间不是走直线,而是在转弯。
2.3 从直线到弧线的过渡
想象一下:机器人不是走完美直线,而是一边走一边微微右转。
- 如果转了 0.1 度 —— 几乎是直线,Δv 和 Δh 直接当位移用也差不多
- 如果转了 5 度 —— 有点弯了,直接用 Δv 当 y 位移就不太准了
- 如果转了 90 度 —— 明显是弧线,必须用更精确的方法
弧线越弯,弧长和位移的差距越大。所以我们需要一个方法,把弧长转换成位移。
深入 2.4 转弯情况(圆弧模型)
关键假设:在很短的时间内,机器人的运动轨迹可以看作一段圆弧。
为什么?因为两边电机功率不同,机器人会绕一个点画弧线。时间越短,这个假设越准确。
B (新位置)
╱
╱ 弦长(我们要求的位移)
╱
A (旧位置)
\
\ 半径 R
\
O (圆心)
角度变化 = Δθ(陀螺仪告诉我们的)
弧长 = 定位轮走的距离
推导过程(不需要背,理解思路就好):
- 陀螺仪告诉我们角度变了
Δθ - 竖轮告诉我们走了弧长
弧长v - 圆弧公式:弧长 = 半径 × 角度,所以
半径 = 弧长v ÷ Δθ - 弦长公式(几何):
弦长 = 2 × 半径 × sin(Δθ/2) - 弦长就是实际位移,再分解到 x 和 y 方向
第 5 步为什么要"分解"? 因为机器人是斜着走的(一边前进一边转弯),位移不是纯 x 或纯 y 方向,需要用三角函数拆成两个分量。用的角度是这段时间的平均朝向 θ旧 + Δθ/2(起点和终点的中间值)。
Δy = 弦长v × cos(平均角度) - 弦长h × sin(平均角度)
为什么是 sin 和 cos 这样搭配? 这其实是"旋转矩阵" —— 把机器人视角的前后左右,转换成场地视角的 x 和 y。车头朝前(y+方向)时,前进 = y 增加,所以竖轮对 y 的贡献用 cos(cos(0)=1);前进不改变 x,所以竖轮对 x 的贡献用 sin(sin(0)=0)。转了角度之后,cos 和 sin 的值随之变化,自动完成了坐标转换。
实战 2.5 偏移补正
理想情况下,竖轮应该装在机器人的旋转中心上。但实际上很难做到,轮子往往偏了一点。
偏移会导致:机器人原地转圈时,定位轮也会走一段弧,程序误以为机器人移动了。
补正方法:在计算半径时,加上定位轮到旋转中心的偏移距离。
这个偏移距离需要量出来(后面会讲怎么测量)。
必学 三、代码实现
3.1 准备工作:常量定义
// 定位轮参数
#define WHEEL_DIAMETER_V 5.08 // 竖轮直径(cm),2 英寸全向轮
#define WHEEL_DIAMETER_H 5.08 // 横轮直径(cm)
#define OFFSET_V 4.0 // 竖轮到旋转中心的水平偏移(cm)
#define OFFSET_H 10.0 // 横轮到旋转中心的纵向偏移(cm)
// 角度转弧度
#define DEG_TO_RAD (M_PI / 180.0)
// 极小角度阈值(小于这个值视为直线)
#define ANGLE_THRESHOLD 0.001 // 约 0.06 度
为什么用弧度? 三角函数sin()和cos()要求输入弧度,不是角度。
弧度 = 角度 × π ÷ 180
3.2 先看极简版(只处理直线)
如果机器人只走直线不转弯,定位代码只需要 5 行:
// 极简版:假设不转弯
void updatePosition_simple() {
double delta_v = (VerticalEncoder.position(deg) - last_vertical)
* DEG_TO_RAD * (WHEEL_DIAMETER_V / 2.0);
double delta_h = (HorizontalEncoder.position(deg) - last_horizontal)
* DEG_TO_RAD * (WHEEL_DIAMETER_H / 2.0);
double angle = IMU.rotation(deg) * DEG_TO_RAD;
// 直接用当前角度做坐标旋转
pos_x += delta_v * sin(angle) + delta_h * cos(angle);
pos_y += delta_v * cos(angle) - delta_h * sin(angle);
last_vertical = VerticalEncoder.position(deg);
last_horizontal = HorizontalEncoder.position(deg);
}
这个版本在机器人走直线时完全正确,转弯时有误差但也能用。很多队伍一开始就用这个版本。
3.3 完整版:加上圆弧修正
在极简版基础上,加上转弯时的圆弧修正(新增部分用 // ★ 标注):
void updatePosition() {
// === 第一步:一次性读取所有传感器(保证数据一致性) ===
double cur_vertical = VerticalEncoder.position(deg); // ★ 局部变量
double cur_horizontal = HorizontalEncoder.position(deg); // ★ 局部变量
double angle = IMU.rotation(deg) * DEG_TO_RAD;
// 编码器角度转成轮子走过的距离(弧长)
double arc_v = (cur_vertical - last_vertical)
* DEG_TO_RAD * (WHEEL_DIAMETER_V / 2.0);
double arc_h = (cur_horizontal - last_horizontal)
* DEG_TO_RAD * (WHEEL_DIAMETER_H / 2.0);
// 陀螺仪角度变化
double delta_angle = angle - last_angle;
// === 第二步:算弦长(实际位移) ===
double chord_v, chord_h;
if (fabs(delta_angle) < ANGLE_THRESHOLD) { // ★ 用阈值,不用 == 0
// 几乎没转弯,弧长 ≈ 弦长
chord_v = arc_v;
chord_h = arc_h;
} else {
// 有转弯,用圆弧模型
double radius_v = arc_v / delta_angle + OFFSET_V; // ★ 补正偏移
double radius_h = arc_h / delta_angle + OFFSET_H; // ★ 补正偏移
chord_v = 2 * radius_v * sin(delta_angle / 2.0);
chord_h = 2 * radius_h * sin(delta_angle / 2.0);
}
// === 第三步:转换到全局坐标 ===
double avg_angle = last_angle + delta_angle / 2.0; // ★ 平均角度
pos_x += chord_v * sin(avg_angle) + chord_h * cos(avg_angle);
pos_y += chord_v * cos(avg_angle) - chord_h * sin(avg_angle);
// === 第四步:保存本次值,给下次循环用 ===
last_vertical = cur_vertical; // ★ 用局部变量
last_horizontal = cur_horizontal; // ★ 用局部变量
last_angle = angle;
}
对比极简版,完整版多了什么?
| 改进 | 作用 | 不加会怎样 |
|---|---|---|
| 传感器一次性读取到局部变量 | 保证计算和保存用的是同一组数据 | 偶尔数据不一致 |
fabs(delta_angle) < 阈值 | 避免除以接近零的数 | 半径算出天文数字,坐标飞走 |
| 圆弧弦长计算 | 转弯时更精确 | 走弧线误差大 |
| 偏移补正 | 消除轮子不在旋转中心的影响 | 原地转圈坐标会漂移 |
| 平均角度 | 用中间时刻的角度更准 | 走弧线时 x/y 分配有偏差 |
3.4 后台线程:持续更新
定位系统需要在后台不停地跑,不能被其他代码打断:
int trackingTask() {
while (true) {
updatePosition();
task::delay(5); // 每 5ms 更新一次(一秒 200 次)
}
return 0;
}
在 main() 里启动它:
// VEXcode 写法
task tracking = task(trackingTask);
// PROS 写法(如果你用 PROS)
// pros::Task tracking(trackingTask);
3.5 逐行解读
为什么编码器值要乘 DEG_TO_RAD * (直径/2)?
编码器返回角度(度) → 乘 π/180 → 角度(弧度)
弧度 × 半径 = 弧长(距离)
为什么不能用 delta_angle == 0?
因为陀螺仪总有微小噪声,返回值可能是 0.00003 而不是精确的 0。用 == 0 判断几乎永远为 false,导致每次都走圆弧分支 —— 当 delta_angle 极小时,arc_v / delta_angle 会算出一个巨大的半径,坐标直接飞走。用阈值 fabs(delta_angle) < 0.001 就安全了。
为什么用 sin(avg_angle) 和 cos(avg_angle)?
这是坐标旋转。定位轮测到的是机器人自己视角的前后左右,我们需要转换成场地视角的 x 和 y。用平均角度做旋转最准。
必学 四、定位轮安装指南
安装质量直接决定定位精度。
4.1 位置
| 要求 | 原因 |
|---|---|
| 竖轮尽量在旋转中心的纵线上 | 减少原地转圈时的误差 |
| 横轮尽量在旋转中心的横线上 | 同上 |
| 离旋转中心越近越好 | 偏移越大,补正误差越大 |
旋转中心在哪? 一般在底盘的几何中心附近。可以让机器人原地旋转,看哪个点不动,那就是旋转中心。
4.2 机械要求
| 要求 | 原因 | 不达标的后果 |
|---|---|---|
| 轮子必须完全平行/垂直于底盘 | 哪怕偏 2 度,走远了误差很大 | 走 3 米偏 10cm+ |
| 左右晃动极小(掰不动的程度) | 晃动 = 每次读数方向不一致 | 误差快速积累 |
| 轮子始终贴地 | 离地就读不到数据 | 定位直接失效 |
| 用皮筋或弹簧向下压 | 保证过颠簸时不离地 | 弹起瞬间数据丢失 |
| 旋转阻力越小越好 | 阻力大 = 轮子跟不上机器人 | 读数滞后 |
| 皮筋力方向竖直向下 | 斜着拉会给轮子施加扭矩 | 轮子被拉歪 |
怎么检查轮子是否平行? 把机器人放在场地上,手推着它走一条直线(3米),看竖轮读数是否一直增长(不应该有来回跳动)。如果跳动,说明轮子歪了或者有晃动。
4.3 最常见的错误
轮子歪了 2-3 度,以为没影响
→ 走一圈回来坐标偏了 20cm
轮子没压紧,过坎时弹起来
→ 弹起的瞬间数据丢失,位置跳变
在定位线程里打印数据到遥控器屏幕
→ 打印很慢,拖慢刷新频率(从 200Hz 降到 50Hz),精度下降
编码器接线松动
→ 偶尔读到 0,坐标瞬间飘走
横轮装反了(向右滚读出负值)
→ x 坐标方向反了,机器人以为自己在镜像位置
→ 解决:传感器设置里 reverse,或代码里取反
实战 4.4 偏移距离怎么测?
测量定位轮到旋转中心的距离:
- 设定初始位置
(0, 0),先把偏移距离设为0 - 让机器人原地顺时针转 10 圈
- 看程序报告的
(x, y)—— 理论上应该还是(0, 0) - 如果 x 偏了,调整竖轮偏移(OFFSET_V);如果 y 偏了,调整横轮偏移(OFFSET_H)
- 反复调整直到转 10 圈后坐标几乎不变(x, y 都在 2cm 以内)
偏移值有正负:轮子在旋转中心右边就是正,左边就是负。可以先量个大概值,再用上面的方法微调。
实战 五、和 LemLib 的关系
上面的代码是从头写的,帮助理解原理。实际比赛中,很多队伍用 LemLib 库,它帮你封装好了定位系统。
LemLib 的核心逻辑和我们写的基于同一个数学模型(圆弧近似),但实现细节有差异:
// LemLib 的核心算法(简化版)
localX = 2 * sin(deltaHeading / 2) * (deltaX / deltaHeading + horizontalOffset);
localY = 2 * sin(deltaHeading / 2) * (deltaY / deltaHeading + verticalOffset);
// 转换到全局坐标
odomPose.x += localY * sin(avgHeading) + localX * (-cos(avgHeading));
odomPose.y += localY * cos(avgHeading) + localX * sin(avgHeading);
-cos 和 +sin,我们的代码用的是 +cos 和 -sin。这不是谁写错了 —— 而是横轮正方向的约定不同。LemLib 定义横轮"向左为正",我们定义"向右为正",所以符号自然相反。
核心公式是一样的: 弦长 = 2R sin(Δθ/2),R = 弧长/Δθ + 偏移。区别只在坐标轴方向的约定。
LemLib 额外提供的功能:
- 支持多个竖轮/横轮(冗余提高精度)
- 自动选择最佳的角度来源(优先用追踪轮算角度,其次陀螺仪,最后电机编码器)
- 速度平滑滤波(EMA 指数移动平均)
建议:先用自己写的代码理解原理,比赛时再切换到 LemLib 享受它的额外功能。遇到定位不准时,你知道该查什么。
实战 六、用定位数据做什么? —— MoveTo 函数
知道了 (x, y, θ),最直接的应用是:让机器人自动走到指定坐标。
6.1 思路
把底盘功率拆成两部分:
右轮功率 = 直行功率 - 转弯功率
- 直行功率:由"离目标还有多远"决定(PID 控制)
- 转弯功率:由"车头方向和目标方向差多少"决定(PID 控制)
T (目标点)
╱|
╱ |
╱ | Δy
╱ |
O ─────────┘
(当前位置) Δx
α = atan2(Δx, Δy) ← 目标方向
误差角度 = α - 当前角度 ← 车头偏了多少
距离 = √(Δx² + Δy²) ← 还有多远
6.2 简化代码
// 角度归一化到 [-180, 180]
double normalizeAngle(double angle) {
while (angle > 180) angle -= 360;
while (angle < -180) angle += 360;
return angle;
}
void moveTo(double target_x, double target_y, int timeout_ms) {
timer t;
while (t.time(msec) < timeout_ms) {
// 当前位置(从定位系统读取)
double cur_x = pos_x;
double cur_y = pos_y;
double cur_angle = IMU.rotation(deg);
// 计算误差
double err_x = target_x - cur_x;
double err_y = target_y - cur_y;
double distance = sqrt(err_x * err_x + err_y * err_y);
// 目标方向角度(度)
double target_angle = atan2(err_x, err_y) / DEG_TO_RAD;
// 角度误差,归一化防止转大圈
double angle_error = normalizeAngle(target_angle - cur_angle);
// 投影距离(沿车头方向还要走多远)
double forward_error = distance * cos(angle_error * DEG_TO_RAD);
// PID 计算功率(这里简化为 P 控制)
double power_linear = forward_error * 2.0; // kP = 2.0
double power_turn = angle_error * 1.5; // kP = 1.5
// 限幅
if (fabs(power_linear) > 100)
power_linear = (power_linear > 0) ? 100 : -100;
if (fabs(power_turn) > 100)
power_turn = (power_turn > 0) ? 100 : -100;
// 快到了就停止转弯(防止结尾抖动)
if (distance < 10) power_turn = 0;
// 分配给左右轮
double left = power_linear + power_turn;
double right = power_linear - power_turn;
// 等比缩放,防止超过 100
double max_power = fmax(fabs(left), fabs(right));
if (max_power > 100) {
left = left / max_power * 100;
right = right / max_power * 100;
}
moveLeft(left);
moveRight(right);
// 到达退出
if (distance < 3) break;
task::delay(10);
}
// 停下
moveLeft(0);
moveRight(0);
}
为什么需要 normalizeAngle? 假如机器人转了 350°,陀螺仪读数 350,目标方向 10°。不归一化的话 10 - 350 = -340,机器人会傻傻地转 340 度大圈。归一化后变成 +20,只转 20 度小圈。
6.3 使用方式
void autonomous() {
// 机器人从 (0, 0) 出发
moveTo(60, 0, 3000); // 往右走 60cm,3 秒超时
moveTo(60, 60, 3000); // 再往前走 60cm
moveTo(0, 0, 5000); // 回到起点
}
对比以前用 TimerForward(127, 1000) 凭时间走路 —— 现在是告诉机器人"去这个坐标",它自己算怎么走。精确度和灵活性完全不是一个量级。
深入 6.4 实战细节
上面的 moveTo 是最简版,实际使用中还需要注意几个问题:
功率比例问题:直行功率 400 + 转弯功率 300,如果直接加起来就是 700,但电机最大 100。不做等比缩放的话,(100, 100) 变成直走,转弯完全丢失。代码里的等比缩放就是解决这个问题。
起步时强制转弯:刚开始时距离很远,直行功率很大,容易把转弯功率盖过去。可以在距离远的时候给转弯功率一个最低值:
if (distance > 10 && fabs(power_turn) < 60) {
power_turn = (power_turn > 0) ? 60 : -60;
}
收尾时停止转弯:快到目标时 Δx 和 Δy 都很小,任何微小变化都会导致目标方向剧烈跳动,机器人会原地左右摇摆。所以接近目标时直接把转弯功率清零。
功率平滑(Slew Rate):功率突变会让机器人抖动,限制每次循环最大功率变化:
// 每次循环功率变化不超过 10
float slew(float current, float last, float max_change) {
float change = current - last;
if (change > max_change) change = max_change;
if (change < -max_change) change = -max_change;
return last + change;
}
必学 七、常见问题
理解原理后,比赛建议用成熟的库(LemLib、EZ-Template、JAR-Template 等)。但理解原理能帮你调参和排查问题。
校准时机器人不能动。如果漂移严重,可以用两个竖轮的差来算角度(代替陀螺仪),但需要两个竖轮左右对称安装。
定位轮解决"我在哪",Pure Pursuit 解决"怎么沿曲线走"。Pure Pursuit 需要定位轮提供实时位置,然后计算应该往前方路径上哪个点开。像开车时眼睛看前方一段距离的路面,而不是盯着脚下。
5ms(每秒 200 次)是实践中比较好的值。太慢会丢精度,太快传感器跟不上也没意义。注意:不要在定位线程里做其他事(打印、复杂计算),会拖慢频率。
这确实会造成微小误差(一个更新了另一个还没更新)。目前没有完美解决方案,但 5ms 的循环频率下这个误差很小,实践中可以接受。
这是累积误差 —— 每次循环的微小误差会叠加。2 分钟比赛后可能累积 5-10cm。常见缓解方法:
- 墙面重置:让机器人靠到场地墙边,直接把对应坐标设为墙的已知位置
- 起始位置校准:每次自动阶段开始前,在代码里设好起始坐标
- 减少误差源:把安装做到极致(见第四节)
必学 八、练习
练习 1:理解坐标系(纸上练习)
机器人在 (0, 0),车头朝 y 轴正方向(0°)。
- 直走 50cm,现在坐标是?
- 右转 90°,再直走 30cm,现在坐标是?
- 左转 45°(现在朝向 45°),再直走 20cm,现在坐标大约是?
(0, 50)—— 只沿 y 轴走了 50(30, 50)—— 右转 90° 后车头朝 x+,直走 30cm 只增加 x- 从
(30, 50)出发,朝向 45°(东北方向),走 20cm:- Δx = 20 × sin(45°) = 20 × 0.707 ≈ 14.1
- Δy = 20 × cos(45°) = 20 × 0.707 ≈ 14.1
- 最终 ≈
(44.1, 64.1)
练习 2:补全代码
下面的 updatePosition() 函数缺了关键部分,补全它:
void updatePosition() {
double cur_v = VerticalEncoder.position(deg);
double cur_h = HorizontalEncoder.position(deg);
double arc_v = (cur_v - last_vertical)
* DEG_TO_RAD * (WHEEL_DIAMETER_V / 2.0);
double arc_h = /* (A) */;
double angle = IMU.rotation(deg) * DEG_TO_RAD;
double delta_angle = /* (B) */;
double chord_v, chord_h;
if (/* (C) */) {
chord_v = /* (D) */;
chord_h = /* (E) */;
} else {
double radius_v = /* (F) */;
double radius_h = /* (G) */;
chord_v = 2 * radius_v * sin(delta_angle / 2.0);
chord_h = 2 * radius_h * sin(delta_angle / 2.0);
}
double avg_angle = /* (H) */;
pos_x += /* (I) */;
pos_y += /* (J) */;
last_vertical = cur_v;
last_horizontal = cur_h;
last_angle = angle;
}
提示:答案全在第三节的完整版代码里,但试着先自己想再对照。
点击查看答案
- (A)
(cur_h - last_horizontal) * DEG_TO_RAD * (WHEEL_DIAMETER_H / 2.0) - (B)
angle - last_angle - (C)
fabs(delta_angle) < ANGLE_THRESHOLD - (D)
arc_v - (E)
arc_h - (F)
arc_v / delta_angle + OFFSET_V - (G)
arc_h / delta_angle + OFFSET_H - (H)
last_angle + delta_angle / 2.0 - (I)
chord_v * sin(avg_angle) + chord_h * cos(avg_angle) - (J)
chord_v * cos(avg_angle) - chord_h * sin(avg_angle)
练习 3:调参挑战(实机练习)
- 装好定位轮,运行定位程序
- 让机器人手动控制走一个正方形(每边 60cm),回到起点
- 看程序报告的坐标离
(0, 0)差多少 - 目标:走完正方形后,x 和 y 误差都在 5cm 以内
深入 练习 4:写你自己的 MoveTo
基于第六节的思路,写一个 moveTo 函数,要求:
- 能从任意位置走到目标坐标
- 有超时退出
- 有到达退出(距离 < 5cm)
- 加入 slew rate 限制(每次循环功率变化不超过 10)
提示:先在纸上画出机器人当前位置、目标位置、需要算哪些东西,再写代码。
参考资料
- PDFEN Team 5225 — Introduction to Position Tracking — 定位轮技术的起源论文(2018),本课件的核心参考
- PDFEN Two Wheel Odom Theory — 双轮定位的完整数学推导
- PDFEN Pure Pursuit Path Tracking Algorithm — Carnegie Mellon 经典路径跟踪论文
- PDFCN PID 控制经典培训教程 — 中文 PID 原理讲解
- VideoEN Essence of Robot Odometry Pt. 1 — Rex Liu · 什么是 Odometry(6 分钟)
- VideoEN Essence of Robot Odometry Pt. 2 — Rex Liu · Odometry 数学推导(11 分钟)
- VideoEN VEX Auton Tutorial — Tracking Wheels — EthanMik · 定位轮硬件+安装(11 分钟)
- VideoEN VEX Auton Tutorial — Setting Up Odometry — EthanMik · 配置和校准(13 分钟)
- VideoEN VEX Auton Tutorial — Tuning PID — EthanMik · PID 调参实操(16 分钟)
- VideoEN VEX Auton Tutorial — Writing Autonomous — EthanMik · 写自动程序(23 分钟)
- VideoEN How to Set Up LemLib + PROS — BennyBuildsRobots · LemLib 完整配置(19 分钟)
- VideoEN VEX Robotics PID Control: An Introduction — Seaquam Robotics · PID 入门(15 分钟)
- VideoEN Pure Pursuit Controller — MATLAB · 路径跟踪算法讲解(11 分钟)
- EN Purdue SIGBots Wiki — Odometry — 定位轮原理百科
- EN LemLib 源码 (GitHub) — 成熟的定位+运动控制库
- EN LemLib 文档 — 官方使用教程
- CN Team 18422B 定位轮分享 — 中文实战经验