Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

ย 
ย 

Latest commit

ย 

History

137 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

KIMM Car Simulator

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.


๐Ÿ“‘ ๋ชฉ์ฐจ (Table of Contents)


๐ŸŒŸ ๊ฐœ์š” (Overview)

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 ์งํ†ต ํ†ต์‹ ์„ ์ง€์›ํ•œ๋‹ค.

โœจ ์ฃผ์š” ๊ธฐ๋Šฅ (Key Features)

๋ถ„๋ฅ˜ ์ฃผ์š” ๊ธฐ๋Šฅ ๋ฐ ๊ธฐ์ˆ  ์ŠคํŽ™
๐Ÿš— ์ฐจ๋Ÿ‰ ๋™์—ญํ•™ โ€ข 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 ์ฆ‰์‹œ ํ•ซ์Šค์™‘

๐Ÿš€ ์‹œ์ž‘ํ•˜๊ธฐ ๋ฐ ๋ฐฐํฌ๋ณธ ์‹คํ–‰ (Getting Started)

์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋Š” ๋ณ„๋„์˜ ์†Œ์Šค์ฝ”๋“œ ๋นŒ๋“œ ๊ณผ์ • ์—†์ด, ์‚ฌ์ „์— ๋นŒ๋“œ๋œ ๋…๋ฆฝ ์‹คํ–‰ ํŒจํ‚ค์ง€๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ ์ฆ‰์‹œ ๊ตฌ๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.

1. Windows ํ™˜๊ฒฝ ์‹คํ–‰

  1. ์ €์žฅ์†Œ ์šฐ์ธก์˜ Releases ํŽ˜์ด์ง€์—์„œ ์ตœ์‹  Windows ํŒจํ‚ค์ง€(Kimm-Car-Simulator_v1.0.0_Windows_x64.zip)๋ฅผ ๋‹ค์šด๋กœ๋“œํ•œ๋‹ค.
  2. ๋‹ค์šด๋กœ๋“œํ•œ .zip ์••์ถ•ํŒŒ์ผ์„ ์›ํ•˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ์— ํ•ด์ œํ•œ๋‹ค.
  3. ํด๋” ๋‚ด์˜ Kimm-Car-Simulator.exe ๋ฅผ ๋”๋ธ”ํด๋ฆญํ•˜์—ฌ ์‹คํ–‰ํ•œ๋‹ค.
  4. ํ‚ค๋ณด๋“œ(W/A/S/D) ๋˜๋Š” USB ๋ ˆ์ด์‹ฑ ํœ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผํ–‰์„ ์‹œ์ž‘ํ•œ๋‹ค.

2. Linux ํ™˜๊ฒฝ ์‹คํ–‰

  1. ์ €์žฅ์†Œ ์šฐ์ธก์˜ Releases ํŽ˜์ด์ง€์—์„œ ์ตœ์‹  Linux ํŒจํ‚ค์ง€(Kimm-Car-Simulator_v1.0.0_Linux_x64.tar.gz)๋ฅผ ๋‹ค์šด๋กœ๋“œํ•œ๋‹ค.
  2. ํ„ฐ๋ฏธ๋„์„ ์—ด๊ณ  ์••์ถ•์„ ํ•ด์ œํ•œ ํ›„ ์‹คํ–‰ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•œ๋‹ค:
    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

๐ŸŒ ROS 2 ์—ฐ๋™ ๋ฐ ํ†ต์‹  ๋ช…์„ธ (ROS 2 Integration & Topics)

Ubuntu 22.04 (Humble / Foxy) ๋˜๋Š” Windows WSL2 ํ™˜๊ฒฝ์—์„œ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ TCP ์†Œ์ผ“์œผ๋กœ ๊ณ ์† ์—ฐ๋™ํ•˜์—ฌ ์„ผ์„œ ๋ฐ์ดํ„ฐ ์ˆ˜์‹  ๋ฐ By-Wire ์ž์œจ์ฃผํ–‰ ์ œ์–ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

1. ROS-TCP-Endpoint ์„ค์น˜ ๋ฐ ๋นŒ๋“œ

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

