Загрузка данных


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Autonomous flight: 7x7 ArUco field, marker 42 = origin (0,0).
Clover + Gazebo.

Navigation: absolute coords in 'map' frame (no drift like navigate_target).
Altitude: fixed z=1.0 in every navigate call (no set_altitude).
LED: turns on BEFORE flying to each colored point.

Route check (x,y from marker 42, step 1 m):
  42(0,0) -> 44(2,0) -> 38(3,1) pink ->
  orange(5,2.5) -> cyan(5.5,4) -> 12(5,5) purple ->
  11(4,5) -> 17(3,4) red -> 9(2,5) -> 8(1,5) yellow ->
  green(0,3.5) -> darkblue(1.5,3) -> 38(3,1) pink -> 42(0,0) land
"""

import math
import rospy
from clover import srv
from clover.srv import SetLEDEffect
from std_srvs.srv import Trigger

FLIGHT_Z = 1.0
SPEED = 0.35
ARRIVE_DIST = 0.35
ARRIVE_TIMEOUT = 70.0
LED_PAUSE = 1.5
HOVER_PAUSE = 2.0

rospy.init_node('clover_autonomous_mission')

get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
land = rospy.ServiceProxy('land', Trigger)
set_effect = rospy.ServiceProxy('led/set_effect', SetLEDEffect)


def set_led(r, g, b):
    try:
        set_effect(effect='fill', r=r, g=g, b=b)
    except rospy.ServiceException:
        pass
    rospy.sleep(LED_PAUSE)


def wait_arrival():
    start = rospy.Time.now()
    while not rospy.is_shutdown():
        telem = get_telemetry(frame_id='navigate_target')
        dist = math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2)
        if dist < ARRIVE_DIST:
            rospy.sleep(HOVER_PAUSE)
            return True
        if (rospy.Time.now() - start).to_sec() > ARRIVE_TIMEOUT:
            rospy.logwarn('arrival timeout, dist=%.2f', dist)
            return False
        rospy.sleep(0.2)


def fly_to(x, y, label=''):
    if label:
        rospy.loginfo('fly -> %s (%.1f, %.1f, %.1f)', label, x, y, FLIGHT_Z)
    navigate(x=x, y=y, z=FLIGHT_Z, speed=SPEED, frame_id='map')
    wait_arrival()


def marker_xy(mid):
    row = mid // 7
    col = mid % 7
    return col * 1.0, (6 - row) * 1.0


def mid(a, b):
    xa, ya = marker_xy(a)
    xb, yb = marker_xy(b)
    return (xa + xb) / 2.0, (ya + yb) / 2.0


# (x, y, name, LED rgb or None)  -- LED before this leg
MISSION = [
    (marker_xy(44)[0], marker_xy(44)[1], 'marker 44', None),
    (marker_xy(38)[0], marker_xy(38)[1], 'marker 38 pink', (255, 0, 255)),
    (mid(26, 33)[0], mid(26, 33)[1], 'orange block', (255, 165, 0)),
    (mid(19, 20)[0], mid(19, 20)[1], 'cyan block', (0, 255, 255)),
    (marker_xy(12)[0], marker_xy(12)[1], 'marker 12 purple', (128, 0, 255)),
    (marker_xy(11)[0], marker_xy(11)[1], 'marker 11', None),
    (marker_xy(17)[0], marker_xy(17)[1], 'marker 17 red', (255, 0, 0)),
    (marker_xy(9)[0], marker_xy(9)[1], 'marker 9', None),
    (marker_xy(8)[0], marker_xy(8)[1], 'marker 8 yellow', (255, 255, 0)),
    (mid(14, 21)[0], mid(14, 21)[1], 'green block', (0, 255, 0)),
    (mid(22, 23)[0], mid(22, 23)[1], 'dark blue block', (0, 0, 139)),
    (marker_xy(38)[0], marker_xy(38)[1], 'marker 38 pink', (255, 0, 255)),
    (marker_xy(42)[0], marker_xy(42)[1], 'marker 42 home', None),
]


try:
    set_led(255, 255, 255)
    navigate(x=0, y=0, z=FLIGHT_Z, speed=0.4, frame_id='body', auto_arm=True)
    rospy.sleep(6.0)

    for x, y, name, color in MISSION:
        if color is not None:
            set_led(*color)
        fly_to(x, y, name)

    land()
    rospy.sleep(5.0)
    set_led(0, 0, 0)

except rospy.ROSInterruptException:
    pass
except KeyboardInterrupt:
    try:
        land()
        set_led(0, 0, 0)
    except rospy.ServiceException:
        pass