""" MavlinkCommandService 使用範例 展示如何從其他 ROS2 節點調用 MAVLink 指令服務 """ import rclpy from rclpy.node import Node from std_srvs.srv import Trigger import time class MavlinkClientExample(Node): """ 範例:MAVLink Service Client 這個節點展示如何調用 MavlinkCommandService 提供的服務 """ def __init__(self): super().__init__('mavlink_client_example') # 創建 service client self.client = self.create_client( Trigger, '/mavlink/send_command_long' ) # 等待服務可用 self.get_logger().info('等待 service 可用...') self.client.wait_for_service() self.get_logger().info('Service 已連接!') def send_arm_command(self): """ 範例:發送 ARM 指令 實際使用時應該發送: - message_id = 76 (COMMAND_LONG) - command = 400 (MAV_CMD_COMPONENT_ARM_DISARM) - param1 = 1 (ARM) """ self.get_logger().info('發送 ARM 指令...') request = Trigger.Request() # TODO: 實際使用時應該是自定義的 SendCommandLong.Request # request.target_sysid = 1 # request.target_compid = 1 # request.command = 400 # MAV_CMD_COMPONENT_ARM_DISARM # request.param1 = 1.0 # 1 = ARM, 0 = DISARM # request.param2 = 0.0 # ... param3-7 # request.timeout = 3.0 # 異步調用 future = self.client.call_async(request) # 等待結果 rclpy.spin_until_future_complete(self, future) if future.done(): response = future.result() if response.success: self.get_logger().info('✓ ARM 指令發送成功') else: self.get_logger().error(f'✗ ARM 指令失敗: {response.message}') else: self.get_logger().error('✗ Service 調用超時') def main(): """主函數""" rclpy.init() # 創建客戶端節點 client = MavlinkClientExample() # 發送指令 client.send_arm_command() # 清理 client.destroy_node() rclpy.shutdown() if __name__ == '__main__': main() """ ═══════════════════════════════════════════════════════════════════════════ 進階使用範例:高層應用程式 假設我們要創建一個 "任務控制器",通過 MavlinkCommandService 來控制載具: ```python class MissionController(Node): def __init__(self): super().__init__('mission_controller') # 創建各種 service clients self.client_arm = self.create_client( SendCommandLong, '/mavlink/send_command_long') self.client_mode = self.create_client( SendCommandLong, '/mavlink/send_command_long') self.client_takeoff = self.create_client( SendCommandLong, '/mavlink/send_command_long') self.client_goto = self.create_client( SendCommandInt, '/mavlink/send_command_int') def arm_vehicle(self, sysid=1): \"\"\"解鎖載具\"\"\" request = SendCommandLong.Request() request.target_sysid = sysid request.target_compid = 1 request.command = 400 # MAV_CMD_COMPONENT_ARM_DISARM request.param1 = 1.0 # ARM future = self.client_arm.call_async(request) # 處理回應... def set_mode(self, sysid=1, mode='GUIDED'): \"\"\"設置飛行模式\"\"\" # 實現模式切換邏輯... pass def takeoff(self, sysid=1, altitude=10.0): \"\"\"起飛\"\"\" request = SendCommandLong.Request() request.target_sysid = sysid request.target_compid = 1 request.command = 22 # MAV_CMD_NAV_TAKEOFF request.param7 = altitude future = self.client_takeoff.call_async(request) # 處理回應... def goto_position(self, sysid=1, lat=0, lon=0, alt=10): \"\"\"前往指定位置\"\"\" request = SendCommandInt.Request() request.target_sysid = sysid request.target_compid = 1 request.command = 192 # MAV_CMD_DO_REPOSITION request.x = int(lat * 1e7) request.y = int(lon * 1e7) request.z = alt future = self.client_goto.call_async(request) # 處理回應... def execute_mission(self): \"\"\"執行完整任務\"\"\" # 1. 解鎖 self.arm_vehicle() time.sleep(1) # 2. 切換到 GUIDED 模式 self.set_mode(mode='GUIDED') time.sleep(1) # 3. 起飛到 10 公尺 self.takeoff(altitude=10.0) time.sleep(10) # 4. 前往目標點 self.goto_position(lat=25.033, lon=121.565, alt=10) time.sleep(30) # 5. 返回並降落 # ... ``` 這樣的設計讓高層應用可以: 1. 完全不需要知道 MAVLink 協議細節 2. 通過 ROS2 service 與載具互動 3. 模組化開發不同功能 4. 易於測試和維護 ═══════════════════════════════════════════════════════════════════════════ """