0
0
Lập trình
Hưng Nguyễn Xuân 1
Hưng Nguyễn Xuân 1xuanhungptithcm

Hướng Dẫn Tạo Robot Tự Hành Không GPS Bằng Python

Đăng vào 6 tháng trước

• 8 phút đọc

Chủ đề:

KungFuTech

Giới Thiệu

Trong bài viết này, chúng ta sẽ tìm hiểu cách xây dựng một robot tự hành không cần GPS sử dụng Python. Robot này sẽ sử dụng các công nghệ như định vị bằng cảm biến IMU, lập bản đồ lưới, và lập kế hoạch đường đi bằng A*. Chúng ta sẽ cung cấp mã nguồn mẫu và giải thích từng phần để bạn có thể dễ dàng áp dụng vào dự án của riêng mình.

Tổng Quan Về Dự Án

Robot của chúng ta sẽ sử dụng các công nghệ sau:

  • Định vị bằng cảm biến IMU: Sử dụng cảm biến để xác định vị trí và hướng của robot.
  • Lập bản đồ lưới: Sử dụng lưới để đại diện cho không gian và giúp robot nhận biết môi trường xung quanh.
  • Lập kế hoạch đường đi: Sử dụng thuật toán A* để tìm đường đi tối ưu đến đích.
  • Giao diện Dashboard bằng Flask: Cung cấp giao diện người dùng để theo dõi trạng thái của robot.

Cài Đặt Môi Trường

Trước khi bắt đầu, bạn cần cài đặt một số thư viện cần thiết. Đầu tiên, hãy tạo một môi trường ảo và cài đặt các thư viện cần thiết:

bash Copy
python3 -m venv venv
source venv/bin/activate
pip install opencv-python-headless numpy flask matplotlib scipy pillow

Cấu Trúc Mã Nguồn

Chúng ta sẽ xây dựng mã nguồn trong một tệp duy nhất có tên robot.py. Dưới đây là cấu trúc chính của mã:

python Copy
#!/usr/bin/env python3

import time
import threading
import math
import io
import base64
from typing import List, Tuple
import numpy as np
import cv2
from flask import Flask, Response, render_template_string, jsonify
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from PIL import Image
import heapq

Khởi Tạo Flask

Đầu tiên, chúng ta sẽ khởi tạo ứng dụng Flask:

python Copy
app = Flask(__name__)

Định Nghĩa Các Lớp Cảm Biến

Chúng ta sẽ tạo một lớp SensorHealth để theo dõi tình trạng của các cảm biến:

python Copy
class SensorHealth:
    def __init__(self):
        t = time.time()
        self.last_imu = t
        self.last_odom = t
        self.last_cam = t
        self.last_lidar = t

    def update(self, imu=False, odom=False, cam=False, lidar=False):
        now = time.time()
        if imu: self.last_imu = now
        if odom: self.last_odom = now
        if cam: self.last_cam = now
        if lidar: self.last_lidar = now

    def ok(self, timeout=1.0):
        now = time.time()
        return {
            'imu': (now - self.last_imu) < timeout,
            'odom': (now - self.last_odom) < timeout,
            'cam': (now - self.last_cam) < timeout,
            'lidar': (now - self.last_lidar) < timeout
        }

Đọc Giá Trị Từ Cảm Biến

Các hàm sau đây sẽ mô phỏng việc đọc dữ liệu từ cảm biến IMU, odometry và Lidar:

python Copy
def read_imu():
    wz = np.random.normal(0.0, 0.02)
    ax = np.random.normal(0.0, 0.1)
    return float(wz), float(ax)

def read_wheel_odometry():
    d = 0.02 + np.random.normal(0.0, 0.004)
    dtheta = np.random.normal(0.0, 0.004)
    return float(d), float(dtheta)

def read_lidar_scan(num_beams=180, max_range=5.0):
    angles = np.linspace(-np.pi/2, np.pi/2, num_beams)
    ranges = max_range * np.ones_like(angles)
    center_idx = num_beams // 2
    ranges[center_idx-3:center_idx+4] = 1.5 + np.random.normal(0.0, 0.03, 7)
    ranges += np.random.normal(0.0, 0.02, size=angles.shape)
    ranges = np.clip(ranges, 0.02, max_range)
    return ranges.astype(float), angles.astype(float)

Tạo Class CameraWrapper

Chúng ta cũng cần một lớp để quản lý camera:

python Copy
class CameraWrapper:
    def __init__(self, source=0, width=320, height=240):
        self.cap = cv2.VideoCapture(source)
        self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
        self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
        self.last_frame = None

    def read(self):
        ret, frame = self.cap.read()
        if not ret or frame is None:
            frame = np.zeros((240,320,3), dtype=np.uint8)
        self.last_frame = frame
        return frame

    def release(self):
        self.cap.release()

Lớp EKF (Kalman Filter Mở Rộng)

