Files
car_simulation/README.md
2026-06-14 23:26:38 +08:00

4.1 KiB
Raw Blame History

Origincar Simulation

基于 MotrixSim 的阿克曼小车仿真,支持键盘控制和 HTTP API 局域网共享。

启动

uv run mxpython main.py

HTTP API端口 8765

仿真启动后,局域网内其他设备可通过 HTTP 获取摄像头图像、IMU 数据和发送控制指令。

GET /image

获取前置摄像头最新 JPEG 图像。浏览器可直接打开。

# 浏览器
http://<仿真机IP>:8765/image

# curl
curl http://192.168.1.100:8765/image -o frame.jpg

# Python
import requests
r = requests.get("http://192.168.1.100:8765/image")
with open("frame.jpg", "wb") as f:
    f.write(r.content)

GET /state

获取小车当前状态JSON

curl http://192.168.1.100:8765/state

返回示例:

{
  "x": -2.0,
  "y": -2.3,
  "z": 0.08,
  "yaw_deg": 0.0,
  "speed_target": 1.0,
  "speed_actual": 0.98,
  "steer_target": 0.0,
  "speed_amp": 1.0,
  "steer_amp": 0.35
}

GET /imu

获取 IMU 数据(含 MPU6050 噪声JSON。

curl http://192.168.1.100:8765/imu

返回示例:

{
  "orientation": {"w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0},
  "angular_velocity": {"x": 0.001, "y": -0.003, "z": 0.008},
  "linear_acceleration": {"x": 0.02, "y": -0.01, "z": 9.81}
}

噪声参数MPU6050 级别):

  • 陀螺仪白噪声 σ = 0.01 rad/sbias 随机游走
  • 加速度计白噪声 σ = 0.05 m/s²bias 随机游走

POST /cmd

发送控制指令JSON

curl -X POST http://192.168.1.100:8765/cmd \
  -H "Content-Type: application/json" \
  -d '{"speed": 1.0, "steer": 0.3}'
字段 类型 说明
speed float 目标速度 m/s正=前进,负=后退
steer float 目标转向角 rad正=左转,负=右转

Python 客户端示例

import time
import requests

IP = "192.168.1.100"

# 获取图像
r = requests.get(f"http://{IP}:8765/image")
with open("frame.jpg", "wb") as f:
    f.write(r.content)

# 获取状态
state = requests.get(f"http://{IP}:8765/state").json()
print(f"位置: ({state['x']}, {state['y']}), 速度: {state['speed_actual']} m/s")

# 发送控制指令
requests.post(f"http://{IP}:8765/cmd", json={"speed": 1.0, "steer": 0.2})
time.sleep(2)
requests.post(f"http://{IP}:8765/cmd", json={"speed": 0.0, "steer": 0.0})

ROS2 桥接示例

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image as RosImage
from geometry_msgs.msg import Twist
from cv_bridge import CvBridge
import requests
import numpy as np
import cv2

IP = "192.168.1.100"

class OrigincarBridge(Node):
    def __init__(self):
        super().__init__("origincar_bridge")
        self.bridge = CvBridge()
        self.pub = self.create_publisher(RosImage, "/image", 10)
        self.sub = self.create_subscription(Twist, "/cmd_vel", self.cmd_cb, 10)
        self.timer = self.create_timer(0.1, self.fetch_and_publish)

    def fetch_and_publish(self):
        r = requests.get(f"http://{IP}:8765/image", timeout=1)
        if r.status_code == 200:
            arr = np.frombuffer(r.content, np.uint8)
            cv_img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
            msg = self.bridge.cv2_to_imgmsg(cv_img, "bgr8")
            self.pub.publish(msg)

    def cmd_cb(self, msg: Twist):
        requests.post(f"http://{IP}:8765/cmd", json={
            "speed": msg.linear.x,
            "steer": msg.angular.z
        })

rclpy.init()
node = OrigincarBridge()
rclpy.spin(node)

键盘控制

按键 方式 作用
W/S 按住 前进/后退
A/D 按住 左转/右转
↑/↓ 点按 速度幅度 ±0.2 m/s0~2.0
←/→ 点按 转向幅度 ±0.05 rad0~0.5
Space 点按 截图保存到 captures/

键盘与 HTTP /cmd 可同时使用:按住 W/A/S/D 时键盘优先,松开后自动切回 HTTP 控制。

场景结构

scene.xml  — 5m×5m 地图 + 40cm 白色围栏 + 阿克曼小车
main.py    — 仿真控制 + HTTP API 服务
origincar.urdf / origincar.xacro — 小车模型(参考)