14์์ ๋(14-DOF) ๋ค๋ฌผ์ฒด ๋์ญํ FMU ๋ฐ Unity 3D, ROS 2 ๊ธฐ๋ฐ ์ค์๊ฐ ์์จ์ฃผํ ์ฐจ๋ ๋์งํธ ํธ์ ์๋ฎฌ๋ ์ดํฐ
An Open-Source Real-Time Autonomous Driving Digital Twin Simulator Framework Based on Simscape Multibody 14-DOF FMU, Unity 3D, and ROS 2.
- ๊ฐ์ (Overview)
- ์ฃผ์ ๊ธฐ๋ฅ (Key Features)
- ์์ํ๊ธฐ ๋ฐ ๋ฐฐํฌ๋ณธ ์คํ (Getting Started)
- ROS 2 ์ฐ๋ ๋ฐ ํต์ ๋ช
์ธ (ROS 2 Integration & Topics)
- 1. ROS-TCP-Endpoint ์ค์น ๋ฐ ๋น๋
- 2. KIMM ์ ์ด ๋ฉ์์ง ํจํค์ง (
kimm_msgs) ๋ค์ด๋ก๋ ๋ฐ ๋น๋ - 3. ROS-TCP-Endpoint ์๋ฒ ์คํ
- 4. KIMM ์ฐจ๋ ์ ์ด ๋ฉ์์ง ๋ช
์ธ (
kimm_msgs/CarControlCmd) - 5. ROS 2 ํ ํฝ ์ธํฐํ์ด์ค ์ ์ฒด ๋ช ์ธ (Topics Specification)
- 6. ์์จ์ฃผํ ๊ฒฝ๋ก ์ถ์ข
์ ์ด Python ์์ ์ฝ๋ (
pure_pursuit_demo.py)
- ์กฐ์ ๋ฐ ๋จ์ถํค ์๋ด (Controls Guide)
- ๋ฐํ์ ํ๊ฒฝ์ค์ (Configuration & Hot-Swap)
- ์ง์ ๋งต ๋ฐ ํธ๋ (Supported Tracks)
KIMM Car Simulator๋ ์ค์ยท์ค๊ฒฌ ์๋์ฐจ ๋ถํ์ฌ, ์คํํธ์ ๋ฐ ์ฐ๊ตฌ๊ธฐ๊ด์ ๊ณ ๊ฐ ์ธ์ฐ ์์ฉ ์๋ฎฌ๋ ์ดํฐ ๋์ ๋น์ฉ ๋ถ๋ด์ ๋๊ณ , ์ค์ฐจ ์์ค์ ๊ณ ์ถฉ์ค๋ ๊ฐ์ ๊ฒ์ฆ ํ๊ฒฝ์ ์ ๊ณตํ๊ธฐ ์ํด ๊ฐ๋ฐ๋ ์คํ์์ค ์์จ์ฃผํ ์ฐจ๋ ๋์งํธ ํธ์ ์๋ฎฌ๋ ์ดํฐ์ด๋ค.
๐ ๊ณต์ ์ฌ์ฉ์ ๋งค๋ด์ผ PDF ์ด๋ ๋ฐ ๋ค์ด๋ก๋ (User Manual PDF)
์๋ฎฌ๋ ์ดํฐ UI ๊ฐ์ด๋, ํค๋ณด๋/๋ ์ด์ฑํ ์กฐ์๋ฒ, ์๋๋ฆฌ์ค ํธ์ง ๋ชจ๋ ๋ฑ ์์ธ ์ค๋ช ์ด ํฌํจ๋ ๊ณต์ ๋งค๋ด์ผ ๋ฌธ์
- 1000 Hz ๋ค๋ฌผ์ฒด ๋์ญํ: MATLAB Simscape Multibody ๊ธฐ๋ฐ 14์์ ๋(14-DOF) ๋ชจ๋ธ๊ณผ Magic Formula ๋น์ ํ ํ์ด์ด ๋ง์ฐฐ ๋ชจ๋ธ์ C++ FMU๋ก ์ฐ๋ํ์ฌ 1ms Co-Simulation์ ์ํํ๋ค.
- ์ผ์ ๋ฐ ํ๋ผ๋ฏธํฐ ํซ์ค์: ์์ค์ฝ๋ ์ฌ์ปดํ์ผ ์์ด JSON ํ์ผ๋ง์ผ๋ก 45๊ฐ ์ฐจ๋ ๋ฌผ๋ฆฌ ๋ณ์์ ๋ณต์ LiDAR/Camera/GNSS/IMU ๊ตฌ์ฑ์ ์ค์๊ฐ ๊ต์ฒดํ๋ค.
- ํ์ค ROS 2 ์ธํฐํ์ด์ค: ์ค์ ์ฐจ๋ By-Wire ์ ์ด ๊ท๊ฒฉ(
kimm_msgs/CarControlCmd)์ ํตํด Ubuntu ROS 2 ์์จ์ฃผํ ํ์คํ(์ธ์ง-ํ๋จ-์ ์ด)๊ณผ 1:1 ์งํต ํต์ ์ ์ง์ํ๋ค.
| ๋ถ๋ฅ | ์ฃผ์ ๊ธฐ๋ฅ ๋ฐ ๊ธฐ์ ์คํ |
|---|---|
| ๐ ์ฐจ๋ ๋์ญํ | โข 14์์ ๋ ๋ค๋ฌผ์ฒด ๋ชจ๋ธ: ์ฐจ์ฒด 6-DOF, 4๋ฅ ๋
๋ฆฝ ์์คํ์
4-DOF, ํ ํ์ 4-DOF โข Magic Formula ํ์ด์ด ๋ชจ๋ธ: 4๋ฐํด ์ค์๊ฐ ๋ ธ๋ฉด ๊ณ ๋/๊ฒฝ์ฌ๊ฐ ๋ ์ด์บ์คํธ ๋ฐ ๋น์ ํ ๊ตฌ๋/์ ๋/์ฝ๋๋ง ํฌ์ค ๊ณ์ฐ โข 1000 Hz Co-Simulation: FMI 2.0 ํ์ค C++ ๋ฐ์ด๋๋ฆฌ ๊ธฐ๋ฐ 1ms ๊ฒฐ์ ๋ก ์ ์ฐ์ฑ ํด์ |
| ๐ก ์ผ์ ์ค์ํธ | โข 3D LiDAR: 16/32/64์ฑ๋ ๋ณ๋ ฌ ๋ ์ด์บ์คํธ ๋ฐ sensor_msgs/PointCloud2 ๋ฐํโข HD Camera: RGB ์ /ํ๋ฐฉ/์ด๋ผ์ด๋๋ทฐ ๋ ๋ ํ ์ค์ฒ ๋ฐ sensor_msgs/CompressedImage ์คํธ๋ฆฌ๋ฐโข GNSS & IMU: WGS84 ์๊ฒฝ๋ ๋ณํ( NavSatFix) ๋ฐ 100Hz 6์ถ ๊ด์ฑ ์ผ์ ๋ฐ์ดํฐ(Imu) |
| ๐ ํต์ ๋ฐ ์ฐ๋ | โข ROS 2 By-Wire ์ธํฐํ์ด์ค: kimm_msgs/CarControlCmd (๊ฐ์, ์ ๋, ์กฐํฅ, ๊ธฐ์ด)โข ๋น๋๊ธฐ TCP ๊ฒ์ดํธ์จ์ด: ROS-TCP-Endpoint ๊ธฐ๋ฐ ๋ค์ค ์ค๋ ๋ ๊ณ ์ ํต์ |
| ๐ ๏ธ ์ฌ์ฉ์ ํธ์ ๊ธฐ๋ฅ | โข ์ค์๊ฐ ํ
๋ ๋ฉํธ๋ฆฌ ์ฐจํธ (TAB): ์๋, ๋กค/ํผ์น๊ฐ, ์์คํ์
๋ณ์, ์ฌ๋ฆฝ๋ฅ ๋์ ์๊ฐํโข ์ธํฐ๋ํฐ๋ธ ์๋๋ฆฌ์ค ํธ์ง ๋ชจ๋ ( E): ์ฃผํ ์ ์ง ํ ๊ณผ์๋ฐฉ์งํฑ, ๋๋ผํต, ๋๋ฏธ์ฐจ๋, ๋์ ๋ณดํ์ ์ค์๊ฐ ๋ฐฐ์นโข ESC ์์คํ ๋ฉ๋ด: ๋งต ์ ํ, ํ์ผ ํ์๊ธฐ ๊ธฐ๋ฐ ์ฐจ๋/์ผ์ JSON ์ฆ์ ํซ์ค์ |
์๋ฎฌ๋ ์ดํฐ๋ ๋ณ๋์ ์์ค์ฝ๋ ๋น๋ ๊ณผ์ ์์ด, ์ฌ์ ์ ๋น๋๋ ๋ ๋ฆฝ ์คํ ํจํค์ง๋ฅผ ๋ค์ด๋ก๋ํ์ฌ ์ฆ์ ๊ตฌ๋ํ ์ ์๋ค.
- ์ ์ฅ์ ์ฐ์ธก์ Releases ํ์ด์ง์์ ์ต์ Windows ํจํค์ง(
Kimm-Car-Simulator_v1.0.0_Windows_x64.zip)๋ฅผ ๋ค์ด๋ก๋ํ๋ค. - ๋ค์ด๋ก๋ํ
.zip์์ถํ์ผ์ ์ํ๋ ๋๋ ํ ๋ฆฌ์ ํด์ ํ๋ค. - ํด๋ ๋ด์
Kimm-Car-Simulator.exe๋ฅผ ๋๋ธํด๋ฆญํ์ฌ ์คํํ๋ค. - ํค๋ณด๋(
W/A/S/D) ๋๋ USB ๋ ์ด์ฑ ํ ์ ์ฌ์ฉํ์ฌ ์ฃผํ์ ์์ํ๋ค.
- ์ ์ฅ์ ์ฐ์ธก์ Releases ํ์ด์ง์์ ์ต์ Linux ํจํค์ง(
Kimm-Car-Simulator_v1.0.0_Linux_x64.tar.gz)๋ฅผ ๋ค์ด๋ก๋ํ๋ค. - ํฐ๋ฏธ๋์ ์ด๊ณ ์์ถ์ ํด์ ํ ํ ์คํ ๊ถํ์ ๋ถ์ฌํ๋ค:
tar -zxvf Kimm-Car-Simulator_v1.0.0_Linux_x64.tar.gz cd Kimm-Car-Simulator_Linux chmod +x Kimm-Car-Simulator.x86_64 ./Kimm-Car-Simulator.x86_64
Ubuntu 22.04 (Humble / Foxy) ๋๋ Windows WSL2 ํ๊ฒฝ์์ ์๋ฎฌ๋ ์ดํฐ์ TCP ์์ผ์ผ๋ก ๊ณ ์ ์ฐ๋ํ์ฌ ์ผ์ ๋ฐ์ดํฐ ์์ ๋ฐ By-Wire ์์จ์ฃผํ ์ ์ด๋ฅผ ์ํํ ์ ์๋ค.
Unity์ ROS 2 ๊ฐ์ ๋น๋๊ธฐ TCP ํต์ ์ ์ง์ํ๋ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Unity-Technologies/ROS-TCP-Endpoint๋ฅผ ์ํฌ์คํ์ด์ค์ ํด๋ก ํ๊ณ ๋น๋ํ๋ค:
# 1. ROS 2 ์ํฌ์คํ์ด์ค ์์ฑ ๋ฐ ์ด๋
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
# 2. Unity ๊ณต์ ROS-TCP-Endpoint ์ ์ฅ์ ํด๋ก
git clone -b main-ros2 https://github.com/Unity-Technologies/ROS-TCP-Endpoint.git
# 3. ํจํค์ง ๋น๋
cd ~/ros2_ws
colcon build --packages-select ros_tcp_endpoint
source install/setup.bash์ฐจ๋ By-Wire ์ ์ด ๋ช
๋ น(/kimm/car_cmd)์ ๋ฐํํ๊ธฐ ์ํ ์ปค์คํ
๋ฉ์์ง ํจํค์ง(kimm_msgs)๋ฅผ ๋ค์ด๋ก๋ํ์ฌ ๋น๋ํ๋ค:
cd ~/ros2_ws/src
# 1. KIMM ROS 2 ๋ฉ์์ง ํจํค์ง ๋ค์ด๋ก๋ ๋ฐ ์์ถ ํด์ (1์ด ์ปท)
wget https://github.com/dbsrn0125/Kimm-Car-Simulator/releases/download/v1.0.0/kimm_ros2_packages.zip
unzip kimm_ros2_packages.zip
# 2. kimm_msgs ๋ฉ์์ง ํจํค์ง ๋น๋ ๋ฐ ํ๊ฒฝ ์ ์ฉ
cd ~/ros2_ws
colcon build --packages-select kimm_msgs
source install/setup.bash# ROS 2 ํ๊ฒฝ ํ์ฑํ
source ~/ros2_ws/install/setup.bash
# TCP ์๋ํฌ์ธํธ ์๋ฒ ์คํ (๊ธฐ๋ณธ ํฌํธ: 10000)
ros2 run ros_tcp_endpoint default_server_endpoint --ros-args -p ROS_IP:=0.0.0.0 -p ROS_PORT:=10000
### 4. KIMM ์ฐจ๋ ์ ์ด ๋ฉ์์ง ๋ช
์ธ (`kimm_msgs/CarControlCmd`)
์ธ๋ถ ์์จ์ฃผํ ์๊ณ ๋ฆฌ์ฆ ๋
ธ๋๊ฐ ์๋ฎฌ๋ ์ดํฐ ์ฐจ๋์ By-Wire ๋ฐฉ์์ผ๋ก ์ ์ ์ ์ดํ๊ธฐ ์ํด `/kimm/car_cmd` ํ ํฝ์ผ๋ก ๋ฐํํ๋ ๋ฉ์์ง ์ ์์ด๋ค:
```yaml
# kimm_msgs/msg/CarControlCmd.msg
float32 accel # ๊ฐ์ ํ๋ฌ ๋ต๋ ฅ (0.0 ~ 1.0)
float32 brake # ์ ์ ์ ๋ ํ๋ฌ ๋ต๋ ฅ (0.0 ~ 1.0)
float32 steering # ์ ๋ฅ ์กฐํฅ๊ฐ (-1.0: ์ต๋ ์ขํ์ , +1.0: ์ต๋ ์ฐํ์ )
int32 gear # ์ ์์ ๋ณ์ ๊ธฐ์ด (0: Park, 1: Drive, -1: Reverse)๊ธฐ๋ณธ ์ผ์ ๊ตฌ์ฑ(default_sensor_config.json) ๊ธฐ์ค ๋ฐํ/๊ตฌ๋
ํ ํฝ ๋ชฉ๋ก:
| ํ ํฝ๋ช (Topic Name) | ๋ฉ์์ง ํ์ (Type) | ์ฃผํ์ (Hz) | ์ค๋ช |
|---|---|---|---|
/kimm/vehicle_status |
nav_msgs/msg/Odometry |
50.0 | ์ค์๊ฐ ์ฐจ์, ์ ์ญ ์ค๋๋ฉํธ๋ฆฌ ์์น$(X, Y, Z)$, ์ฟผํฐ๋์ธ ํค๋ฉ ์์ธ |
/kimm/lidar/points |
sensor_msgs/msg/PointCloud2 |
20.0 | 3D LiDAR ํฌ์ธํธํด๋ผ์ฐ๋ (100,000 pts/scan) |
/kimm/camera/color/compressed |
sensor_msgs/msg/CompressedImage |
30.0 | ์ ๋ฐฉ HD RGB ์นด๋ฉ๋ผ JPEG ์ค์๊ฐ ์์ ์คํธ๋ฆผ |
/kimm/gnss/fix |
sensor_msgs/msg/NavSatFix |
10.0 | WGS84 ์๋, ๊ฒฝ๋, ํ์์ฒด ๊ณ ๋ ๋ฐ์ดํฐ |
/kimm/imu/data |
sensor_msgs/msg/Imu |
100.0 | 6์ถ ๊ด์ฑ ์ผ์ ๊ฐ์๋ ๋ฐ 3์ถ ๊ฐ์๋ ๋ฐ์ดํฐ |
/kimm/goal_pose |
geometry_msgs/msg/PoseStamped |
Event | Auto Mode ํ๋ฉด ํ(Pin ๐) ํด๋ฆญ ์ 5ํ ์ฐ์ ๋ธ๋ก๋์บ์คํธ ๋ฐํ |
/kimm/car_cmd |
kimm_msgs/msg/CarControlCmd |
100.0 | ์ธ๋ถ ์์จ์ฃผํ ์ ์ด๊ธฐ๋ก๋ถํฐ์ By-Wire ์ฃผํ ๋ช ๋ น (์์ ) |
์๋ฎฌ๋ ์ดํฐ ์ฐจ๋์ ์์จ์ฃผํ ์ ์ด ๋ชจ๋(AUTO MODE, ๋จ์ถํค M)๋ก ์ ํํ๋ฉด ํ๋ฉด์์ ๋ง์ฐ์ค ์ขํด๋ฆญ์ผ๋ก ๋ฐ๋ฅ์ ๋ชฉํ ํ(Goal Pin ๐)์ ์ง์ ๋ฐฐ์นํ ์ ์๋ค. ํ์ด ๋ฐฐ์น๋๋ฉด ์๋ฎฌ๋ ์ดํฐ๊ฐ /kimm/goal_pose ํ ํฝ์ 5ํ ์ฐ์ ์ ์กํ๋ฉฐ, ์๋ ํ์ด์ฌ ์คํฌ๋ฆฝํธ๊ฐ ์ด๋ฅผ ์์ ํ์ฌ Pure Pursuit ์กฐํฅ๊ฐ ์ฐ์ถ, ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ ์ ์ํ ๊ฐ์, 2.0m ์ด๋ด ์ ๋ฐ ์ ์ฐจ๋ฅผ ์ํํ๋ค:
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
import math
from nav_msgs.msg import Odometry
from geometry_msgs.msg import PoseStamped
from kimm_msgs.msg import CarControlCmd
class KimmPurePursuitController(Node):
def __init__(self):
super().__init__('kimm_pure_pursuit_controller')
# ์๋ฎฌ๋ ์ดํฐ ์ฐจ๋ ์ํ(Odometry) ๋ฐ ๋ง์ฐ์ค ํ ๋ชฉํ ์ง์ (Goal Pose) ๊ตฌ๋
self.sub_odom = self.create_subscription(Odometry, '/kimm/vehicle_status', self.odom_cb, 10)
self.sub_goal = self.create_subscription(PoseStamped, '/kimm/goal_pose', self.goal_cb, 10)
# By-Wire ์ ์ด ๋ช
๋ น ํผ๋ธ๋ฆฌ์
์์ฑ
self.pub_cmd = self.create_publisher(CarControlCmd, '/kimm/car_cmd', 10)
self.current_x = None
self.current_y = None
self.current_speed = 0.0
self.current_yaw = 0.0
self.goal_x = None
self.goal_y = None
self.timer = self.create_timer(0.05, self.control_loop) # 20 Hz ์ ์ด ๋ฃจํ
self.get_logger().info("๐ [KIMM Pure Pursuit Node] Autonomous Controller Ready!")
def odom_cb(self, msg):
self.current_x = msg.pose.pose.position.x
self.current_y = msg.pose.pose.position.y
vx = msg.twist.twist.linear.x
vy = msg.twist.twist.linear.y
self.current_speed = math.hypot(vx, vy)
q = msg.pose.pose.orientation
siny_cosp = 2.0 * (q.w * q.z + q.x * q.y)
cosy_cosp = 1.0 - 2.0 * (q.y * q.y + q.z * q.z)
self.current_yaw = math.atan2(siny_cosp, cosy_cosp)
def goal_cb(self, msg):
self.goal_x = msg.pose.position.x
self.goal_y = msg.pose.position.y
self.get_logger().info(f"๐ฉ New Goal Pin Received: X={self.goal_x:.2f}, Y={self.goal_y:.2f}")
def control_loop(self):
if self.current_x is None or self.goal_x is None:
return
dx = self.goal_x - self.current_x
dy = self.goal_y - self.current_y
dist = math.hypot(dx, dy)
cmd = CarControlCmd()
# 1. ๋ชฉํ ์ง์ 2.0m ์ด๋ด ์ ๋ฐ ์ ์ฐจ
if dist < 2.0:
cmd.accel = 0.0
cmd.brake = 1.0
cmd.steering = 0.0
cmd.gear = 1
self.get_logger().info("๐ฏ Goal Destination Reached! Vehicle Safely Stopped.")
self.goal_x = None
self.goal_y = None
else:
# 2. Pure Pursuit ์กฐํฅ๊ฐ ์ฐ์ถ
target_angle = math.atan2(dy, dx)
alpha = target_angle - self.current_yaw
while alpha > math.pi: alpha -= 2 * math.pi
while alpha < -math.pi: alpha += 2 * math.pi
steering_cmd = math.sin(alpha) * 1.5
cmd.steering = max(-1.0, min(1.0, steering_cmd))
# 3. ๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ ์ ์ํ ๊ฐ์ ํ๋กํ์ผ๋ง (25m ์ ๋ถํฐ ๊ฐ์)
if dist < 25.0:
target_speed_mps = max(0.6, dist * 0.2)
if self.current_speed > target_speed_mps:
cmd.accel = 0.0
cmd.brake = min(1.0, (self.current_speed - target_speed_mps) * 0.5 + 0.15)
else:
cmd.accel = 0.08
cmd.brake = 0.0
else:
cmd.accel = 0.4
cmd.brake = 0.0
cmd.gear = 1
self.pub_cmd.publish(cmd)
def main(args=None):
rclpy.init(args=args)
node = KimmPurePursuitController()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()- ์๋ฎฌ๋ ์ดํฐ ์ฃผํ ์ค ํค๋ณด๋
Mํค๋ฅผ ๋๋ฌAUTO MODE๋ก ์ ํํ๋ค. - ๋ง์ฐ์ค ์ปค์๊ฐ ํ์ฑํ๋๋ฉด ๊ฐ์ ํธ๋ ๋๋ก ๋ฐ๋ฅ์ ์ํ๋ ์์น๋ฅผ ๋ง์ฐ์ค ์ขํด๋ฆญํ๋ค.
- 3D ์งํ์ ๋ถ์์ ๋ชฉํ ํ(Goal Pin ๐) ์ด ๊ฝํ๋ฉฐ, ์๋ฎฌ๋ ์ดํฐ๋ ํจํท ์ ์ค ๋ฐฉ์ง๋ฅผ ์ํด ROS 2
/kimm/goal_poseํ ํฝ์ 5ํ ์ฐ์ ๋ธ๋ก๋์บ์คํธํ๋ค. - ์คํ ์ค์ธ
pure_pursuit_demo.py๊ฐ ์ด๋ฅผ ์์ ํ์ฌ ์ฐจ๋์ด ์ฆ์ ํด๋น ๋ชฉํ ํ์ ํฅํด ์์จ์ฃผํ์ ์์ํ๋ค.
| ํค (Key) | ๊ธฐ๋ฅ (Function) | ์์ธ ์ค๋ช |
|---|---|---|
W / S |
๊ฐ์ / ๊ฐ์ (Throttle / Brake) | ์ฐจ๋ ์ข ๋ฐฉํฅ ๊ฐ์ ๋ฐ ์ ์ ์ ๋ |
A / D |
์กฐํฅ (Steering Left / Right) | ์ ๋ฅ ์กฐํฅ๊ฐ ์ ์ด |
Shift / Ctrl |
๊ธฐ์ด ์ ์ง / ํ์ง (Drive / Reverse) | Shift: ์ ์ง(D) ๊ธฐ์ด ์ฒด๊ฒฐ / Ctrl: ํ์ง(R) ๊ธฐ์ด ์ฒด๊ฒฐ |
P |
ํํน ๊ธฐ์ด (Park) | ์ฃผ์ฐจ(P) ๊ธฐ์ด ์ฒด๊ฒฐ (gear: 0) |
M |
์๋ / ์์จ ๋ชจ๋ ์ ํ (Manual โ Auto) | ์ด์ ์ ์๋ ์ฃผํ๊ณผ ROS 2 ์์จ์ฃผํ ์ ์ด๊ถ 1:1 ํ ๊ธ |
R |
์ฐจ๋ ์์น ๋ฆฌ์ (Reset Vehicle) | ํ์ฌ ๋งต์ ์ต์ด ์์ ์คํฐ ์์น๋ก ์ฆ์ ์ฌ๋ฐฐ์น |
E |
์ธํฐ๋ํฐ๋ธ ์๋๋ฆฌ์ค ํธ์ง ๋ชจ๋ ํ ๊ธ | ์ฃผํ ์ ์ง ํ ์ฅ์ ๋ฌผ/๋ณดํ์ ๋ง์ฐ์ค ๋ฐฐ์น ๋ชจ๋ ์ง์ |
TAB |
์ค์๊ฐ ํ ๋ ๋ฉํธ๋ฆฌ ์ฐจํธ ํ ๊ธ | ์๋, ๋กค/ํผ์น, ์์คํ์ ๋ณ์, ์ฌ๋ฆฝ๋ฅ ๊ทธ๋ํ ์ค๋ฒ๋ ์ด |
ESC |
๋ฉ์ธ ์์คํ ๋ฉ๋ด ์ด๊ธฐ / ๋ซ๊ธฐ | ๋งต ์ ํ, ์ฐจ๋/์ผ์ JSON ํซ์ค์, ์ค์ ํ์ |
F1 |
์กฐ์ ๋์๋ง ํ์ ํ ๊ธ | ์ ์ฒด ํค ๋งคํ ๋ฐ ํ ์กฐ์ ์๋ด์ฐฝ ํ์ |
F5 ~ F8 |
์์ ์ ํ (Camera Views) | F5: 1์ธ์นญ/3์ธ์นญ, F6: ํ๋ทฐ, F7/F8: ์ข/์ฐ ์ฌ์ด๋๋ทฐ |
- ์คํฐ์ด๋ง ํ / ํ๋ฌ: ์๋ ๋ก๊ทธ ์กฐํฅ๊ฐ ๋ฐ ๊ฐ์(Gas) / ์ ๋(Brake) ํ๋ฌ ๋ต๋ ฅ ๋น๋ก ์ ์ด (0 ~ 100%)
-
ํจ๋ค ์ํํธ: ์ฐ์ธก ํจ๋ค(D ๊ธฐ์ด ์ฒด๊ฒฐ) / ์ข์ธก ํจ๋ค(R ๊ธฐ์ด
$\leftrightarrow$ P ๊ธฐ์ด ์ํ) -
๋ฒํผ ๋งคํ:
- ๐ต
A๋ฒํผ (South): ์๋ โ ์์จ์ฃผํ ๋ชจ๋ ์ ํ (Mํค ๋์ผ) - ๐ด
B๋ฒํผ (East): ์ฐจ๋ ์์น ๋ฆฌ์ (Rํค ๋์ผ) - ๐ข
X๋ฒํผ (West): HUD ๋ฏธ๋ ๋ทฐํฌํธ ์์ ๋ณ๊ฒฝ - ๐ก
Y๋ฒํผ (North): ๋งต ์ํ ๋ก๋ฉ (K-City โ Mcity โ ZalaZone โ PG) - ์ญ์ํค (D-Pad): ์/ํ/์ข/์ฐ ์นด๋ฉ๋ผ ๋ทฐ ์ฆ์ ์ ํ
- ๐ต
์ค์ ํ์ผ์ ์คํ ํ์ผ ๊ธฐ์ค Kimm-Car-Simulator_Data/StreamingAssets/ ํด๋์ ์์นํ๋ฉฐ, ์์ค์ฝ๋ ์์ ์์ด JSON ์์ ๋ง์ผ๋ก ๋์์ด ๋ณ๊ฒฝ๋๋ค.
{
"Metadata": {
"VehicleName": "KIMM Standard Sedan (Original Baseline)",
"Description": "์ธ์คํํฐ ์๋ณธ ๋ฐ์ดํฐ ๊ธฐ๋ฐ 45๊ฐ ์ ํํ baseline ํ๋ผ๋ฏธํฐ ์ค์ ํ์ผ",
"Version": "1.0"
},
"Parameters": {
"gnssLatitude": 35.8714,
"gnssLongitude": 128.6014,
"gnssAltitude": 45.0,
"Veh_AeroArea": 2.594,
"Veh_AeroCd": 0.2888,
"Veh_AeroCl": 0.149,
"Veh_AeroRho": 1.205,
"Veh_BodyInertia[1,1]": 600.0,
"Veh_BodyInertia[1,2]": 3000.0,
"Veh_BodyInertia[1,3]": 3200.0,
"Veh_BodyMass": 1600.0,
"Veh_BodyRefZ0": 0.6147,
"Veh_BodytoWheelCenter": 0.2647,
"Veh_FrontAxleX": 1.5,
"Veh_RearAxleX": -1.5,
"Veh_SteerRatio": 16.0,
"Veh_SuspF_BumpC": 3000.0,
"Veh_SuspF_BumpK": 200000.0,
"Veh_SuspF_BumpLimit": -0.084,
"Veh_SuspF_BumpWidth": 0.003,
"Veh_SuspF_C": 1750.0,
"Veh_SuspF_EqPos": 0.1126,
"Veh_SuspF_K": 35000.0,
"Veh_SuspF_ReboundC": 3000.0,
"Veh_SuspF_ReboundK": 200000.0,
"Veh_SuspF_ReboundLimit": 0.056,
"Veh_SuspF_ReboundWidth": 0.003,
"Veh_SuspF_UnsprungInertia[1,1]": 1.0,
"Veh_SuspF_UnsprungInertia[1,2]": 1.0,
"Veh_SuspF_UnsprungInertia[1,3]": 1.0,
"Veh_SuspF_UnsprungMass": 48.0,
"Veh_SuspR_BumpC": 4000.0,
"Veh_SuspR_BumpK": 300000.0,
"Veh_SuspR_BumpLimit": -0.095,
"Veh_SuspR_BumpWidth": 0.003,
"Veh_SuspR_C": 2200.0,
"Veh_SuspR_EqPos": 0.0985,
"Veh_SuspR_K": 40000.0,
"Veh_SuspR_ReboundC": 4000.0,
"Veh_SuspR_ReboundK": 300000.0,
"Veh_SuspR_ReboundLimit": 0.04,
"Veh_SuspR_ReboundWidth": 0.003,
"Veh_SuspR_UnsprungInertia[1,1]": 1.0,
"Veh_SuspR_UnsprungInertia[1,2]": 1.0,
"Veh_SuspR_UnsprungInertia[1,3]": 1.0,
"Veh_SuspR_UnsprungMass": 45.0,
"Veh_TrackF": 1.6,
"Veh_TrackR": 1.6
}
}๋จ์ผ ์ผ์ ๊ตฌ์ฑ ๊ธฐ์ค ๊ธฐ๋ณธ ์ค์ ํ์ผ:
{
"SensorConfigName": "KIMM Default Sensor Suite",
"_CoordinateSystem_Guide": {
"Position": "FLU Standard (x: Forward(+)/Backward(-), y: Left(+)/Right(-), z: Up(+)/Down(-))",
"Rotation": "Degrees (roll: Right(+), pitch: NoseUp(+)/NoseDown(-), yaw: TurnLeft(+)/TurnRight(-))"
},
"ROS2Connection": {
"RosIP": "127.0.0.1",
"RosPort": 10000
},
"GNSS": {
"FrameId": "gnss_frame",
"TopicName": "/kimm/gnss/fix",
"PublishFrequency": 10.0,
"InitialLatitude": 0.0,
"InitialLongitude": 0.0,
"InitialAltitude": 0.0,
"LocalPosition": { "x": 0.0, "y": 0.0, "z": 0.0 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
"IMU": {
"FrameId": "imu_frame",
"TopicName": "/kimm/imu/data",
"PublishFrequency": 100.0,
"LocalPosition": { "x": 0.0, "y": 0.0, "z": 0.0 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
"LiDAR": {
"FrameId": "lidar_frame",
"TopicName": "/kimm/lidar/points",
"PublishFrequency": 20.0,
"PointsNumPerScan": 100000,
"MinRange": 0.1,
"MaxRange": 70.0,
"GaussianNoiseSigma": 0.02,
"MaxIntensity": 255.0,
"LocalPosition": { "x": 0.0, "y": 0.0, "z": 0.6 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
"Camera": {
"FrameId": "camera_frame",
"TopicName": "/kimm/camera/color/compressed",
"CameraInfoTopic": "/kimm/camera/camera_info",
"PublishFrequency": 30.0,
"ResolutionWidth": 640,
"ResolutionHeight": 480,
"FieldOfView": 60.0,
"LocalPosition": { "x": 0.3, "y": 0.0, "z": 0.7 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
"VehicleStatus": {
"TopicName": "/kimm/vehicle_status",
"PublishFrequency": 50.0
},
"CarControlCmd": {
"TopicName": "/kimm/car_cmd"
}
}"LiDAR" ๋๋ "Camera" ํค ์๋์ ๋ฐฐ์ด [ { ... }, { ... } ] ํํ๋ก ์์ฑํ๋ฉด, ์ ๋ฐฉ/ํ๋ฐฉ ๋ผ์ด๋ค ๋ฐ ๋ค์ค ์นด๋ฉ๋ผ๊ฐ ๋ฐํ์์ ๋์ ์ผ๋ก ๊ฐ๊ฐ ์ธ์คํด์คํ๋๋ค:
{
"SensorConfigName": "KIMM Dual-Camera & Dual-LiDAR Suite",
"ROS2Connection": {
"RosIP": "127.0.0.1",
"RosPort": 10000
},
"GNSS": {
"FrameId": "gnss_frame",
"TopicName": "/kimm/gnss/fix",
"PublishFrequency": 10.0,
"InitialLatitude": 36.37561,
"InitialLongitude": 127.35921,
"InitialAltitude": 55.0,
"LocalPosition": { "x": 0.0, "y": 0.0, "z": 0.0 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
"IMU": {
"FrameId": "imu_frame",
"TopicName": "/kimm/imu/data",
"PublishFrequency": 200.0,
"LocalPosition": { "x": 0.0, "y": 0.0, "z": 0.0 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
"LiDAR": [
{
"FrameId": "front_lidar_frame",
"TopicName": "/kimm/lidar_front/points",
"PublishFrequency": 10.0,
"PointsNumPerScan": 50000,
"MinRange": 0.1,
"MaxRange": 70.0,
"GaussianNoiseSigma": 0.02,
"MaxIntensity": 255.0,
"LocalPosition": { "x": 0.3, "y": 0.0, "z": 0.6 },
"LocalRotation": { "roll": 0.0, "pitch": -15.0, "yaw": 0.0 }
},
{
"FrameId": "rear_lidar_frame",
"TopicName": "/kimm/lidar_rear/points",
"PublishFrequency": 10.0,
"PointsNumPerScan": 50000,
"MinRange": 0.1,
"MaxRange": 70.0,
"GaussianNoiseSigma": 0.02,
"MaxIntensity": 255.0,
"LocalPosition": { "x": -0.3, "y": 0.0, "z": 0.6 },
"LocalRotation": { "roll": 0.0, "pitch": -15.0, "yaw": 180.0 }
}
],
"Camera": [
{
"FrameId": "front_camera_frame",
"TopicName": "/kimm/camera_front/color/compressed",
"CameraInfoTopic": "/kimm/camera_front/camera_info",
"PublishFrequency": 30.0,
"ResolutionWidth": 640,
"ResolutionHeight": 480,
"FieldOfView": 60.0,
"LocalPosition": { "x": 0.3, "y": 0.0, "z": 0.7 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 0.0 }
},
{
"FrameId": "rear_camera_frame",
"TopicName": "/kimm/camera_rear/color/compressed",
"CameraInfoTopic": "/kimm/camera_rear/camera_info",
"PublishFrequency": 30.0,
"ResolutionWidth": 640,
"ResolutionHeight": 480,
"FieldOfView": 60.0,
"LocalPosition": { "x": -0.3, "y": 0.0, "z": 0.7 },
"LocalRotation": { "roll": 0.0, "pitch": 0.0, "yaw": 180.0 }
}
]
}| ๋งต ๋ช ์นญ (Track Name) | ํน์ง ๋ฐ ํ๊ฒฝ ๊ตฌ์ฑ | ๊ถ์ฅ ํ ์คํธ ์๋๋ฆฌ์ค |
|---|---|---|
| K-City (์์จ์ฃผํ ์คํ๋์) | ํ๊ตญ๊ตํต์์ ๊ณต๋จ(KATRI) ์ค๋๋ก ๊ธฐ๋ฐ ๊ต์ฐจ๋ก, ๊ฑด๋ฌผ, ํฐ๋ ํธ๋ | ์ฐจ์ ์ธ์, 3D LiDAR ์ฅ์ ๋ฌผ ํํผ, ๋์ฌ ์ ํธ ๊ต์ฐจ๋ก ์ฃผํ |
| Mcity (๋์ฌ ์์จ์ฃผํ ํธ๋) | ๋์ฌํ ์ธํฐ์ฒด์ธ์ง ๋ฐ ๋ณตํฉ ๋๋ก ํ๊ฒฝ ํธ๋ | ๋ณตํฉ ๊ต์ฐจ๋ก ํ์ , ๋ค์ค ๋ณดํ์/๋๋ฏธ์ฐจ๋ ๋๋ฐ ์ํฉ ๊ฒ์ฆ |
| ZalaZone (์๋ผ์กด ์ํ์ฅ) | ์ ๋ฝํ ์ค๋งํธ์ํฐ ๋ฐ ๊ณ ์ ํธ๋ค๋ง/์ ํ ์ํ ํธ๋ | ๊ณ ์ ์์จ์ฃผํ ๊ฒฝ๋ก ์ถ์ข , ๋ณตํฉ ์ฌ๋ผ๋ผ ๋ฐ ํก๋ฐฉํฅ ํธ๋ค๋ง ๊ฒ์ฆ |
| Proving Ground (PG) | ํํํ ๋ค๋ชฉ์ ์ฐจ๋ ์ข ํฉ ์ฑ๋ฅ ์ํ์ฅ ๋ฐ ์ง์ /์ ํ๋ก | ์ฐจ๋ 14-DOF ๋์ญํ ํ๊ณ ๊ฑฐ๋, ๊ธ๊ฐ์/๊ธ์ ๋, ์์คํ์ ํ๋ |