python Copy
class EKF:
    def __init__(self):
        self.x = np.zeros((3,1)) # x, y, theta
        self.P = np.diag([0.1, 0.1, 0.05])  # noise covariance
        self.Q = np.diag([0.02, 0.02, 0.01])  # process noise

    def predict(self, delta_dist, delta_theta):
        x, y, th = self.x.flatten()
        th_new = th + delta_theta
        x_new = x + delta_dist * np.cos(th_new)
        y_new = y + delta_dist * np.sin(th_new)
        self.x = np.array([[x_new],[y_new],[th_new]])
        self.P += self.Q

    def update_pose(self, z, R):
        H = np.eye(3)
        y = z - H.dot(self.x)
        y[2] = (y[2] + np.pi) % (2*np.pi) - np.pi
        S = H.dot(self.P).dot(H.T) + R
        K = self.P.dot(H.T).dot(np.linalg.inv(S))
        self.x += K.dot(y)
        self.P = (np.eye(3) - K.dot(H)).dot(self.P)

    def get_state(self):
        return self.x.flatten()

Lớp Lập Bản Đồ Lưới

python Copy
class OccupancyGrid:
    def __init__(self, width_m=10.0, height_m=10.0, resolution=0.05):
        self.resolution = resolution
        self.width = int(width_m / resolution)
        self.height = int(height_m / resolution)
        self.log_odds = np.zeros((self.height, self.width), dtype=np.float32)
        self.l_free = -0.4
        self.l_occ = 0.85
        self.origin_x = -width_m / 2.0
        self.origin_y = -height_m / 2.0

    def integrate_scan(self, pose: Tuple[float,float,float], ranges: np.ndarray, angles: np.ndarray):
        # Implement logic to integrate Lidar scan into occupancy grid
        pass

Lớp Điều Khiển (Pure Pursuit)

python Copy
class PurePursuitController:
    def __init__(self, lookahead_m=0.3, max_speed=0.2):
        self.lookahead = lookahead_m
        self.max_speed = max_speed

    def compute_control(self, pose: Tuple[float,float,float], path_world: List[Tuple[float,float]], obstacle_dist: float):
        # Implement control logic
        pass

Router Flask

python Copy
@app.route('/')
def index():
    return render_template_string("""
    <h1>Robot Dashboard</h1>
    <p>Đang chạy robot không GPS.</p>
    """)

@app.route('/state')
def state():
    return jsonify(_state)

Thực Thi Dashboard

Chúng ta sẽ chạy một luồng cho dashboard:

python Copy
def run_dashboard_server():
    app.run(host='0.0.0.0', port=5000, debug=False, use_reloader=False)

Vòng Lặp Chính

python Copy
def main_loop(rate_hz=10):
    dt = 1.0 / rate_hz
    ekf = EKF()
    vo = VisualOdometry()
    grid = OccupancyGrid()
    controller = PurePursuitController()
    sensor_health = SensorHealth()
    cam = CameraWrapper()

    while True:
        # Read sensors and update state
        time.sleep(dt)

Kết Luận

Trong bài viết này, chúng ta đã khám phá cách xây dựng một robot tự hành không cần GPS bằng Python. Bằng cách kết hợp các công nghệ như định vị bằng IMU, lập bản đồ lưới, và A*, chúng ta đã tạo ra một hệ thống có thể di chuyển và lập bản đồ trong môi trường không có GPS. Hãy thử nghiệm với mã nguồn và điều chỉnh các tham số để tối ưu hóa hiệu suất robot của bạn!

Các Thực Hành Tốt Nhất

  • Thử nghiệm với các cảm biến khác nhau để cải thiện độ chính xác của robot.
  • Tối ưu hóa mã nguồn để giảm thiểu độ trễ trong quá trình xử lý.

Những Cạm Bẫy Thường Gặp

  • Không kiểm tra tình trạng của cảm biến có thể dẫn đến lỗi khi robot hoạt động.
  • Không cập nhật thường xuyên trạng thái của robot có thể làm cho robot mất định vị.

Mẹo Hiệu Suất

  • Sử dụng đa luồng để xử lý song song các cảm biến.
  • Giảm độ phân giải của hình ảnh nếu không cần thiết để tiết kiệm băng thông.

Giải Quyết Vấn Đề

  • Nếu robot không di chuyển, hãy kiểm tra cảm biến IMU và odometry.
  • Đảm bảo rằng thuật toán A* được cấu hình chính xác.

Câu Hỏi Thường Gặp

  1. Robot có thể sử dụng các cảm biến nào?
    • Robot có thể sử dụng cảm biến IMU, Lidar, và camera.
  2. Có cần thiết phải có GPS không?
    • Không, robot có thể hoạt động hoàn toàn mà không cần GPS thông qua cảm biến nội bộ.
  3. Làm thế nào để cải thiện độ chính xác của robot?
    • Điều chỉnh các tham số trong bộ lọc Kalman và cải thiện độ chính xác của cảm biến.

Tham Khảo

Hãy bắt đầu xây dựng robot của bạn ngay hôm nay!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào