Skip to content

Công nghệ 9 giây

“Website hướng dẫn, thử nghiệm và giải thích công nghệ theo cách dễ hiểu cho mọi người.”

Menu
  • Home
  • Công nghệ
  • STM32
  • ESP32
  • Altium Desinger
  • Kiến thức điện máy
Menu

BÀI 53 – ODOMETRY NÂNG CAO: TÍNH X, Y, θ CHO ROBOT 2 BÁNH + ĐIỀU KHIỂN ROBOT ĐẾN MỘT TỌA ĐỘ

Posted on August 23, 2026August 23, 2026 by congnghe9s

BÀI 53 – ODOMETRY NÂNG CAO: TÍNH X, Y, θ VÀ ĐIỀU KHIỂN ROBOT ĐẾN MỘT TỌA ĐỘ

Ở Bài 52, chúng ta đã làm được điều rất quan trọng:

Encoder trái + Encoder phải
             ↓
       Quãng đường bánh
             ↓
          Δθ
             ↓
        X, Y, θ

Nhưng robot mới chỉ biết mình đang ở đâu.

Bài 53 sẽ tiến thêm một bước:

Robot biết vị trí hiện tại và tự chạy đến tọa độ mà chúng ta yêu cầu.

Ví dụ:

Robot_GoTo(1000, 500);

nghĩa là:

Hãy đi đến điểm (X = 1000 mm, Y = 500 mm).


1. Bức tranh tổng thể

Ta sẽ xây dựng hệ thống:

                 TARGET
              X = 1000 mm
              Y = 500 mm
                   │
                   ▼
          ┌─────────────────┐
          │ POSITION        │
          │ CONTROLLER      │
          └────────┬────────┘
                   │
          ┌────────┴────────┐
          ▼                 ▼
     Target Distance   Target Heading
          │                 │
          └────────┬────────┘
                   ▼
             MOTION CONTROL
                   │
          ┌────────┴────────┐
          ▼                 ▼
       LEFT RPM          RIGHT RPM
          │                 │
          ▼                 ▼
       PID LEFT          PID RIGHT
          │                 │
          ▼                 ▼
       PWM LEFT          PWM RIGHT
          │                 │
          ▼                 ▼
       MOTOR LEFT        MOTOR RIGHT
          │                 │
          ▼                 ▼
      ENCODER LEFT      ENCODER RIGHT
          └────────┬────────┘
                   ▼
              ODOMETRY
              X, Y, θ
                   │
                   └──────► feedback

Đây chính là cấu trúc cơ bản của một robot differential-drive có điều khiển vị trí.


2. Robot phải biết 3 thứ

Ta gọi trạng thái robot:

typedef struct
{
    float x;
    float y;
    float theta;

} Pose_t;

Trong đó:

x     → tọa độ X
y     → tọa độ Y
theta → hướng robot

Ví dụ:

X = 500 mm
Y = 300 mm
θ = 90°

có nghĩa robot đang ở:

          Y
          ↑
          │       ROBOT ↑
          │
          │
          └────────────────→ X

vị trí:

(500, 300)

và đang hướng lên.


3. Hệ tọa độ

Ta thống nhất:

                 +Y
                  ↑
                  │
                  │
                  │
        -X ◄──────┼──────► +X
                  │
                  │
                  │
                  ↓
                 -Y

Góc:

θ = 0°

robot hướng:

→

và:

θ = +90°

robot hướng:

↑

4. Tại sao phải dùng X, Y, θ?

Ở Bài 51 ta có:

Move 1000 mm

Ở Bài 52:

Turn 90°

Nhưng bây giờ ta có thể nói:

GoTo(1000, 500)

Robot không cần biết trước phải:

đi 700 mm
quay 30°
đi 400 mm
...

Controller tự tính.


5. Tính vị trí bằng encoder

Ta quay lại công thức differential drive.

Gọi:

ΔL = quãng đường bánh trái
ΔR = quãng đường bánh phải

Khoảng cách hai bánh:

W = Wheel Base

Ta có:

[
\Delta S=\frac{\Delta L+\Delta R}{2}
]

và:

[
\Delta\theta=\frac{\Delta L-\Delta R}{W}
]

Đây là hai công thức cốt lõi của odometry.


6. Cập nhật X, Y

Nếu robot đang có góc:

θ

thì:

[
\Delta X=\Delta S\cos(\theta)
]