2. KIMM ์ œ์–ด ๋ฉ”์‹œ์ง€ ํŒจํ‚ค์ง€ (kimm_msgs) ๋‹ค์šด๋กœ๋“œ ๋ฐ ๋นŒ๋“œ

์ฐจ๋Ÿ‰ 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

3. ROS-TCP-Endpoint ์„œ๋ฒ„ ์‹คํ–‰

# 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)

5. ROS 2 ํ† ํ”ฝ ์ธํ„ฐํŽ˜์ด์Šค ์ „์ฒด ๋ช…์„ธ (Topics Specification)

๊ธฐ๋ณธ ์„ผ์„œ ๊ตฌ์„ฑ(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 ์ฃผํ–‰ ๋ช…๋ น (์ˆ˜์‹ )

6. ์ž์œจ์ฃผํ–‰ ๊ฒฝ๋กœ ์ถ”์ข… ์ œ์–ด Python ์˜ˆ์ œ ์ฝ”๋“œ (pure_pursuit_demo.py)

์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ ์ฐจ๋Ÿ‰์„ ์ž์œจ์ฃผํ–‰ ์ œ์–ด ๋ชจ๋“œ(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()

๐Ÿ“ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ๋งˆ์šฐ์Šค ๋ชฉํ‘œ ํ•€(Goal Pin) ์ง€์ • ๋ฐฉ๋ฒ•

  1. ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ ์ฃผํ–‰ ์ค‘ ํ‚ค๋ณด๋“œ M ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ AUTO MODE ๋กœ ์ „ํ™˜ํ•œ๋‹ค.
  2. ๋งˆ์šฐ์Šค ์ปค์„œ๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด ๊ฐ€์ƒ ํŠธ๋ž™ ๋„๋กœ ๋ฐ”๋‹ฅ์˜ ์›ํ•˜๋Š” ์œ„์น˜๋ฅผ ๋งˆ์šฐ์Šค ์ขŒํด๋ฆญํ•œ๋‹ค.
  3. 3D ์ง€ํ˜•์— ๋ถ‰์€์ƒ‰ ๋ชฉํ‘œ ํ•€(Goal Pin ๐Ÿ“) ์ด ๊ฝ‚ํžˆ๋ฉฐ, ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋Š” ํŒจํ‚ท ์œ ์‹ค ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ROS 2 /kimm/goal_pose ํ† ํ”ฝ์„ 5ํšŒ ์—ฐ์† ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธํ•œ๋‹ค.
  4. ์‹คํ–‰ ์ค‘์ธ pure_pursuit_demo.py๊ฐ€ ์ด๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ ์ฐจ๋Ÿ‰์ด ์ฆ‰์‹œ ํ•ด๋‹น ๋ชฉํ‘œ ํ•€์„ ํ–ฅํ•ด ์ž์œจ์ฃผํ–‰์„ ์‹œ์ž‘ํ•œ๋‹ค.

๐ŸŽฎ ์กฐ์ž‘ ๋ฐ ๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด (Controls Guide)

1. ํ‚ค๋ณด๋“œ ์กฐ์ž‘ (Keyboard Controls)

ํ‚ค (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: ์ขŒ/์šฐ ์‚ฌ์ด๋“œ๋ทฐ

2. USB ๋ ˆ์ด์‹ฑ ํœ  & ๊ฒŒ์ž„ํŒจ๋“œ ๋งคํ•‘ (Racing Wheel Mapping)

  • ์Šคํ‹ฐ์–ด๋ง ํœ  / ํŽ˜๋‹ฌ: ์•„๋‚ ๋กœ๊ทธ ์กฐํ–ฅ๊ฐ ๋ฐ ๊ฐ€์†(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): ์ƒ/ํ•˜/์ขŒ/์šฐ ์นด๋ฉ”๋ผ ๋ทฐ ์ฆ‰์‹œ ์ „ํ™˜

โš™๏ธ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์„ค์ • (Configuration & Hot-Swap)

์„ค์ • ํŒŒ์ผ์€ ์‹คํ–‰ ํŒŒ์ผ ๊ธฐ์ค€ Kimm-Car-Simulator_Data/StreamingAssets/ ํด๋”์— ์œ„์น˜ํ•˜๋ฉฐ, ์†Œ์Šค์ฝ”๋“œ ์ˆ˜์ • ์—†์ด JSON ์ˆ˜์ •๋งŒ์œผ๋กœ ๋™์ž‘์ด ๋ณ€๊ฒฝ๋œ๋‹ค.

1. ์ฐจ๋Ÿ‰ ๋ฌผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ณธ ์„ค์ • (vehicle_config.json - 45๊ฐœ ๋ณ€์ˆ˜)

{
  "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
  }
}

2. ์„ผ์„œ ์Šค์œ„ํŠธ ๊ธฐ๋ณธ ์„ค์ • (default_sensor_config.json)

๋‹จ์ผ ์„ผ์„œ ๊ตฌ์„ฑ ๊ธฐ์ค€ ๊ธฐ๋ณธ ์„ค์ • ํŒŒ์ผ:

{
  "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"
  }
}

3. ๋‹ค์ค‘ ์„ผ์„œ ํ™•์žฅ ์„ค์ • ์˜ˆ์‹œ (custom_sensor_config.json)

"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 }
    }
  ]
}

