0 / 8 页已完成

常见问题 + 练习FAQ + Practice

常见问题Frequently Asked Questions

理解原理后,比赛建议用成熟的库(LemLib、EZ-Template、JAR-Template 等)。但理解原理能帮你调参和排查问题。After understanding the principles, we recommend using mature libraries (LemLib, EZ-Template, JAR-Template, etc.) for competition. But understanding the theory helps you tune parameters and debug issues.

校准时机器人不能动。如果漂移严重,可以用两个竖轮的差来算角度(代替陀螺仪),但需要两个竖轮左右对称安装。The robot must be still during calibration. If drift is severe, you can use the difference between two vertical wheels to calculate angle (replacing the gyroscope), but this requires two vertical wheels installed symmetrically.

定位轮解决"我在哪",Pure Pursuit 解决"怎么沿曲线走"。Pure Pursuit 需要定位轮提供实时位置,然后计算应该往前方路径上哪个点开。像开车时眼睛看前方一段距离的路面,而不是盯着脚下。Tracking wheels solve "where am I," Pure Pursuit solves "how to follow a curve." Pure Pursuit needs real-time position from tracking wheels, then calculates which point ahead on the path to aim for. Like driving a car by looking at the road ahead, not at your feet.

Vehicle Path Tracking Using Pure Pursuit Controller
MATLAB · 11 分钟min · 英文English · Pure Pursuit 算法原理动画讲解Pure Pursuit algorithm animated explanation

5ms(每秒 200 次)是实践中比较好的值。太慢会丢精度,太快传感器跟不上也没意义。注意:不要在定位线程里做其他事(打印、复杂计算),会拖慢频率。5ms (200 times per second) works well in practice. Too slow loses accuracy; too fast is pointless if sensors can't keep up. Note: don't do other things in the tracking thread (printing, complex calculations) — they slow down the frequency.

这确实会造成微小误差(一个更新了另一个还没更新)。目前没有完美解决方案,但 5ms 的循环频率下这个误差很小,实践中可以接受。This does cause tiny errors (one updates while the other hasn't yet). There's no perfect solution, but at 5ms loop frequency this error is small and acceptable in practice.

这是累积误差 —— 每次循环的微小误差会叠加。2 分钟比赛后可能累积 5-10cm。常见缓解方法:This is accumulated error — tiny errors from each loop add up. After a 2-minute match, it might accumulate 5-10cm. Common ways to mitigate:

  • 墙面重置:让机器人靠到场地墙边,直接把对应坐标设为墙的已知位置Wall reset: drive the robot to a wall and set the corresponding coordinate to the wall's known position
  • 起始位置校准:每次自动阶段开始前,在代码里设好起始坐标Starting position calibration: set the starting coordinates in code before each autonomous period
  • 减少误差源:把安装做到极致(见安装指南)Reduce error sources: perfect the installation (see Installation Guide)

练习Practice

练习 1:理解坐标系(纸上练习)Exercise 1: Understanding Coordinates (Paper Exercise)

机器人在 (0, 0),车头朝 y 轴正方向(0°)。The robot is at (0, 0), facing the positive y-axis (0°).

  1. 直走 50cm,现在坐标是?Drive straight 50cm. What are the coordinates now?
  2. 右转 90°,再直走 30cm,现在坐标是?Turn right 90°, then drive straight 30cm. Coordinates?
  3. 左转 45°(现在朝向 45°),再直走 20cm,现在坐标大约是?Turn left 45° (now facing 45°), then drive straight 20cm. Approximate coordinates?
  1. (0, 50) —— 只沿 y 轴走了 50(0, 50) — only moved 50 along the y-axis
  2. (30, 50) —— 右转 90° 后车头朝 x+,直走 30cm 只增加 x(30, 50) — after turning right 90°, heading is x+, driving 30cm only increases x
  3. (30, 50) 出发,朝向 45°(东北方向),走 20cm:Starting from (30, 50), heading 45° (northeast), traveling 20cm:
    • Δx = 20 × sin(45°) = 20 × 0.707 ≈ 14.1
    • Δy = 20 × cos(45°) = 20 × 0.707 ≈ 14.1
    • 最终 ≈ (44.1, 64.1)Final ≈ (44.1, 64.1)

练习 2:补全代码Exercise 2: Complete the Code

下面的 updatePosition() 函数缺了关键部分,补全它:The updatePosition() function below is missing key parts. Fill them in:

C++
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;
}

提示:答案全在代码实现那一节的完整版代码里,但试着先自己想再对照。Hint: All answers are in the complete code from the Code Implementation section, but try to figure them out yourself first.