[
\Delta Y=\Delta S\sin(\theta)
]

Sau đó:

X = X + ΔX
Y = Y + ΔY
θ = θ + Δθ

Đây là cách đơn giản nhất để hiểu odometry.


7. Nhưng có một cải tiến quan trọng

Trong Bài 52, chúng ta dùng:

cos(theta)
sin(theta)

với theta hiện tại.

Khi robot vừa đi vừa quay, chính xác hơn là dùng góc trung bình trong bước đó:

[
\theta_{mid}

\theta+\frac{\Delta\theta}{2}
]

Sau đó:

[
\Delta X=
\Delta S\cos(\theta_{mid})
]

[
\Delta Y=
\Delta S\sin(\theta_{mid})
]

Đây là cải tiến rất đáng dùng trong Bài 53.


8. Tại sao phải dùng góc giữa?

Giả sử trong một chu kỳ:

θ đầu = 20°
θ cuối = 30°

Robot không chạy toàn bộ quãng đường ở:

20°

mà nó liên tục quay:

20 → 21 → 22 → ... → 30°

Góc trung bình:

25°

sẽ đại diện tốt hơn.


9. Hàm Odometry_Update nâng cao

void Odometry_Update(void)
{
    int32_t left_now;
    int32_t right_now;

    int32_t delta_left;
    int32_t delta_right;

    float left_mm;
    float right_mm;

    float delta_s;
    float delta_theta;
    float theta_mid;

    left_now =
        left_encoder.position;

    right_now =
        right_encoder.position;

    delta_left =
        left_now -
        odom.last_left;

    delta_right =
        right_now -
        odom.last_right;

    odom.last_left = left_now;
    odom.last_right = right_now;

    left_mm =
        (float)delta_left /
        LEFT_COUNTS_PER_MM;

    right_mm =
        (float)delta_right /
        RIGHT_COUNTS_PER_MM;

    delta_s =
        (left_mm + right_mm)
        / 2.0f;

    delta_theta =
        (left_mm - right_mm)
        / WHEEL_BASE_MM;

    theta_mid =
        odom.theta +
        delta_theta / 2.0f;

    odom.x +=
        delta_s * cosf(theta_mid);

    odom.y +=
        delta_s * sinf(theta_mid);

    odom.theta +=
        delta_theta;
}

Đây là một phiên bản odometry tốt hơn phiên bản ở Bài 52.


10. Chuẩn hóa góc

Sau nhiều vòng quay:

θ = 370°

hoặc:

θ = -450°

không có gì sai về mặt toán học, nhưng điều khiển sẽ dễ hơn nếu chuẩn hóa.

Ta có:

float NormalizeAngleRad(float angle)
{
    while (angle > M_PI)
        angle -= 2.0f * M_PI;

    while (angle < -M_PI)
        angle += 2.0f * M_PI;

    return angle;
}

Sau:

odom.theta =
    NormalizeAngleRad(odom.theta);

ta giữ:

-180° ≤ θ ≤ +180°

11. Tọa độ hiện tại

Ta có thể viết:

Pose_t Robot_GetPose(void)
{
    return odom.pose;
}

hoặc đơn giản:

float Robot_GetX(void)
{
    return odom.x;
}

float Robot_GetY(void)
{
    return odom.y;
}

float Robot_GetTheta(void)
{
    return odom.theta;
}

12. Bây giờ đến phần quan trọng nhất: GoTo

Giả sử:

Robot hiện tại:

X = 200
Y = 100
θ = 0°

Mục tiêu:

X = 1000
Y = 500

Ta cần tính:

ΔX = 1000 - 200 = 800
ΔY = 500 - 100 = 400

13. Khoảng cách đến mục tiêu

Dùng định lý Pythagore:

[
d=\sqrt{\Delta X^2+\Delta Y^2}
]

Trong ví dụ:

[
d=\sqrt{800^2+400^2}
]

≈

894.4 mm

Trong C:

distance =
    sqrtf(dx * dx +
          dy * dy);

14. Robot cần quay về hướng nào?

Ta cần tính góc của vector:

(dx, dy)

Công thức:

target_heading =
    atan2f(dy, dx);

Đây là một hàm cực kỳ quan trọng trong robotics.


15. atan2f() là gì?

Nếu:

dx = 800
dy = 400

thì:

atan2f(400, 800)

≈

26.565°

Nghĩa là robot phải hướng khoảng:

26.6°

