commit fbdcc5528e0ac792614e657d7cce7919db1379a0 Author: chyoo Date: Tue Sep 22 09:48:29 2026 +0900 feat: add Yahboom vehicle module for LMS diff --git a/.autonomy-studio-module.json b/.autonomy-studio-module.json new file mode 100644 index 0000000..80550f3 --- /dev/null +++ b/.autonomy-studio-module.json @@ -0,0 +1,8 @@ +{ + "sourceType": "GIT", + "name": "NAV2-Yahboom", + "category": "Vehicle", + "dockerImage": "future-nav2:humble-yahboom", + "packageName": "yahboom_vehicle", + "launchFile": "vehicle.launch.py" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ecbae9e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +install/ +log/ +__pycache__/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..44dfd05 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# NAV2-Yahboom + +LMS 전용 템플릿 저장소입니다. 설치 폴더: `[lms-nav2-yahboom-vehicle]yahboom_vehicle_v1.0.0_ws` + +- 패키지: `yahboom_vehicle` +- 런치: `vehicle.launch.py` +- 이미지: `future-nav2:humble-yahboom` +- 앱의 야붐 실행기 지원이 반영되어야 합니다. +- 서버 과정의 야붐 전용 환경에 이 모듈과 이미지 아티팩트를 등록한 후 + LMS에서 설치 -> 빌드 -> 실행합니다. +- ROS_DOMAIN_ID는 ESP32 설정과 일치시킵니다. GPU 가속은 끕니다. +- 컨테이너 장치: 없음 +- SLAM과 Localization은 동시에 실행하지 않습니다. +- 실차 검증 전 소스입니다. 바퀴를 띄우고 비상정지와 명령 타임아웃을 확인하세요. + +원본 소스: https://github.com/KingKiser/hkit_yahboom_ws +작성자 박승휘, 원본 package.xml 저작자 Leo Cho, 원본 라이선스 표기 Apache 2.0. +재배포 전 자산 라이선스를 확인하세요. diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7d66537 --- /dev/null +++ b/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +MODULE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RUNTIME_ROOT="${AUTONOMY_STUDIO_RUNTIME_ROOT:-$HOME/autonomy-studio/runtime/nav2}" +FOLDER_NAME="$(basename "$MODULE_PATH")" +IMAGE="${NAV2_DOCKER_IMAGE:-future-nav2:humble-yahboom}" +exec bash "$RUNTIME_ROOT/docker/docker_build_nav2.sh" "$(dirname "$MODULE_PATH")" "$FOLDER_NAME" "$IMAGE" "${ROS_DOMAIN_ID:-20}" diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..ef2acf7 --- /dev/null +++ b/run.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +MODULE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RUNTIME_ROOT="${AUTONOMY_STUDIO_RUNTIME_ROOT:-$HOME/autonomy-studio/runtime/nav2}" +FOLDER_NAME="$(basename "$MODULE_PATH")" +IMAGE="${NAV2_DOCKER_IMAGE:-future-nav2:humble-yahboom}" +ROS_PARAM='' +CONTAINER_NAME="${FOLDER_NAME#\[}" +CONTAINER_NAME="${CONTAINER_NAME/\]/-}" +CONTAINER_NAME="${CONTAINER_NAME%_ws}" +read -r -a DEFAULT_ARGS <<< "$ROS_PARAM" +exec bash "$RUNTIME_ROOT/docker/docker_run_nav2.sh" "$CONTAINER_NAME" "$(dirname "$MODULE_PATH")" "$FOLDER_NAME" "$IMAGE" "${ROS_DOMAIN_ID:-20}" "${GPU_ENABLED:-false}" "${DEFAULT_ARGS[@]}" "$@" diff --git a/src/yahboom_vehicle/CMakeLists.txt b/src/yahboom_vehicle/CMakeLists.txt new file mode 100644 index 0000000..3a8cecc --- /dev/null +++ b/src/yahboom_vehicle/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.8) +project(yahboom_vehicle) +find_package(ament_cmake REQUIRED) +install(DIRECTORY launch urdf meshes DESTINATION share/${PROJECT_NAME}) +install(PROGRAMS scripts/odom_bridge.py DESTINATION lib/${PROJECT_NAME}) +ament_package() diff --git a/src/yahboom_vehicle/launch/vehicle.launch.py b/src/yahboom_vehicle/launch/vehicle.launch.py new file mode 100644 index 0000000..3efe3d4 --- /dev/null +++ b/src/yahboom_vehicle/launch/vehicle.launch.py @@ -0,0 +1,22 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +from launch_ros.parameter_descriptions import ParameterValue + +def generate_launch_description(): + share = get_package_share_directory("yahboom_vehicle") + with open(os.path.join(share, "urdf", "yahboom.urdf"), encoding="utf-8") as stream: + description = stream.read() + return LaunchDescription([ + DeclareLaunchArgument("publish_odom_tf", default_value="true"), + Node(package="robot_state_publisher", executable="robot_state_publisher", + parameters=[{"robot_description": description, "use_sim_time": False}], + output="screen"), + Node(package="yahboom_vehicle", executable="odom_bridge.py", output="screen", + parameters=[{"publish_odom_tf": ParameterValue( + LaunchConfiguration("publish_odom_tf"), value_type=bool)}]), + ]) diff --git a/src/yahboom_vehicle/meshes/base_link.STL b/src/yahboom_vehicle/meshes/base_link.STL new file mode 100644 index 0000000..b0ec8c4 Binary files /dev/null and b/src/yahboom_vehicle/meshes/base_link.STL differ diff --git a/src/yahboom_vehicle/meshes/imu_Link.STL b/src/yahboom_vehicle/meshes/imu_Link.STL new file mode 100644 index 0000000..bd786a3 Binary files /dev/null and b/src/yahboom_vehicle/meshes/imu_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/jq1_Link.STL b/src/yahboom_vehicle/meshes/jq1_Link.STL new file mode 100644 index 0000000..993578f Binary files /dev/null and b/src/yahboom_vehicle/meshes/jq1_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/jq2_Link.STL b/src/yahboom_vehicle/meshes/jq2_Link.STL new file mode 100644 index 0000000..4086006 Binary files /dev/null and b/src/yahboom_vehicle/meshes/jq2_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/radar_Link.STL b/src/yahboom_vehicle/meshes/radar_Link.STL new file mode 100644 index 0000000..ea83ba2 Binary files /dev/null and b/src/yahboom_vehicle/meshes/radar_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/radar_Link3x.STL b/src/yahboom_vehicle/meshes/radar_Link3x.STL new file mode 100644 index 0000000..4825e5b Binary files /dev/null and b/src/yahboom_vehicle/meshes/radar_Link3x.STL differ diff --git a/src/yahboom_vehicle/meshes/yh_Link.STL b/src/yahboom_vehicle/meshes/yh_Link.STL new file mode 100644 index 0000000..fd2331b Binary files /dev/null and b/src/yahboom_vehicle/meshes/yh_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/yq_Link.STL b/src/yahboom_vehicle/meshes/yq_Link.STL new file mode 100644 index 0000000..72c2bcc Binary files /dev/null and b/src/yahboom_vehicle/meshes/yq_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/zh_Link.STL b/src/yahboom_vehicle/meshes/zh_Link.STL new file mode 100644 index 0000000..5b661ac Binary files /dev/null and b/src/yahboom_vehicle/meshes/zh_Link.STL differ diff --git a/src/yahboom_vehicle/meshes/zq_Link.STL b/src/yahboom_vehicle/meshes/zq_Link.STL new file mode 100644 index 0000000..86af5c6 Binary files /dev/null and b/src/yahboom_vehicle/meshes/zq_Link.STL differ diff --git a/src/yahboom_vehicle/package.xml b/src/yahboom_vehicle/package.xml new file mode 100644 index 0000000..6dc15c7 --- /dev/null +++ b/src/yahboom_vehicle/package.xml @@ -0,0 +1,17 @@ + + + yahboom_vehicle + 1.0.0 + Yahboom LMS vehicle module, adapted from hkit_yahboom_ws. + FutureDrive + Apache-2.0 + ament_cmake + launch + launch_ros + ament_index_python + rclpy + nav_msgs + tf2_ros + robot_state_publisher + ament_cmake + diff --git a/src/yahboom_vehicle/scripts/odom_bridge.py b/src/yahboom_vehicle/scripts/odom_bridge.py new file mode 100644 index 0000000..b56d545 --- /dev/null +++ b/src/yahboom_vehicle/scripts/odom_bridge.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# Adapted from hkit_yahboom_ws/amr_server/odom_tf_broadcaster.py. +import copy +import rclpy +from rclpy.node import Node +from rclpy.qos import qos_profile_sensor_data +from nav_msgs.msg import Odometry +from geometry_msgs.msg import TransformStamped +from tf2_ros import TransformBroadcaster + + +class OdomBridge(Node): + def __init__(self): + super().__init__("yahboom_odom_bridge") + self.publish_tf = self.declare_parameter("publish_odom_tf", True).value + self.source_frame = self.declare_parameter("source_frame", "odom_frame").value + self.source_child = self.declare_parameter("source_child", "base_footprint").value + self.tf = TransformBroadcaster(self) + self.publisher = self.create_publisher(Odometry, "/odom", 10) + self.subscription = self.create_subscription( + Odometry, "/odom_raw", self.on_odom, qos_profile_sensor_data) + + def on_odom(self, incoming): + if (incoming.header.frame_id != self.source_frame + or incoming.child_frame_id != self.source_child): + self.get_logger().warning( + "Unexpected /odom_raw frames; check source_frame/source_child", + throttle_duration_sec=5.0) + return + message = copy.deepcopy(incoming) + # Rename the known wheel-odometry frame consistently for LMS and Nav2. + message.header.frame_id = "odom" + message.child_frame_id = "base_footprint" + self.publisher.publish(message) + if self.publish_tf: + transform = TransformStamped() + transform.header = message.header + transform.child_frame_id = message.child_frame_id + transform.transform.translation.x = message.pose.pose.position.x + transform.transform.translation.y = message.pose.pose.position.y + transform.transform.translation.z = message.pose.pose.position.z + transform.transform.rotation = message.pose.pose.orientation + self.tf.sendTransform(transform) + + +def main(): + rclpy.init() + node = OdomBridge() + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + finally: + node.destroy_node() + rclpy.shutdown() + + +if __name__ == "__main__": + main() diff --git a/src/yahboom_vehicle/urdf/yahboom.urdf b/src/yahboom_vehicle/urdf/yahboom.urdf new file mode 100644 index 0000000..5691282 --- /dev/null +++ b/src/yahboom_vehicle/urdf/yahboom.urdf @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stop.sh b/stop.sh new file mode 100755 index 0000000..f439c76 --- /dev/null +++ b/stop.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +MODULE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RUNTIME_ROOT="${AUTONOMY_STUDIO_RUNTIME_ROOT:-$HOME/autonomy-studio/runtime/nav2}" +FOLDER_NAME="$(basename "$MODULE_PATH")" +IMAGE="${NAV2_DOCKER_IMAGE:-future-nav2:humble-yahboom}" +CONTAINER_NAME="${FOLDER_NAME#\[}" +CONTAINER_NAME="${CONTAINER_NAME/\]/-}" +CONTAINER_NAME="${CONTAINER_NAME%_ws}" +docker stop -t 10 "$CONTAINER_NAME"