---
# System prepended metadata

title: Ackermann Controller
tags: [Omniverse]

---

# Ackermann Controller

> 2025-12-16

[TOC]

---

## 阿克曼機構 (Ackermann Steering Geometry)

**阿克曼轉向幾何（Ackermann Steering Geometry）** 是車輛工程與移動機器人設計中非常基礎且核心的概念。

簡單來說，它是一種機械連桿設計，目的是為了解決四輪車輛在轉彎時，內外側輪胎路徑半徑不同而導致的「磨胎」或「側滑」問題。

### 1. 核心問題：為什麼需要阿克曼幾何？

當一輛車子在轉彎時，四個輪子所走的軌跡其實是不一樣的：

* **內側輪（Inner Wheel）**：走的是半徑較小的圓（內圈）。
* **外側輪（Outer Wheel）**：走的是半徑較大的圓（外圈）。

如果車輛採用簡單的平行轉向（Parallel Steering），即左右輪轉動的角度完全一樣，那麼內側輪與外側輪會互相「打架」，導致其中一個輪子被強行拖曳（側滑），這會造成：

1.  輪胎過度磨損。
2.  轉向機構受力過大。
3.  轉向不順暢，車輛難以精確控制。

### 2. 阿克曼幾何的解決方案

阿克曼機構的設計原則非常直觀：**在轉彎時，讓內側輪的轉向角度比外側輪大。**

這樣可以確保所有四個輪子的旋轉軸心（垂直於輪胎的線）都能交匯於同一點，這個點稱為**瞬時旋轉中心（Instantaneous Center of Rotation, ICR）**。

#### 幾何特徵：
* **理想狀態**：左右前輪的轉向軸線（延長線）與後輪軸線（延長線）精確交會於同一點（ICR）。
* **梯形連桿**：在機械結構上，通常是將兩側轉向臂（Steering Arms）向內傾斜，使其延長線交匯於後軸的中心點。這形成了一個梯形結構，而不是矩形。

---

## 實作過程

:::info
📅 **Note**
其實是昨天做的，但我昨天趕著回去讀類神經網路 qq
Anyway...
:::

### 1. 製作車底盤

#### 啟動 Docker
複習一下，先用 `Docker`：

```bash
xhost +local:

docker run --name isaac-sim --entrypoint bash -it --gpus all -e "ACCEPT_EULA=Y" --rm --network=host --privileged \
    -e "PRIVACY_CONSENT=Y" \
    -e DISPLAY=$DISPLAY \
    -v $HOME/.Xauthority:/isaac-sim/.Xauthority \
    -v ~/docker/isaac-sim/cache/kit:/isaac-sim/kit/cache:rw \
    -v ~/docker/isaac-sim/cache/ov:/isaac-sim/.cache/ov:rw \
    -v ~/docker/isaac-sim/cache/pip:/isaac-sim/.cache/pip:rw \
    -v ~/docker/isaac-sim/cache/glcache:/isaac-sim/.cache/nvidia/GLCache:rw \
    -v ~/docker/isaac-sim/cache/computecache:/isaac-sim/.nv/ComputeCache:rw \
    -v ~/docker/isaac-sim/cache/warp:/isaac-sim/.cache/warp:rw \
    -v ~/docker/isaac-sim/logs:/isaac-sim/.nvidia-omniverse/logs:rw \
    -v ~/docker/isaac-sim/config:/isaac-sim/.nvidia-omniverse/config:rw \
    -v ~/docker/isaac-sim/data:/isaac-sim/.local/share/ov/data:rw \
    -v ~/docker/isaac-sim/documents:/isaac-sim/Documents:rw \
    -v ~/MyRobotProject:/isaac-sim/MyRobotProject:rw \
    -v ~/IsaacSim-ros_workspaces/jazzy_ws/fastdds.xml:/tmp/fastdds.xml \
    -e FASTRTPS_DEFAULT_PROFILES_FILE=/tmp/fastdds.xml \
    -e ROS_DOMAIN_ID=30 \
    nvcr.io/nvidia/isaac-sim:5.1.0
```

在容器內啟動 `isaac-sim`：
```bash
./runapp.sh
```

#### Isaac Sim 設定
接下來我們已經進入 `isaac-sim` 了：
1.  螢幕左上角打開 **`Create`** > **`Environments`** > **`Flat Grid`** 載入地面。
2.  再來一樣螢幕左上角打開 **`Create`** > **`ROS 2 Assets`** > **`Leatherback`** 打開車子模型。

> **選這台車的目的很簡單**：因為我們需要阿克曼結構。
> 它已經幫我們弄好了模型架構，ROS2 Action Graph，可以直接用！

![Screenshot from 2025-12-08 17-00-38](https://hackmd.io/_uploads/BJiUgjAzbg.png)


然後將 `Stage` 中的 `Eletronics_Mounting` 眼睛關掉。
> (有點陽春的做法 xddddd)

### 2. ROS 2 橋接與控制

#### 🖥️ 開第一個新的 `Terminal` (轉譯節點)
一樣開啟新的 `Terminal 1`，輸入：

```bash
docker run -it --rm \
    --net=host \
    --env="DISPLAY" \
    --env="ROS_DOMAIN_ID" \
    -v ~/IsaacSim-ros_workspaces/jazzy_ws:/jazzy_ws \
    --name ros_ws_docker \
    my_isaac_ros /bin/bash
```

載入環境：
```bash
source /opt/ros/jazzy/setup.bash
source /jazzy_ws/install/local_setup.bash
export FASTRTPS_DEFAULT_PROFILES_FILE=/jazzy_ws/fastdds.xml
export ROS_DOMAIN_ID=30
```

如果你這時候打 `ros2 topic list`，應該會看到類似這樣：
```text
root@dodo-System-Product-Name:/# ros2 topic list
/ackermann_cmd
/depth
/odom
/parameter_events
/rgb
/rosout
/tf
```

接著執行範例鍵盤輸入轉譯：
```bash
ros2 launch cmdvel_to_ackermann cmdvel_to_ackermann.launch.py
```

成功的話應該會跳出：
```text
acceleration:=0.5 steering_velocity:=0.5
[INFO] [launch]: All log files can be found below /root/.ros/log/...
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [cmdvel_to_ackermann.py-1]: process started with pid [74]
```

#### 🖥️ 開第二個新的 `Terminal` (鍵盤控制)
開啟第二個 `Terminal 2`，進入剛剛已經開啟的容器：

```bash
docker exec -it ros_ws_docker /bin/bash
```

一樣要載入環境：
```bash
source /opt/ros/jazzy/setup.bash
source /jazzy_ws/install/local_setup.bash
export FASTRTPS_DEFAULT_PROFILES_FILE=/jazzy_ws/fastdds.xml
export ROS_DOMAIN_ID=30
```

執行控制鍵盤的範例：
```bash
ros2 run teleop_twist_keyboard teleop_twist_keyboard
```

會跳出控制說明：
```text
This node takes keypresses from the keyboard and publishes them
as Twist/TwistStamped messages. It works best with a US keyboard layout.
---------------------------
Moving around:
   u    i    o
   j    k    l
   m    ,    .

For Holonomic mode (strafing), hold down the shift key:
---------------------------
   U    I    O
   J    K    L
   M    <    >

t : up (+z)
b : down (-z)

anything else : stop

q/z : increase/decrease max speeds by 10%
w/x : increase/decrease only linear speed by 10%
e/c : increase/decrease only angular speed by 10%

CTRL-C to quit

currently:    speed 0.50    turn 1.00 
```

:::success
🎉 **然後就能操控了！**
:::

{%preview https://youtu.be/9-NoYgY_ljY %}

:::info
🔜 **預告**
接下來應該是更改 **ROS2 Python Script**
:::


> 更：
> 每次打這串太麻煩了
> 我用docker compose優化了一下

在 home 寫一個 `docker-compose.yaml`
```yaml
services:
  # --- Isaac Sim 5.1.0 ---
  isaac-sim:
    image: nvcr.io/nvidia/isaac-sim:5.1.0
    container_name: isaac-sim
    entrypoint: bash
    stdin_open: true
    tty: true
    network_mode: host
    privileged: true
    environment:
      - ACCEPT_EULA=Y
      - PRIVACY_CONSENT=Y
      - DISPLAY=${DISPLAY}
      - FASTRTPS_DEFAULT_PROFILES_FILE=/tmp/fastdds.xml
      - ROS_DOMAIN_ID=30
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
      - ${HOME}/.Xauthority:/isaac-sim/.Xauthority
      - ~/docker/isaac-sim/cache/kit:/isaac-sim/kit/cache:rw
      - ~/docker/isaac-sim/cache/ov:/isaac-sim/.cache/ov:rw
      - ~/docker/isaac-sim/cache/pip:/isaac-sim/.cache/pip:rw
      - ~/docker/isaac-sim/cache/glcache:/isaac-sim/.cache/nvidia/GLCache:rw
      - ~/docker/isaac-sim/cache/computecache:/isaac-sim/.nv/ComputeCache:rw
      - ~/docker/isaac-sim/cache/warp:/isaac-sim/.cache/warp:rw
      - ~/docker/isaac-sim/logs:/isaac-sim/.nvidia-omniverse/logs:rw
      - ~/docker/isaac-sim/config:/isaac-sim/.nvidia-omniverse/config:rw
      - ~/docker/isaac-sim/data:/isaac-sim/.local/share/ov/data:rw
      - ~/docker/isaac-sim/documents:/isaac-sim/Documents:rw
      - ~/MyRobotProject:/isaac-sim/MyRobotProject:rw
      - ~/IsaacSim-ros_workspaces/jazzy_ws/fastdds.xml:/tmp/fastdds.xml

  # --- ROS 2 Jazzy 控制環境 ---
  ros2_jazzy:
    image: my_isaac_ros
    container_name: ros_ws_docker
    network_mode: host
    stdin_open: true
    tty: true
    environment:
      - DISPLAY=${DISPLAY}
      - ROS_DOMAIN_ID=30
      - FASTRTPS_DEFAULT_PROFILES_FILE=/jazzy_ws/fastdds.xml
      # 這裡是重點：讓 entrypoint 直接幫你 source
      - BASH_ENV=/etc/bash.bashrc
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
      - ~/IsaacSim-ros_workspaces/jazzy_ws:/jazzy_ws
    # 這裡會在你進入 bash 之前先 source 必要的環境
    command: >
      bash -c "source /opt/ros/jazzy/setup.bash && 
               source /jazzy_ws/install/local_setup.bash && 
               bash"
```