để chạy thẳng về điểm đích.


16. Đây là lúc atan2() trở thành vũ khí quan trọng

Trong robotics bạn sẽ gặp rất nhiều:

atan2f(y, x)

Nó giúp tính:

Vector này đang hướng theo góc bao nhiêu?

Ví dụ:

             TARGET
               ●
              /
             /
            /
ROBOT ●────→

Vector:

(dx, dy)

và:

angle = atan2(dy, dx)

17. Tính sai số góc

Ta có:

target_heading

và:

odom.theta

Do đó:

heading_error =
    target_heading -
    odom.theta;

Nhưng phải normalize:

heading_error =
    NormalizeAngleRad(
        heading_error);

18. Ví dụ

Robot:

θ = 0°

Target heading:

26.6°

thì:

heading error = +26.6°

Robot phải quay trái.


19. Nếu robot đang quay 170°

và target:

-170°

tính bình thường:

-170 - 170
=
-340°

nhưng robot thực tế chỉ cần:

+20°

Đây chính là lý do:

NormalizeAngleRad()

cực kỳ quan trọng.


20. Điều khiển góc

Ta tạo:

#define GO_TO_ANGLE_KP 2.0f

và:

turn_command =
    GO_TO_ANGLE_KP *
    heading_error;

Sau đó giới hạn:

turn_command =
    Clamp(
        turn_command,
        -MAX_TURN_SPEED,
        MAX_TURN_SPEED);

21. Bây giờ có hai thành phần điều khiển

Robot cần:

Thành phần tiến

distance_error

và:

Thành phần quay

heading_error

Ta có:

Distance → Forward Speed
Angle    → Turn Speed

Đây là một ý tưởng rất quan trọng.


22. Position Controller

Ví dụ:

forward_speed =
    GO_TO_DISTANCE_KP *
    distance;

Giới hạn:

forward_speed =
    Clamp(
        forward_speed,
        0,
        MAX_FORWARD_SPEED);

23. Turn Controller

turn_speed =
    GO_TO_ANGLE_KP *
    heading_error;

Giới hạn:

turn_speed =
    Clamp(
        turn_speed,
        -MAX_TURN_SPEED,
        MAX_TURN_SPEED);

24. Từ Forward + Turn → hai bánh

Đây là một công thức cực kỳ quan trọng.

Ta có:

V = tốc độ tiến
ω = tốc độ quay

Hai bánh:

[
V_L=V-\omega\frac{W}{2}
]

[
V_R=V+\omega\frac{W}{2}
]

Đây chính là inverse kinematics của differential-drive robot.


25. Hiểu trực quan

Nếu:

V = 100
ω = 0

thì:

Left  = 100
Right = 100

→ đi thẳng.


Nếu:

V = 100
ω > 0

thì:

Left  < 100
Right > 100

→ quay trái.


Nếu:

V = 100
ω < 0

thì:

Left  > 100
Right < 100

→ quay phải.


26. Nhưng phải chú ý đơn vị

Nếu:

V = mm/s

thì:

ω = rad/s

và:

W = mm

sẽ cho:

VL, VR = mm/s

Đây là cách làm sạch và đúng về mặt vật lý.


27. Công thức đầy đủ

             V
             │
       ┌─────┴─────┐
       │           │
       ▼           ▼
     -ωW/2       +ωW/2
       │           │
       ▼           ▼
      VL          VR

Trong C:

left_speed =
    linear_speed -
    angular_speed *
    WHEEL_BASE_MM / 2.0f;

right_speed =
    linear_speed +
    angular_speed *
    WHEEL_BASE_MM / 2.0f;

28. Đây là bước tiến rất lớn

Trước đây chúng ta điều khiển:

Left RPM
Right RPM

Bây giờ điều khiển ở tầng cao hơn:

Linear Speed V
Angular Speed ω

sau đó mới chuyển xuống:

Left wheel
Right wheel

Đây chính là cách tư duy robotics.


29. Kiến trúc điều khiển hoàn chỉnh

                 TARGET X,Y
                     │
                     ▼
              POSITION CONTROLLER
                     │
             ┌───────┴────────┐
             ▼                ▼
        DISTANCE ERROR    HEADING ERROR
             │                │
             ▼                ▼
          Linear V          Angular ω
             │                │
             └───────┬────────┘
                     ▼
              INVERSE KINEMATICS
                     │
              ┌──────┴──────┐
              ▼             ▼
           LEFT V         RIGHT V
              │             │
              ▼             ▼
          SPEED PID      SPEED PID
              │             │
              ▼             ▼
            PWM L         PWM R
              │             │
              ▼             ▼
            MOTOR L       MOTOR R
              │             │
              ▼             ▼
          ENCODER L      ENCODER R
              └──────┬──────┘
                     ▼
                  ODOMETRY
                   X,Y,θ
                     │
                     └──── feedback