๐Ÿ—บ๏ธ ์ง€์› ๋งต ๋ฐ ํŠธ๋ž™ (Supported Tracks)

๋งต ๋ช…์นญ (Track Name) ํŠน์ง• ๋ฐ ํ™˜๊ฒฝ ๊ตฌ์„ฑ ๊ถŒ์žฅ ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค
K-City (์ž์œจ์ฃผํ–‰ ์‹คํ—˜๋„์‹œ) ํ•œ๊ตญ๊ตํ†ต์•ˆ์ „๊ณต๋‹จ(KATRI) ์‹ค๋„๋กœ ๊ธฐ๋ฐ˜ ๊ต์ฐจ๋กœ, ๊ฑด๋ฌผ, ํ„ฐ๋„ ํŠธ๋ž™ ์ฐจ์„  ์ธ์‹, 3D LiDAR ์žฅ์• ๋ฌผ ํšŒํ”ผ, ๋„์‹ฌ ์‹ ํ˜ธ ๊ต์ฐจ๋กœ ์ฃผํ–‰
Mcity (๋„์‹ฌ ์ž์œจ์ฃผํ–‰ ํŠธ๋ž™) ๋„์‹ฌํ˜• ์ธํ„ฐ์ฒด์ธ์ง€ ๋ฐ ๋ณตํ•ฉ ๋„๋กœ ํ™˜๊ฒฝ ํŠธ๋ž™ ๋ณตํ•ฉ ๊ต์ฐจ๋กœ ํšŒ์ „, ๋‹ค์ค‘ ๋ณดํ–‰์ž/๋”๋ฏธ์ฐจ๋Ÿ‰ ๋Œ๋ฐœ ์ƒํ™ฉ ๊ฒ€์ฆ
ZalaZone (์ž๋ผ์กด ์‹œํ—˜์žฅ) ์œ ๋Ÿฝํ˜• ์Šค๋งˆํŠธ์‹œํ‹ฐ ๋ฐ ๊ณ ์† ํ•ธ๋“ค๋ง/์„ ํšŒ ์‹œํ—˜ ํŠธ๋ž™ ๊ณ ์† ์ž์œจ์ฃผํ–‰ ๊ฒฝ๋กœ ์ถ”์ข…, ๋ณตํ•ฉ ์Šฌ๋ผ๋Ÿผ ๋ฐ ํšก๋ฐฉํ–ฅ ํ•ธ๋“ค๋ง ๊ฒ€์ฆ
Proving Ground (PG) ํ‰ํƒ„ํ•œ ๋‹ค๋ชฉ์  ์ฐจ๋Ÿ‰ ์ข…ํ•ฉ ์„ฑ๋Šฅ ์‹œํ—˜์žฅ ๋ฐ ์ง์„ /์„ ํšŒ๋กœ ์ฐจ๋Ÿ‰ 14-DOF ๋™์—ญํ•™ ํ•œ๊ณ„ ๊ฑฐ๋™, ๊ธ‰๊ฐ€์†/๊ธ‰์ œ๋™, ์„œ์ŠคํŽœ์…˜ ํŠœ๋‹

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages