You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.4 KiB
Python

"""
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. 易於測試和維護
"""