30. Hàm Robot_GoTo()

Ta tạo cấu trúc:

typedef struct
{
    float target_x;
    float target_y;

    uint8_t active;

} GoToTarget_t;

Khai báo:

GoToTarget_t goto_target;

31. Hàm bắt đầu

void Robot_GoTo(
    float x,
    float y)
{
    goto_target.target_x = x;
    goto_target.target_y = y;

    goto_target.active = 1;
}

Sau đó:

Robot_GoTo(1000.0f, 500.0f);

32. Tính sai số vị trí

float dx;
float dy;

dx =
    goto_target.target_x -
    odom.x;

dy =
    goto_target.target_y -
    odom.y;

33. Tính distance

float distance;

distance =
    sqrtf(
        dx * dx +
        dy * dy);

34. Tính heading

float target_heading;

target_heading =
    atan2f(dy, dx);

35. Tính heading error

float heading_error;

heading_error =
    target_heading -
    odom.theta;

heading_error =
    NormalizeAngleRad(
        heading_error);

36. Tính tốc độ tiến

float linear_speed;

linear_speed =
    GO_TO_DISTANCE_KP *
    distance;

Ví dụ:

#define GO_TO_DISTANCE_KP 0.5f

Nếu còn:

500 mm

thì:

V = 250 mm/s

Nhưng phải giới hạn.


37. Giới hạn tốc độ

linear_speed =
    Clamp(
        linear_speed,
        0.0f,
        MAX_LINEAR_SPEED);

Ví dụ:

#define MAX_LINEAR_SPEED 300.0f

→ tối đa 300 mm/s.


38. Tính tốc độ quay

float angular_speed;

angular_speed =
    GO_TO_ANGLE_KP *
    heading_error;

Ví dụ:

#define GO_TO_ANGLE_KP 2.0f

Nếu:

heading error = 0.2 rad

thì:

ω = 0.4 rad/s

39. Giới hạn angular speed

angular_speed =
    Clamp(
        angular_speed,
        -MAX_ANGULAR_SPEED,
        MAX_ANGULAR_SPEED);

Ví dụ:

#define MAX_ANGULAR_SPEED 2.0f

40. Một vấn đề: Robot không nên vừa quay quá mạnh vừa chạy nhanh

Nếu:

heading error = 90°

thì robot đang hướng hoàn toàn sai.

Nếu vẫn cho:

linear_speed = 300 mm/s

robot sẽ chạy thành một đường cong rất rộng.

Do đó ta cần giảm tốc độ tiến khi sai số góc lớn.


41. Chiến lược đơn giản

Nếu:

abs(heading_error) > 45°

thì:

linear_speed = 0

Robot quay tại chỗ trước.

Nếu:

abs(heading_error) < 45°

thì bắt đầu chạy.


42. Code

if (fabsf(heading_error) >
    45.0f * DEG_TO_RAD)
{
    linear_speed = 0.0f;
}

Như vậy:

Robot hướng sai nhiều
        ↓
      QUAY
        ↓
Hướng gần đúng
        ↓
     TIẾN + QUAY

43. Đây là State Machine tốt hơn

Ta có thể dùng:

typedef enum
{
    GOTO_IDLE,
    GOTO_ALIGN,
    GOTO_DRIVE,
    GOTO_REACHED

} GoToState_t;

44. GOTO_ALIGN

Robot chỉ quay:

V = 0
ω = ...

45. GOTO_DRIVE

Robot:

V > 0
ω ≠ 0

tức vừa tiến vừa tự chỉnh hướng.


46. GOTO_REACHED

Khi:

distance < tolerance

thì:

V = 0
ω = 0

Robot dừng.


47. Tolerance vị trí

Ví dụ:

#define POSITION_TOLERANCE_MM 10.0f

Nếu:

distance <= 10 mm

→ coi như đã tới.

Đừng đặt:

0.1 mm

với một robot nhỏ dùng encoder thông thường.

Đó là yêu cầu không thực tế.


