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


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Автономный полёт по трассе на полигоне ArUco-меток (7×7, маркеры 0–48).
Платформа: Clover + Gazebo + ROS (simple_offboard).

Маршрут:
  42 (взлёт, белый LED) → 44 → 38 (розовый) →
  правый борт (оранжевый, голубой) → 12 (фиолетовый) →
  11 → 17 (красный) → 9 → 8 (жёлтый) →
  левый борт (зелёный, тёмно-синий) → 38 (розовый) →
  42 (посадка, LED выкл.)
"""

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.8             # скорость, м/с
TOLERANCE = 0.25        # допуск достижения точки, м
ARUCO_MAP_WAIT = 5.0    # ожидание появления фрейма aruco_map после взлёта, с

# --- ROS-сервисы ---
rospy.init_node('autonomous_flight')

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, effect='fill'):
    """Включить светодиодную ленту заданным цветом (RGB 0–255)."""
    set_effect(effect=effect, r=r, g=g, b=b)


def led_off():
    set_led(0, 0, 0)


# Цвета блоков
WHITE   = (255, 255, 255)
PINK    = (255,   0, 255)
ORANGE  = (255, 128,   0)
CYAN    = (  0, 255, 255)
PURPLE  = (128,   0, 255)
RED     = (255,   0,   0)
YELLOW  = (255, 255,   0)
GREEN   = (  0, 255,   0)
DARK_BLUE = (  0,   0, 139)


def marker_xy(marker_id):
    """
    Координаты центра маркера в фрейме aruco_map.
    Начало координат — маркер №42 (левый нижний угол).
    Ось X — вправо, ось Y — вверх (к маркеру №0).
    Шаг между центрами меток — 1 м.
    """
    row = marker_id // 7   # 0 — верхний ряд (маркеры 0–6)
    col = marker_id % 7
    return col * 1.0, (6 - row) * 1.0


def midpoint(marker_a, marker_b):
    """Середина между центрами двух маркеров."""
    xa, ya = marker_xy(marker_a)
    xb, yb = marker_xy(marker_b)
    return (xa + xb) / 2.0, (ya + yb) / 2.0


# Координаты блоков, расположенных между метками
GREEN_BLOCK     = midpoint(14, 21)   # зелёный: между 14 и 21
DARK_BLUE_BLOCK = midpoint(22, 23)     # тёмно-синий: между 22 и 23
CYAN_BLOCK      = midpoint(19, 20)   # голубой: между 19 и 20
ORANGE_BLOCK    = midpoint(26, 33)   # оранжевый: между 26 и 33


def wait_arrival(tolerance=TOLERANCE):
    """Ожидание достижения целевой точки navigate."""
    while not rospy.is_shutdown():
        telem = get_telemetry(frame_id='navigate_target')
        if math.sqrt(telem.x ** 2 + telem.y ** 2 + telem.z ** 2) < tolerance:
            break
        rospy.sleep(0.2)


def fly_to(x, y, z=FLIGHT_Z, frame_id='aruco_map', speed=SPEED):
    """Полёт в точку и ожидание прибытия."""
    navigate(x=x, y=y, z=z, speed=speed, frame_id=frame_id)
    wait_arrival()


def fly_to_marker(marker_id, z=FLIGHT_Z, speed=SPEED):
    """Полёт над центром маркера."""
    fly_to(0, 0, z=z, frame_id='aruco_{}'.format(marker_id), speed=speed)


def fly_to_block(xy, color, z=FLIGHT_Z, speed=SPEED):
    """Полёт над блоком между метками с включением LED."""
    set_led(*color)
    fly_to(xy[0], xy[1], z=z, speed=speed)


def takeoff():
    """Взлёт с маркера №42 на высоту 1 м."""
    set_led(*WHITE)
    navigate(x=0, y=0, z=FLIGHT_Z, speed=0.5, frame_id='body', auto_arm=True)
    wait_arrival()
    rospy.sleep(ARUCO_MAP_WAIT)


def land_at_home():
    """Посадка на маркер №42."""
    fly_to_marker(42, z=FLIGHT_Z)
    land()
    while get_telemetry().armed:
        rospy.sleep(0.2)
    led_off()


def run_mission():
    takeoff()

    # Пролёт над №44, затем над розовым блоком на №38
    fly_to_marker(44)
    set_led(*PINK)
    fly_to_marker(38)

    # Правый борт: оранжевый → голубой → фиолетовый (№12)
    fly_to_block(ORANGE_BLOCK, ORANGE)
    fly_to_block(CYAN_BLOCK, CYAN)
    set_led(*PURPLE)
    fly_to_marker(12)

    # Над №11, затем над красным блоком на №17
    fly_to_marker(11)
    set_led(*RED)
    fly_to_marker(17)

    # Над №9, затем над жёлтым блоком на №8
    fly_to_marker(9)
    set_led(*YELLOW)
    fly_to_marker(8)

    # Левый борт: зелёный → тёмно-синий → розовый (№38)
    fly_to_block(GREEN_BLOCK, GREEN)
    fly_to_block(DARK_BLUE_BLOCK, DARK_BLUE)
    set_led(*PINK)
    fly_to_marker(38)

    land_at_home()


if __name__ == '__main__':
    try:
        run_mission()
    except rospy.ROSInterruptException:
        pass
    except KeyboardInterrupt:
        rospy.loginfo('Прерывание — посадка')
        try:
            land()
            led_off()
        except rospy.ServiceException:
            pass