点击查看答案Click to see answers
  • (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:找 Bug(调试练习)Exercise 3: Find the Bug (Debugging Practice)

下面 4 段代码各有一个 Bug,找出来并说明会导致什么问题:Each of the 4 code snippets below has one bug. Find it and explain what problem it causes:

Bug 1:

C++
// 编码器角度转距离
double arc_v = (cur_v - last_v) * (WHEEL_DIAMETER_V / 2.0);
点击查看答案Click to see answer

缺少 DEG_TO_RAD。编码器返回的是角度(度),直接乘半径得到的不是弧长。正确写法:(cur_v - last_v) * DEG_TO_RAD * (WHEEL_DIAMETER_V / 2.0)。不修的话,算出的距离会偏大约 57 倍(因为 1 rad ≈ 57.3°)。Missing DEG_TO_RAD. The encoder returns degrees — multiplying directly by radius doesn't give arc length. Correct: (cur_v - last_v) * DEG_TO_RAD * (WHEEL_DIAMETER_V / 2.0). Without the fix, calculated distance is off by ~57x (since 1 rad ≈ 57.3°).

Bug 2:

C++
// 判断是否转弯
if (delta_angle == 0) {
    chord_v = arc_v;
} else {
    double radius_v = arc_v / delta_angle + OFFSET_V;
    chord_v = 2 * radius_v * sin(delta_angle / 2.0);
}
点击查看答案Click to see answer

用了 == 0 而不是阈值。陀螺仪有噪声,delta_angle 几乎不会精确等于 0,所以几乎每次都走 else 分支。当 delta_angle 极小(比如 0.00001)时,arc_v / delta_angle 算出天文数字,坐标直接飞走。正确写法:fabs(delta_angle) < 0.001Using == 0 instead of a threshold. The gyroscope has noise — delta_angle is almost never exactly 0, so the else branch runs almost every time. When delta_angle is tiny (e.g., 0.00001), arc_v / delta_angle gives an astronomical number and coordinates fly away. Correct: fabs(delta_angle) < 0.001.

Bug 3:

C++
void updatePosition() {
    double arc_v = (VerticalEncoder.position(deg) - last_vertical) * DEG_TO_RAD * (WHEEL_DIAMETER_V / 2.0);
    double angle = IMU.rotation(deg) * DEG_TO_RAD;
    double delta_angle = angle - last_angle;
    // ... 计算 chord_v, chord_h, 更新 pos_x, pos_y ...
    last_vertical = VerticalEncoder.position(deg);  // 注意这一行
    last_angle = angle;
}
点击查看答案Click to see answer

传感器读了两次。开头用 VerticalEncoder.position(deg) 算 arc_v,结尾又读了一次存到 last_vertical。两次读取之间传感器可能变了,导致下次循环的 arc_v 计算不准。正确做法:开头用局部变量存一次 double cur_v = VerticalEncoder.position(deg);,后面都用 cur_vSensor read twice. At the start, VerticalEncoder.position(deg) calculates arc_v; at the end, it's read again for last_vertical. The sensor may have changed between reads, causing inaccurate arc_v next loop. Correct approach: store in a local variable at the start: double cur_v = VerticalEncoder.position(deg); and use cur_v throughout.

Bug 4:

C++
// 偏移补正
double radius_v = arc_v / delta_angle + OFFSET_V;
// OFFSET_V = -4.0(竖轮在旋转中心左边 4cm)
// 但实际安装时竖轮在旋转中心右边
点击查看答案Click to see answer

偏移量符号错了。竖轮在旋转中心右边,OFFSET_V 应该是正数(+4.0),不是 -4.0。符号写反会导致补正方向相反——原地转圈时坐标不但不归零,反而偏得更远。检查方法:让机器人原地转 10 圈,看坐标是否回到 (0,0) 附近。Wrong offset sign. The vertical wheel is to the right of the rotation center, so OFFSET_V should be positive (+4.0), not -4.0. A wrong sign reverses the correction — spinning in place makes coordinates drift farther instead of returning to zero. Verify by spinning 10 rotations and checking if coordinates return near (0,0).

练习 4:调参挑战(实机练习)Exercise 4: Tuning Challenge (On-Robot Practice)

  1. 装好定位轮,运行定位程序Install tracking wheels and run the tracking program
  2. 让机器人手动控制走一个正方形(每边 60cm),回到起点Manually drive the robot in a square (60cm per side), back to the start
  3. 看程序报告的坐标离 (0, 0) 差多少Check how far the reported coordinates are from (0, 0)
  4. 目标:走完正方形后,x 和 y 误差都在 5cm 以内Goal: after completing the square, both x and y error should be within 5cm

练习 5:写你自己的 MoveTo(分三步)Exercise 5: Write Your Own MoveTo (Three Steps)

不要一口气写完整的 moveTo。按下面三步来,每步写完测试通过再进下一步:Don't try to write the complete moveTo all at once. Follow these three steps, testing each before moving on:

第一步:写 turnTo(targetAngle)Step 1: Write turnTo(targetAngle)

第二步:写 driveForward(distance)Step 2: Write driveForward(distance)

第三步:合并成 moveTo(x, y)Step 3: Combine into moveTo(x, y)

提示:每步都先在纸上画图 → 写伪代码 → 再写 C++。Tip: For each step, draw a diagram → write pseudocode → then write C++.

检查点Checkpoint
机器人在 (0,0),朝 90 度走 30cm,到哪?x 坐标是多少?The robot is at (0,0), moves 30cm at 90°. Where does it end up? What's the x coordinate?
°

参考资料References

文档资料(可下载)Documents (Downloadable)
视频教程Video Tutorials
在线资源Online Resources
核心收获Key Takeaway:定位轮让机器人从"凭感觉走"变成"看着地图走"。数学模型虽然看起来复杂,但核心就一句话 —— 每隔一小段时间,用传感器算出移动了多少,加到坐标上。剩下的都是让这个过程更准确的细节。: Tracking wheels transform the robot from "driving by feel" to "driving with a map." The math model may look complex, but the core is one sentence — every small time interval, use sensors to calculate movement and add it to the coordinates. Everything else is just details to make this process more accurate.