48. Hàm điều khiển GoTo

Một phiên bản đơn giản:

void Robot_GoTo_Update(void)
{
    float dx;
    float dy;

    float distance;
    float target_heading;
    float heading_error;

    float linear_speed;
    float angular_speed;

    float left_speed;
    float right_speed;

    dx =
        goto_target.target_x -
        odom.x;

    dy =
        goto_target.target_y -
        odom.y;

    distance =
        sqrtf(
            dx * dx +
            dy * dy);

    if (distance <=
        POSITION_TOLERANCE_MM)
    {
        left_speed = 0.0f;
        right_speed = 0.0f;

        goto_target.active = 0;

        return;
    }

    target_heading =
        atan2f(dy, dx);

    heading_error =
        NormalizeAngleRad(
            target_heading -
            odom.theta);

    linear_speed =
        GO_TO_DISTANCE_KP *
        distance;

    linear_speed =
        Clamp(
            linear_speed,
            0.0f,
            MAX_LINEAR_SPEED);

    angular_speed =
        GO_TO_ANGLE_KP *
        heading_error;

    angular_speed =
        Clamp(
            angular_speed,
            -MAX_ANGULAR_SPEED,
            MAX_ANGULAR_SPEED);

    if (fabsf(heading_error) >
        45.0f * DEG_TO_RAD)
    {
        linear_speed = 0.0f;
    }

    left_speed =
        linear_speed -
        angular_speed *
        WHEEL_BASE_MM / 2.0f;

    right_speed =
        linear_speed +
        angular_speed *
        WHEEL_BASE_MM / 2.0f;

    Robot_SetWheelSpeed(
        left_speed,
        right_speed);
}

Đây là bộ điều khiển Go-To cơ bản.


49. Nhưng Robot_SetWheelSpeed() không nên trực tiếp xuất PWM

Đây là điểm rất quan trọng.

Không nên:

GoTo
 ↓
PWM

mà:

GoTo
 ↓
Wheel target speed
 ↓
Speed PID
 ↓
PWM

Tức:

Robot_SetWheelSpeed(
    left_speed,
    right_speed);

chỉ đặt:

target_left_speed
target_right_speed

50. Sau đó Speed PID của Bài 50 xử lý

pwm_left =
    PID_Update(
        &left_pid,
        target_left_speed,
        left_actual_speed,
        dt);

và:

pwm_right =
    PID_Update(
        &right_pid,
        target_right_speed,
        right_actual_speed,
        dt);

51. Đây chính là Cascade Control

Ta có:

             TARGET X,Y
                 │
                 ▼
          GO-TO CONTROLLER
                 │
           V / ω
                 │
                 ▼
        INVERSE KINEMATICS
                 │
          Left / Right Speed
                 │
                 ▼
           SPEED PID
                 │
                PWM
                 │
               MOTOR
                 │
              ENCODER
                 │
                 ▼
             ODOMETRY
                 │
                X,Y,θ
                 │
                 └──────────feedback

52. Ví dụ cụ thể

Robot khởi đầu:

X = 0
Y = 0
θ = 0°

Ta gọi:

Robot_GoTo(
    1000,
    500);

Bước 1

dx = 1000
dy = 500

Khoảng cách:

894 mm

Heading:

26.6°

Robot đang:

0°

→ cần quay trái.


Bước 2

Robot quay:

0°
→
10°
→
20°
→
26°

Khi sai số nhỏ hơn ngưỡng:

linear_speed > 0

Bước 3

Robot bắt đầu:

↗

và liên tục tính lại:

dx
dy
distance
heading_error

Bước 4

Robot càng gần:

distance ↓

thì:

linear_speed ↓

Bước 5

Cuối cùng:

X ≈ 1000
Y ≈ 500

và:

distance < 10 mm

→ STOP.


53. Nhưng có một vấn đề lớn

Bạn có thể nhận thấy:

Nếu robot luôn hướng thẳng vào điểm (1000,500), nó có thể chạy theo một đường cong.

Đúng.

Đó là đặc điểm của bộ điều khiển đơn giản này.

Ta chưa kiểm soát quỹ đạo theo nghĩa chính xác.


54. Đây chưa phải Path Planning

GoTo(X,Y) chỉ trả lời:

Làm thế nào để tới điểm này?

Nó chưa trả lời:

Làm thế nào để đi theo một con đường tối ưu tránh vật cản?

Đó sẽ là những bài sau.


55. Một vấn đề khác: Odometry có drift

Ví dụ robot thực tế:

Target:
X = 1000
Y = 500

Odometry báo:

X = 1000
Y = 500

nhưng thực tế có thể:

X = 985
Y = 520

vì bánh trượt.

Do đó:

GoTo dựa hoàn toàn vào encoder chỉ chính xác trong giới hạn của odometry.


56. Cách cải thiện

Sau này ta có thể thêm:

Encoder
   +
IMU

để cải thiện:

θ

hoặc:

Encoder
+
IMU
+
LiDAR

để định vị tốt hơn.

Nhưng chưa nên nhảy sang đó ngay.

Trước tiên phải làm encoder odometry thật chắc.


57. Bài tập cực kỳ quan trọng

Hãy thử trên robot thật:

Test 1

Robot_GoTo(500, 0);

Robot phải đi:

→ 500 mm

Test 2

Reset robot:

X = 0
Y = 0
θ = 0

sau đó:

Robot_GoTo(0, 500);

Robot phải:

quay trái 90°
+
đi 500 mm

Test 3

Robot_GoTo(500, 500);

Robot phải đi tới góc:

       TARGET
          ●
         /
        /
       /
      ●
    ROBOT

58. Test hình vuông

Đây là bài test rất hay.

Bắt đầu:

(0,0)

Ra lệnh:

GoTo(500,0)
GoTo(500,500)
GoTo(0,500)
GoTo(0,0)

Robot sẽ cố tạo thành:

(0,500) ───────── (500,500)
   │                   │
   │                   │
   │                   │
   │                   │
(0,0)   ───────── (500,0)

Nếu quay về gần:

(0,0)

thì hệ thống odometry khá tốt.


59. Nhưng có một điều bạn nên đo

Sau khi chạy hình vuông, in:

X
Y
θ

Ví dụ:

START
X=0
Y=0
θ=0

END
X=38
Y=-17
θ=4.8°

Đừng coi đây là thất bại.

Đây là dữ liệu calibration.


60. Từ sai số này có thể hiệu chỉnh

Ví dụ robot luôn:

đi xa hơn theo bánh phải

ta có thể hiệu chỉnh:

RIGHT_COUNTS_PER_MM

Nếu robot quay nhiều hơn dự kiến:

WHEEL_BASE_MM

có thể cần calibration lại.


61. Ba thông số hình học cực kỳ quan trọng

Trong robot 2 bánh, hãy nhớ:

LEFT_COUNTS_PER_MM
RIGHT_COUNTS_PER_MM
WHEEL_BASE_MM

Ba thông số này ảnh hưởng trực tiếp đến odometry.


62. Calibration WHEEL_BASE

Ví dụ khai báo:

#define WHEEL_BASE_MM 150.0f

Nhưng robot thực tế quay:

90° command
→
94°

thì WHEEL_BASE_MM đang có sai số hoặc còn các sai số cơ khí khác.

Ta có thể calibration bằng cách cho robot:

10 vòng quay tại chỗ

để giảm ảnh hưởng sai số đo góc nhỏ.


63. Calibration encoder

Tương tự:

Robot_MoveDistance(1000);

đo khoảng cách thực tế.

Nếu robot đi:

1030 mm

thay vì:

1000 mm

thì:

COUNTS_PER_MM

cần điều chỉnh.


64. Một kiến trúc code nên hướng tới

Project của bạn từ đây có thể chia:

STM32_ROBOT/
│
├── motor.c
├── motor.h
│
├── encoder.c
├── encoder.h
│
├── pid.c
├── pid.h
│
├── odometry.c
├── odometry.h
│
├── motion.c
├── motion.h
│
├── robot.c
├── robot.h
│
└── main.c

Trong đó:

motor

Chỉ biết:

PWM
DIR

encoder

Chỉ biết:

COUNT
RPM
DISTANCE

pid

Chỉ biết:

TARGET
ACTUAL
OUTPUT

odometry

Chỉ biết:

X
Y
THETA

motion

Biết:

GoTo
Move
Turn

Đây là cách tổ chức rất tốt khi project lớn dần.


65. Một nguyên tắc thiết kế rất quan trọng

Đừng viết:

if (distance > ...)
    GPIO...
    PWM...
    encoder...

tất cả vào main.c.

Hãy để:

main.c
   ↓
Robot_Update()
   ↓
Motion_Update()
   ↓
PID
   ↓
Motor

và:

Encoder
   ↓
Odometry

độc lập.

Đây là cách giúp project robot sau này không biến thành một mớ if/else.


66. Bài 53 đã đưa chúng ta tới đâu?

Từ:

Bài 45
Encoder

đến:

Bài 46
Motor + Encoder

đến:

Bài 50
2 Motor + 2 PID

đến:

Bài 51
Distance Control

đến:

Bài 52
Angle + Odometry

và bây giờ:

Bài 53
X,Y,θ + GoTo

Bạn đã đi từ điều khiển một ngoại vi sang điều khiển một hệ thống robot hoàn chỉnh.


67. Điều quan trọng nhất cần nhớ trong Bài 53

Có 4 công thức bạn nên thực sự hiểu, không nhất thiết phải học thuộc máy móc.

① Quãng đường trung bình

[
\Delta S=
\frac{\Delta L+\Delta R}{2}
]

② Góc quay

[
\Delta\theta=
\frac{\Delta L-\Delta R}{W}
]

③ Cập nhật vị trí

[
\Delta X=
\Delta S\cos(\theta_{mid})
]

[
\Delta Y=
\Delta S\sin(\theta_{mid})
]

④ Hướng tới mục tiêu

[
\theta_{target}

atan2(\Delta Y,\Delta X)
]

Đây là bộ công thức nền tảng cho robot differential-drive.


68. Và công thức cực kỳ quan trọng tiếp theo

Sau khi có:

V = linear speed
ω = angular speed

ta chuyển thành tốc độ hai bánh:

[
V_L=V-\omega\frac{W}{2}
]

[
V_R=V+\omega\frac{W}{2}
]

Đây chính là inverse kinematics.

Nói cách khác:

           Robot muốn:
          tiến + quay
               ↓
          V + ω
               ↓
       Inverse Kinematics
          ↙         ↘
      LEFT          RIGHT
      wheel          wheel

Đây là một trong những khái niệm quan trọng nhất nếu bạn muốn đi tiếp sang robotics chuyên sâu.


69. Bài 54 sẽ là bước rất đáng học

Sau Bài 53, bài hợp lý tiếp theo là:

BÀI 54 – INVERSE KINEMATICS ROBOT 2 BÁNH: TỪ V, ω → TỐC ĐỘ 2 BÁNH + ĐIỀU KHIỂN QUỸ ĐẠO

Ta sẽ đi sâu vào:

Linear velocity V
Angular velocity ω
        ↓
Inverse Kinematics
        ↓
Left wheel velocity
Right wheel velocity
        ↓
2 × Speed PID
        ↓
2 Motor

và đặc biệt xây dựng một bộ điều khiển có thể nhận:

Robot_SetVelocity(200, 0);

→ đi thẳng,

Robot_SetVelocity(200, 0.5);

→ vừa tiến vừa quay,

Robot_SetVelocity(0, 1.0);

→ quay tại chỗ.

Đây sẽ là bước chuyển từ “đi tới một điểm” sang “điều khiển chuyển động của robot bằng vận tốc tuyến tính V và vận tốc góc ω”.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Bạn có thể hướng dẫn tôi quy trình sửa chữa một mainboard laptop cũng như mainboard của máy tính để bàn không?
  • Có những mức nguồn DC nào trên một bo mạch mainboard laptop?Kỹ thuật đốt dòng để kiểm tra nguồn laptop được thực hiện như thế nào?
  • bài tiếp theo hợp lý là: BÀI 63 – SENSOR FUSION THỰC CHIẾN: ENCODER + IMU MPU6050 + EKF + ODOMETRY X,Y,θ TRÊN STM32F103
  • BÀI 62 – EKF (EXTENDED KALMAN FILTER) CHO ROBOT 2 BÁNH: FUSION ENCODER + IMU + ƯỚC LƯỢNG X, Y, θ, V, ω
  • BÀI 61 – KALMAN FILTER CHO ENCODER + IMU: ƯỚC LƯỢNG TỐC ĐỘ, GÓC θ VÀ SENSOR FUSION

Recent Comments

No comments to show.

Archives

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • May 2026
  • February 2026

Categories

  • Altium Desinger
  • Công nghệ
  • ESP32
  • Khác
  • Kiến thức điện máy
  • STM32
Live 3D Globes Visitor
©2026 Công nghệ 9 giây | Design: Newspaperly WordPress Theme