Программирование на Python

Справочник по библиотекам pioneer_sdk2 0.15.1 и pioneer_rknn 1.6.3 для вычислительного модуля Пионер Мини 2. Описаны установленные компоненты, подключение и автомат состояний, управление полётом, телеметрия, события, камеры, сервопривод, RC-каналы, нейросети на NPU и готовые примеры.

1. Установленное ПО

КомпонентВерсияПуть
Python3.12.3/usr/bin/python3
pioneer_sdk20.15.1/usr/local/lib/python3.12/dist-packages/pioneer_sdk2/
pioneer_rknn (ИИ)1.6.3/usr/local/lib/python3.12/dist-packages/pioneer_rknn/
rknn-toolkit-lite22.3.0/usr/local/lib/python3.12/dist-packages/rknnlite/
OpenCV (cv2)4.10.0/usr/lib/python3.12/dist-packages/cv2/
numpy1.26.4
pyserial / grpcio3.5 / 1.74.0

Встроенная справка SDK на русском находится в pioneer_sdk2-0.15.1.dist-info/METADATA (966 строк) — это фактически официальная документация.

Зависимости SDK: numpy==1.26.4, opencv-python==4.10.0.84, pyserial==3.5. Поддерживаются Windows 10/11, Linux, macOS (Apple Silicon).

2. Подключение и автомат состояний

from pioneer_sdk2 import Pioneer

drone = Pioneer()                                   # TCP 127.0.0.1:20556 (PlazLink)
# Pioneer(serial="/dev/ttyS3", baudrate=57600)       # прямое подключение по UART
# Pioneer(tcp="host:port", wait_callback=True, safety_command=True, logger=True)

drone.close_connection()
ПараметрОписание
serialПоследовательный порт
tcp127.0.0.1:20556
wait_callbacktrue — ждать события
safety_commandtrue — проверять состояние

При wait_callback=True и safety_command=True работает контроль последовательности ON_LAND → ARMED → IN_SKY → ON_LAND:

  • команда не из текущего состояния — игнорируется (возвращает False);
  • пропуск обязательного этапа — исключение RuntimeError;
  • контроль действует только в рамках одной программы.

3. Управление полётом

Основные команды

МетодНазначение
arm(timeout=5, retries=0)Запуск моторов (ждёт ENGINES_STARTED)
disarm()Отключение моторов
takeoff()Взлёт (ждёт TAKEOFF_COMPLETE)
land()Посадка (ждёт COPTER_LANDED)
rtl()Возврат домой
reboot_board()Перезагрузка платы
point_reached() / point_deceleration()Достижение/торможение у точки

Навигация

МетодНазначение
go_to_local_point(x, y, z, yaw, time=0)Локальная точка (м, °); time=0 — текущая скорость
go_to_local_point_body_fixed(x, y, z, yaw, time=0)Смещение относительно текущей позиции
go_to_global_point(lat, lon, alt, yaw=0)Глобальная точка по GPS
go_to_global_point_relative(lat, lon, alt, yaw)Смещение по GPS
set_yaw(yaw)Угол рыскания (°)
set_manual_speed(vx, vy, vz, yaw_rate, interval=1.0)Скорость (м/с, рад/с) в глоб. СК
set_manual_speed_body_fixed(...)Скорость относительно корпуса

Состояние и параметры

from pioneer_sdk2 import Pioneer, FlyState, NavSystem

state = drone.get_fly_state()          # ON_LAND / ARMED / IN_SKY
nav   = drone.get_nav_system()         # GPS / LPS / OPT
drone.set_param("Copter_flyWithoutRc", 1.0)
drone.led_control(255, 0, 1, 0)          # все LED — зелёный
drone.grab_open(velocity=100)

4. Телеметрия и датчики

МетодРезультат
get_battery_status()tuple(напряжение, температура) | None
get_orientation()tuple(roll, pitch, yaw)
get_accel() / get_gyro() / get_mag()tuple(x, y, z)
get_altitude()высота, м
get_dist_sensor_data()дальность (ToF), м
get_motors_rpm()list[4] оборотов
get_ranger_data()(право, лево, вперёд, назад, верх/низ), м
get_local_position_lps() / get_local_velocity_lps()tuple(x, y, z) / tuple(vx, vy, vz)
get_local_yaw_lps()угол, −180…+180°
get_nav_status_lps() / get_nav_status_gps()NO_DATA / CANNOT / LOW / OK
get_optical_data()tuple[int, int, float] (оптический поток)
get_global_position_gps() / get_global_velocity_gps()координаты / скорости (GPS)
get_satellites_count()tuple(GPS, ГЛОНАСС)
time() / uptime() / flight_time()секунды

