소스 정보
- 저장소
- MIUAV/vibe-coding-ros2
- 최근 소스 활동
- 2026년 4월 3일 16:42
- 감지된 SKILL.md 언어
- 중국어
- 스타
- 26
- 포크
- 2
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/MIUAV/vibe-coding-ros2 --skill ros2-bridge명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | ros2-bridge |
| description | PX4 AirSim 与 ROS2 桥接技能 - SITL/HITL 集成、无人机控制、传感器数据同步、多机协同 |
| user-invocable | true |
| argument-hint | PX4 AirSim桥接 OR PX4 ros2桥接 OR 无人机仿真 OR airsim多机 OR SITL HITL |
PX4 Autopilot + AirSim 仿真器与 ROS2 之间的通讯桥接完整指南
当需要以下帮助时使用此技能:
┌─────────────────────────────────────────────────────────────┐
│ PX4 Autopilot │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Commander │───▶│ Navigator │───▶│ Actuator │ │
│ └─────────────┘ └──────────────┘ └───────────────┘ │
└───────────┬─────────────────┬─────────────────────────────┘
│ │
▼ ▼
┌───────────────┐ ┌──────────────┐
│ AirSim API │◄─│ uORB Topics │
│ │ │ (mavlink) │
└───────┬───────┘ └──────────────┘
│ │
▼ ▼
┌───────────────┐ ┌──────────────┐
│ AirSim Sim │ │ MAVLink │
│ │ │ (ROS2) │
└───────┬───────┘ └──────┬───────┘
│ │
▼ ▼
┌───────────────┐ ┌──────────────┐
│ Sensors │ │ ROS2 │
│ (Cam/Lidar) │ │ Bridge │
└───────────────┘ └──────────────┘
# 1. 安装 AirSim
git clone https://github.com/microsoft/AirSim.git
cd AirSim
./setup.sh
./build.sh
# 2. 安装 PX4 SITL
git clone --recursive https://github.com/PX4/PX4-Autopilot.git
cd PX4-Autopilot
make px4_sitl_default
# 3. 配置 AirSim 作为 PX4 后端
export PX4_SIMULATOR=AirSim
export PX4_GAZEBO_HOSTNAME=127.0.0.1
# 安装 mavros 和 mavlink
sudo apt install -y ros-humble-mavros ros-humble-mavlink
sudo apt install -y geographiclib-tools
# 初始化 mavros 地理数据库
sudo /opt/ros/humble/lib/mavros/install_geographiclib_datasets.sh
# 源码安装(最新版本)
cd ~/ws/src
git clone -b humble https://github.com/mavlink/mavros.git
git clone -b humble https://github.com/mavlink/mavlink-ros2.git
cd ~/ws && colcon build --packages-select mavros mavros_extras
# px4_mavros.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
# mavros 节点
Node(
package='mavros',
executable='mavros_node',
name='mavros',
parameters=[{
# 链接配置
'pluginlibs': ['mavros'],
'plugin_lock_key': '',
# 系统配置
'system_id': 1,
'component_id': 1,
'mavlink_system': 1,
# 话题命名空间
'fcu_url': 'udp://:14540@127.0.0.1:14557', # PX4 SITL
# 或串口: 'serial:///dev/ttyACM0:921600'
# gz_bridge 需要这个
'fcu_protocol': 'v2.0',
# 传感器/位置源
'sensor_bitrate': 0,
'conn_timeout': 5.0,
'timeout': 5.0,
# 目标系统
'target_system_id': 1,
'target_component_id': 1,
: ,
}],
remappings=[
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
],
output=,
emulate_tty=
),
Node(
package=,
executable=,
parameters=[{
:
}]
)
])
# airsim_camera_bridge.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
# 前视相机
Node(
package='airsim_ros_pkgs',
executable='img_pub_node',
name='front_camera',
parameters=[{
'camera_name': 'front_center',
'publish_rate': 30,
'publish_via_ros2': True,
'ros2_namespace': '/drone0',
'topic_id': 'front_camera/image_raw'
}]
),
# 深度相机
Node(
package='airsim_ros_pkgs',
executable='img_pub_node',
name='depth_camera',
parameters=[{
'camera_name': 'depth_center',
'publish_rate': 15,
'publish_via_ros2': True,
'ros2_namespace': '/drone0',
'topic_id': 'depth_camera/image_raw'
}]
),
# 红外相机
Node(
package='airsim_ros_pkgs',
executable='img_pub_node',
name='seg_camera',
parameters=[{
'camera_name': ,
: ,
: ,
: ,
:
}]
),
])
# airsim_lidar_bridge.launch.py
def generate_launch_description():
return LaunchDescription([
Node(
package='airsim_ros_pkgs',
executable='lidar_pub_node',
name='lidar',
parameters=[{
'lidar_name': 'Lidar1',
'publish_rate': 10,
'publish_via_ros2': True,
'ros2_namespace': '/drone0',
'topic_id': 'lidar/scan',
'frame_id': 'lidar_link',
# 激光雷达参数
'points_per_second': 100000,
'angle_min': -3.14159,
'angle_max': 3.14159,
'range_min': 0.5,
'range_max': 100.0,
}]
)
])
# airsim_gps_imu_bridge.launch.py
def generate_launch_description():
return LaunchDescription([
# GPS
Node(
package='airsim_ros_pkgs',
executable='gps_pub_node',
name='gps',
parameters=[{
'gps_name': 'Gps1',
'publish_rate': 10,
'publish_via_ros2': True,
'ros2_namespace': '/drone0',
'topic_id': 'gps/fix'
}]
),
# IMU
Node(
package='airsim_ros_pkgs',
executable='imu_pub_node',
name='imu',
parameters=[{
'imu_name': 'Imu1',
'publish_rate': 100,
'publish_via_ros2': True,
'ros2_namespace': '/drone0',
'topic_id': 'imu/data'
}]
),
])
# drone_control.launch.py
def generate_launch_description():
return LaunchDescription([
# 起飞服务
Node(
package='mavros',
executable='mavros_node',
name='mavros_takeoff',
parameters=[{
'fcu_url': 'udp://:14540@127.0.0.1:14557',
}],
remappings=[
('/mavros/cmd/arming', '/drone0/mavros/cmd/arming'),
('/mavros/cmd/takeoff', '/drone0/mavros/cmd/takeoff'),
('/mavros/cmd/land', '/drone0/mavros/cmd/land'),
]
),
])
# drone_control.py
import rclpy
from rclpy.node import Node
from mavros_msgs.srv import CommandBool, CommandTOL, SetMode
from mavros_msgs.msg import State, GlobalPosition, LocalPosition
from geometry_msgs.msg import PoseStamped, Twist
from geographic_msgs.msg import GeoPoseStamped
class DroneController(Node):
def __init__(self, drone_name='drone0'):
super().__init__(f'{drone_name}_controller')
self.drone_name = drone_name
# 服务客户端
self.arming_client = self.create_client(CommandBool, f'/{drone_name}/mavros/cmd/arming')
self.takeoff_client = self.create_client(CommandTOL, f'/{drone_name}/mavros/cmd/takeoff')
self.land_client = self.create_client(CommandTOL, f'/{drone_name}/mavros/cmd/land')
self.set_mode_client = self.create_client(SetMode, f'/{drone_name}/mavros/set_mode')
# 订阅状态
self.state_sub = self.create_subscription(
State, f'//mavros/state', .state_callback, )
.local_pos_sub = .create_subscription(
PoseStamped, , .pos_callback, )
.cmd_vel_pub = .create_publisher(
Twist, , )
.local_pos_pub = .create_publisher(
PoseStamped, , )
.current_state =
.current_pos =
():
.current_state = msg
():
.current_pos = msg
():
client.wait_for_service(timeout_sec=):
.get_logger().info()
():
.wait_for_service(.arming_client)
req = CommandBool.Request()
req.value =
future = .arming_client.call_async(req)
rclpy.spin_until_future_complete(, future)
future.result().success
():
.wait_for_service(.takeoff_client)
req = CommandTOL.Request()
req.altitude = altitude
req.latitude =
req.longitude =
req.min_pitch =
req.yaw =
future = .takeoff_client.call_async(req)
rclpy.spin_until_future_complete(, future)
future.result().success
():
.wait_for_service(.land_client)
req = CommandTOL.Request()
future = .land_client.call_async(req)
rclpy.spin_until_future_complete(, future)
future.result().success
():
.wait_for_service(.set_mode_client)
req = SetMode.Request()
req.custom_mode = mode
future = .set_mode_client.call_async(req)
rclpy.spin_until_future_complete(, future)
future.result().mode_sent
():
cmd = Twist()
cmd.linear.x = linear[]
cmd.linear.y = linear[]
cmd.linear.z = linear[]
cmd.angular.x = angular[]
cmd.angular.y = angular[]
cmd.angular.z = angular[]
.cmd_vel_pub.publish(cmd)
():
pos = PoseStamped()
pos.header.stamp = .get_clock().now().to_msg()
pos.header.frame_id =
pos.pose.position.x = x
pos.pose.position.y = y
pos.pose.position.z = z
.local_pos_pub.publish(pos)
():
rclpy.init()
controller = DroneController()
controller.get_logger().info()
controller.arm():
controller.get_logger().info()
:
controller.get_logger().error()
controller.get_logger().info()
controller.takeoff(altitude=):
controller.get_logger().info()
:
controller.get_logger().error()
rate = controller.create_rate()
_ ():
controller.publish_cmd_vel(linear=(, , ), angular=(, , ))
rclpy.spin_once(controller)
rate.sleep()
controller.get_logger().info()
controller.land()
rclpy.shutdown()
# settings.json 配置
{
"SeeDocsAt": "https://github.com/Microsoft/AirSim/blob/main/docs/settings.md",
"SettingsVersion": 1.2,
"SimMode": "Multirotor",
"Vehicles": {
"Drone0": {
"VehicleType": "SimpleFlight",
"X": 0, "Y": 0, "Z": 0,
"Yaw": 0,
"Cameras": {
"front_center": {
"CaptureSettings": [
{
"ImageType": 0,
"Width": 640,
"Height": 480
}
]
}
}
},
"Drone1": {
"VehicleType": "SimpleFlight",
"X": 10, "Y": 0, "Z": 0,
"Yaw": 0,
"Cameras": {...}
}
}
}
# multi_drone_bridge.launch.py
def generate_launch_description():
nodes = []
# 为每架无人机启动 mavros
for i, port in enumerate([14540, 14541, 14542]):
drone_ns = f'drone{i}'
nodes.append(
Node(
package='mavros',
executable='mavros_node',
name='mavros',
namespace=drone_ns,
parameters=[{
'system_id': i + 1,
'component_id': 1,
'fcu_url': f'udp://:14540@{127.0.0.1}:{14557 + i}',
'target_system_id': i + 1,
}],
remappings=[
('/mavros/state', f'/{drone_ns}/mavros/state'),
('/mavros/local_position/pose', f'/{drone_ns}/mavros/local_position/pose'),
('/mavros/setpoint_velocity/cmd_vel_unstamped', f'/{drone_ns}/cmd_vel'),
]
)
)
return LaunchDescription(nodes)
# depth_perception.py
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image, CameraInfo
from geometry_msgs.msg import TransformStamped
from cv_bridge import CvBridge
import cv2
import numpy as np
class DepthPerception(Node):
def __init__(self):
super().__init__('depth_perception')
self.bridge = CvBridge()
# 订阅深度图像
self.depth_sub = self.create_subscription(
Image, '/drone0/depth_camera/image_raw', self.depth_callback, 10)
# 订阅 RGB 图像
self.rgb_sub = self.create_subscription(
Image, '/drone0/front_camera/image_raw', self.rgb_callback, 10)
# 发布检测结果
self.detection_pub = self.create_publisher(
Image, '/drone0/detections', 10)
self.latest_depth = None
self.latest_rgb = None
def depth_callback():
.latest_depth = .bridge.imgmsg_to_cv2(msg)
():
.latest_rgb = .bridge.imgmsg_to_cv2(msg)
.latest_depth :
depth_m = np.array(.latest_depth, dtype=np.float32)
valid_depth = depth_m[depth_m > ]
(valid_depth) > :
min_dist = valid_depth.()
max_dist = valid_depth.()
avg_dist = valid_depth.mean()
.get_logger().info(
)
depth_colored = cv2.applyColorMap(
cv2.convertScaleAbs(depth_m, alpha=), cv2.COLORMAP_JET)
out_msg = .bridge.cv2_to_imgmsg(depth_colored, )
.detection_pub.publish(out_msg)
# 检查 mavros 连接状态
ros2 service call /drone0/mavros/get_log_info mavros_msgs/srv/FileClose
# 查看 PX4 状态
ros2 topic echo /drone0/mavros/state
# 检查飞行模式
ros2 topic echo /drone0/mavros/extended_state
# airsim_api_test.py
import airsim
# 连接
client = airsim.MultirotorClient()
client.confirmConnection()
# 获取状态
state = client.getMultirotorState()
print(f"State: {state}")
# 解锁
client.armDisarm(True)
# 起飞
client.takeoff()
# 飞到目标位置
client.moveToPositionAsync(0, 0, -10, 5).join()
# 降落
client.land()
端口配置:确保 PX4 SITL 和 mavros 使用正确的 UDP 端口
时钟同步:PX4 使用仿真时钟,确保 use_sim_time:=true
多机ID:每架无人机使用不同的 system_id
安全检查:飞行前确认无人机状态
GPS原点:AirSim 中设置与 ROS2 地图一致的 GPS 原点
| 问题 | 原因 | 解决方案 |
|---|---|---|
| mavros 连接失败 | 端口被占用 | 检查 PX4 是否启动 |
| 无人机不响应 | 未解锁 | 调用 arming 服务 |
| 位置漂移 | GPS 未同步 | 设置一致的 GPS 原点 |
| 相机无数据 | AirSim 插件未加载 | 检查 settings.json |