Классы состояний

  • FlyState: ON_LAND, ARMED, IN_SKY
  • NavSystem: GPS, LPS, OPT
  • NavStatus: NO_DATA, CANNOT, LOW, OK

5. События и field_watcher

from pioneer_sdk2 import Pioneer, Event

def on_point(ev):
    print("Точка достигнута")

drone.subscribe(on_point, Event.POINT_REACHED)

# подписка на изменение произвольного поля телеметрии
watcher = {"comp": "SmartBoard", "field": "rcServo",
           "callback": lambda v: print("rcServo =", v),
           "last_value": None}
drone.field_watcher.append(watcher)

Список событий Event: ALL, COPTER_LANDED, LOW_VOLTAGE1, LOW_VOLTAGE2, LOW_CHARGE, POINT_REACHED, POINT_DECELERATION, TAKEOFF_COMPLETE, ENGINES_STARTED, SHOCK.

6. Камеры и запись

from pioneer_sdk2 import Camera, CameraType, ImageViewer, RecorderControl

cam = Camera(CameraType.MAIN)            # MAIN / OPT (из board_config.json)
frame = cam.get_cv_frame(timeout=5.0)   # numpy BGR

iv = ImageViewer()                       # публикация в RTSP mediamtx
iv.imshow("test", frame)                 # rtsp://localhost:8554/test

rec = RecorderControl()
rec.get_camera_recording_configs(CameraType.MAIN)   # [RecordingConfig(w,h,fps)]
rec.start_recording(CameraType.MAIN, output_dir="/mnt/media/videos/")
rec.take_photo("shot.jpg", CameraType.MAIN, output_dir="/mnt/media/photos/")
rec.stop_recording(CameraType.MAIN)

cam.stop(); iv.close()
ДрайверОсобенность
gstreamerзахват из shared memory /tmp/{maincamera,optcamera}; поддерживает ImageViewer
rtspCamera(camera_type, camera_ip="10.42.0.1:8554")

Режимы записи/фото берутся из board_config.json (поле recordable): MAIN — до 4K/2K/FullHD/720p, OPT — 1280×800. Запись идёт через pm2-jmp-camera-control.

7. Сервопривод камеры

from pioneer_sdk2 import ServoCamera, ServoPriority

servo = ServoCamera()
servo.set_angle(-45, ServoPriority.HIGH)   # диапазон -80…+30°, HIGH/MEDIUM/LOW

Команда уходит в Unix-сокет /tmp/servo.sock и исполняется службой pwm-servo (PWM chip0).

8. RC-каналы

Перед использованием требуется выставить параметры автопилота:

Copter_man_rcMode0 = 6.0
Copter_man_rcMode1 = 3.0
Copter_man_rcMode2 = 3.0
Copter_flyWithoutRc = 1.0
SensorMux_rc = 2.0

# непрерывная отправка каналов для поддержания связи
drone.send_rc_channels(channel_1=0, channel_2=0, channel_3=0,
                       channel_4=0, channel_5=1)
ch5, ch7 = drone.rc_sdk1_to_sdk2(...)   # конвертация из SDK1
  • channel_1 — правый джойстик: −1 влево, 0, +1 вправо
  • channel_2 — правый джойстик: −1 вперёд, 0, +1 назад
  • channel_3 — левый джойстик: −1 вниз, 0, +1 вверх
  • channel_4 — левый джойстик: +1 влево, 0, −1 вправо
  • channel_5 — режим управления; 6–8 — дополнительные

9. ИИ на NPU (pioneer_rknn)

Модели берутся из локального реестра http://127.0.0.1:7777/model (Flask) либо по пути к .rknn файлу.

from pioneer_rknn import Yolo, YoloPose, PaddleOCR, ModelRegistry

model = Yolo(model_name="yolov8n", object_thresh=0.5)     # arch: yolov8, yolov11
boxes, classes, scores = model.run([img])            # img: (1,640,640,3) uint8 BGR
model.release()

pose = YoloPose(model_name="yolov8n-pose")            # 17 кейпойнтов COCO
ocr  = PaddleOCR(det_model_name="PP-OCRv5_mobile_det",
                 rec_model_name="eslav_PP-OCRv5_mobile_rec")
boxes, texts = ocr.run(img)                          # [(текст, уверенность), …]

Доступные модели в реестре

ИмяАрхитектураВерсия
yolov8nyolov81.0.0
yolov8n-poseyolov8-pose1.0.0
PP-OCRv5_mobile_detPP-OCRv5_mobile_det0.0.0
eslav_PP-OCRv5_mobile_recPP-OCRv5_mobile_rec0.0.0

Управление реестром

reg = ModelRegistry()
reg.list_model()
reg.get_model_info("yolov8n")
reg.upload_model("my_model", "1.0.0", "model.rknn", "yolov8")
reg.delete_model("my_model")

ModelContainer сам определяет чип по /proc/device-tree/compatible (RK3576) и запускает инференс на NPU-ядре.

Класс ключевых точек YoloPose: NOSE 0, LEFT/RIGHT_EYE 1/2, LEFT/RIGHT_EAR 3/4, LEFT/RIGHT_SHOULDER 5/6, LEFT/RIGHT_ELBOW 7/8, LEFT/RIGHT_WRIST 9/10, LEFT/RIGHT_HIP 11/12, LEFT/RIGHT_KNEE 13/14, LEFT/RIGHT_ANKLE 15/16.

10. Визуальное программирование (Blockly)

pioneer-bricks (порт 2020) хранит программы как Blockly-XML и генерирует Python. Пример flight_test использует блоки:

  • start_block
  • preflight
  • take_off
  • go_local_point
  • controls_whileUntil
  • not_point_reached
  • cam_get_cv_frame
  • imshow
  • landing

Эквивалент на Python:

pioneer.arm()
pioneer.takeoff()
pioneer.go_to_local_point(0, 1, 1, 0, 0)
while not pioneer.point_reached():
    img = cam_main.get_cv_frame()
    iv.imshow("test", img)
pioneer.land()

11. Готовые примеры на борту

ФайлЧто показывает
/home/pioneermini/workspace/py.pyМаршрут по точкам с подпиской на POINT_REACHED
/opt/scripts/test_nn.pyYOLO + ArUco + OpenCV, LED-индикация (многопоточно)
/opt/scripts/servo_rc_trigger.pyСерво по RC-триггеру через field_watcher
/opt/scripts/servo_example.pyРучное управление углом серво
/opt/tests/cam/*.pyТесты камер, ToF (lasercam.py), EEPROM, серво
pioneer-bricks/static/save/flight_test/Пример блочной программы (XML + Python)

Запуск: python3 файл.py по SSH либо через code-server на http://10.42.1.1:9999 (рабочая папка /home/pioneermini/workspace).

12. Полные примеры

Маршрут по точкам (py.py)

from pioneer_sdk2 import Pioneer
import pioneer_sdk2, threading, time

drone = Pioneer()
point_event = threading.Event()

def point_reached(event): point_event.set()

drone.subscribe(point_reached, pioneer_sdk2.Event.POINT_REACHED)

try:
    drone.arm()
    drone.takeoff()
    time.sleep(3)
    for (x, y) in [(0,0), (1,0), (1,2), (-1,2), (-1,0), (0,0)]:
        drone.go_to_local_point(x=x, y=y, z=1, yaw=0, time=3)
        point_event.wait(); point_event.clear()
    drone.land()
except KeyboardInterrupt:
    drone.land()
finally:
    drone.close_connection()

YOLO + ArUco (фрагмент test_nn.py)

from pioneer_sdk2 import Camera, ImageViewer, Pioneer
from pioneer_rknn import Yolo
import cv2, numpy as np

model = Yolo(model_name="yolov8n", object_thresh=0.5)
cam   = Camera()
iv    = ImageViewer()
aruco = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_ARUCO_ORIGINAL)

while True:
    img = cam.get_cv_frame()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    boxes, classes, scores = model.run([np.expand_dims(cv2.resize(img, [640,640]), 0)])
    corners, ids, _ = cv2.aruco.detectMarkers(gray, aruco)
    iv.imshow("XYZ", img)

13. Нюансы и требования

  • SDK требует поднятого plazlink-core (мост к полётному контроллеру по ttyS3).
  • Камеры требуют media-server (mediamtx) и shared memory /tmp/maincamera, /tmp/optcamera.
  • Запись/фото — только при установленном pm2-jmp-camera-control.
  • GPS-методы — при наличии модуля GNSS; ranger/grab — при установленной нагрузке (в board_config.json: ranger=true, grab=true, cargo=false).
  • CameraType генерируется динамически из секции cameras файла board_config.json.
  • Событийное управление позволяет реализовать неблокирующую логику.