Примеры и поддержка
Готовые программы роботов и устранение неполадок

Примеры роботов
Готовые шаблоны программ для типовых устройств. Перед запуском создайте params.json с адресом сервера (см. Конфигурация ). 
 Пример 1. Светодиодная лампа (тип LED) 
 Страница LED в веб-интерфейсе позволяет выбрать цвет ( #RRGGBB ) и яркость (0–100 %). Робот хранит текущее состояние и возвращает его в телеметрии. 
 from artex_robot import Robot

robot = Robot({"type": "LED", "name": "lamp-01", "telem_can": True})
robot.log.set_level("skip_TODO")

state = {"color": "#FFFFFF", "brightness": 100}

def hex_to_rgb(value):
 value = value.lstrip("#")
 return tuple(int(value[i:i + 2], 16) for i in (0, 2, 4))

@robot.com_handler
def on_command(type_command, command, author=None):
 robot.log("INFO", f"LED: {type_command}={command} от {author}")
 if isinstance(command, str) and command.startswith("#") and len(command) == 7:
 state["color"] = command.upper()
 elif isinstance(command, (int, float)) or (isinstance(command, str) and command.isdigit()):
 state["brightness"] = max(0, min(100, int(command)))
 # здесь — вывод на реальный светодиод (PWM, NeoPixel и т.п.)
 r, g, b = hex_to_rgb(state["color"])
 k = state["brightness"] / 100
 print("RGB:", int(r * k), int(g * k), int(b * k))

@robot.telemetry("led")
def report():
 return dict(state)

@robot.mainloop
def loop(ctx):
 report()

robot.init_connector()
robot.start()
 
 Формат команд цвета и яркости зависит от версии веб-интерфейса — проверьте его по журналу робота (сообщение recieved command from ... ) и при необходимости поправьте разбор в on_command . 
 Пример 2. Колёсный робот с камерой (Raspberry Pi) 
 Робот на двух моторах (драйвер L298N / TB6612), FPV-камера, контроль заряда АКБ, остановка при потере команд. 
 import time
import cv2
from gpiozero import Robot as Chassis # pip install gpiozero
from artex_robot import Robot

robot = Robot({"type": "Robot", "name": "tank-01",
 "telem_can": True, "video_can": True,
 "max_main_freq": 0.05, "max_send_freq": 0.05})
robot.log.set_level("skip_TODO")

chassis = Chassis(left=(17, 18), right=(22, 23)) # номера GPIO — по схеме робота
cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

robot["speed"] = 0.6
robot["last_cmd"] = 0.0
COMMAND_TIMEOUT = 0.5

MOVES = {
 "forward": lambda s: chassis.forward(s),
 "back": lambda s: chassis.backward(s),
 "left": lambda s: chassis.left(s),
 "right": lambda s: chassis.right(s),
 "stop": lambda s: chassis.stop(),
}

@robot.com_handler
def on_command(type_command, command, author=None):
 if isinstance(command, str) and command.startswith("speed:"):
 robot["speed"] = int(command.split(":")[1]) / 100
 return
 move = MOVES.get(command)
 if move is None:
 robot.log("WARN", f"Неизвестная команда: {command}")
 return
 move(robot["speed"])
 robot["last_cmd"] = time.monotonic()

@robot.telemetry("battery")
def read_battery():
 return 11.9 # замените чтением АЦП (например, ADS1115)

@robot.telemetry("motion")
def read_motion():
 return {"left": chassis.left_motor.value, "right": chassis.right_motor.value}

@robot.video("rgb")
def send_frame(frame):
 return frame

@robot.mainloop
def loop(ctx):
 # сторожевой таймер: нет команд — стоим
 if time.monotonic() - ctx["last_cmd"] > COMMAND_TIMEOUT:
 chassis.stop()

 read_battery()
 read_motion()

 ok, frame = cam.read()
 if ok:
 send_frame(frame)

try:
 robot.init_connector()
 robot.start()
finally:
 chassis.stop()
 cam.release()
 
 Пример 3. Виртуальный робот (без оборудования) 
 Робот-симулятор: хранит координаты и курс, рисует «вид сверху» в кадр и передаёт телеметрию. Подходит для отладки интерфейса, моделей ИИ и сервера без реального железа. 
 import math, time
import numpy as np, cv2
from artex_robot import Robot

robot = Robot({"type": "Robot", "name": "sim-01",
 "telem_can": True, "video_can": True})
robot.log.set_level("skip_TODO")

sim = {"x": 0.0, "y": 0.0, "heading": 0.0, "v": 0.0, "w": 0.0, "battery": 12.6}
ACTIONS = {"forward": (0.5, 0), "back": (-0.5, 0), "left": (0, 1.2),
 "right": (0, -1.2), "stop": (0, 0)}

@robot.com_handler
def on_command(type_command, command, author=None):
 if command in ACTIONS:
 sim["v"], sim["w"] = ACTIONS[command]

@robot.telemetry("pose")
def pose():
 return {k: round(sim[k], 3) for k in ("x", "y", "heading")}

@robot.telemetry("battery")
def battery():
 return round(sim["battery"], 2)

@robot.video("rgb")
def render(frame):
 return frame

def draw():
 img = np.full((360, 360, 3), 40, np.uint8)
 cx, cy = int(180 + sim["x"] * 40), int(180 - sim["y"] * 40)
 hx = int(cx + 15 * math.cos(sim["heading"]))
 hy = int(cy - 15 * math.sin(sim["heading"]))
 cv2.circle(img, (cx, cy), 12, (0, 200, 255), -1)
 cv2.line(img, (cx, cy), (hx, hy), (255, 255, 255), 2)
 return img

@robot.mainloop
def loop(ctx):
 dt = 0.1
 sim["heading"] += sim["w"] * dt
 sim["x"] += sim["v"] * math.cos(sim["heading"]) * dt
 sim["y"] += sim["v"] * math.sin(sim["heading"]) * dt
 sim["battery"] = max(10.0, sim["battery"] - 0.0005 - 0.002 * abs(sim["v"]))
 pose(); battery(); render(draw())

robot.init_connector()
robot.start()
 
 Пример 4. Бортовая модель ИИ: признаки в телеметрии 
 Бортовой компьютер может сам обрабатывать видео и отправлять на сервер не только кадры, но и выделенные признаки — например, результаты детекции. Модели ИИ на сервере получают их вместе с телеметрией. 
 from ultralytics import YOLO # pip install ultralytics
model = YOLO("yolov8n.pt") # лёгкая модель для бортового компьютера

@robot.telemetry("detections")
def detections(frame):
 result = model(frame, verbose=False)[0]
 return [
 {"cls": result.names[int(b.cls)], "conf": round(float(b.conf), 2),
 "xyxy": [round(v) for v in b.xyxy[0].tolist()]}
 for b in result.boxes
 ]

@robot.mainloop
def loop(ctx):
 ok, frame = ctx["cam"].read()
 if ok:
 send_frame(frame)
 detections(frame)
 
 На слабых бортовых компьютерах запускайте детекцию не на каждом кадре (например, раз в 3–5 итераций) или переносите её в вычислительную среду платформы — см. книгу «Управление роботами с помощью ИИ».

Устранение неполадок
Частые проблемы 
 
 
 
 Симптом 
 Причина 
 Решение 
 
 
 
 
 ModuleNotFoundError: No module named 'cv2' при импорте SDK 
 OpenCV не входит в зависимости пакета 
 pip install opencv-python (или opencv-python-headless ) и numpy 
 
 
 AttributeError: 'Conductor' object has no attribute 'command_handler' 
 Не объявлен обработчик команд до init_connector() 
 Объявите функцию с декоратором @robot.com_handler (можно пустую) 
 
 
 AttributeError: ... 'main_loop_func' 
 Не объявлен основной цикл 
 Объявите функцию с декоратором @robot.mainloop 
 
 
 TypeError: ... takes 0 positional arguments but 1 was given в основном цикле 
 Функция основного цикла не принимает context 
 def loop(context): ... 
 
 
 socketio.exceptions.ConnectionError при запуске 
 Сервер недоступен или неверный адрес 
 Проверьте server и port в params.json , доступность сервера: curl http://<сервер>:<порт>/socket.io/?EIO=4&transport=polling 
 
 
 Робот не находит сервер artex.arcon 
 Не настроено имя по умолчанию 
 Укажите IP-адрес сервера в params.json или добавьте запись в /etc/hosts 
 
 
 Ошибка OpenCV !_img.empty() в imencode 
 В функцию @robot.video передан/возвращён пустой кадр ( None ) 
 Проверяйте результат cam.read() перед отправкой кадра 
 
 
 Параметры из params.json не применяются 
 Программа запущена из другого каталога 
 Запускайте из каталога с params.json или задайте WorkingDirectory в systemd 
 
 
 Консоль заполнена сообщениями [TODO] 
 Уровень журнала all 
 "logger_level": "skip_TODO" или robot.log.set_level("skip_TODO") 
 
 
 Робот в списке, но видео/телеметрии нет 
 Сервер не прислал Ready , или функции-источники не вызываются в основном цикле 
 Проверьте в журнале сообщение in heartbeat recieved [...] ; вызовите функции @robot.telemetry / @robot.video в @robot.mainloop 
 
 
 Команды не доходят до обработчика 
 Робот ещё не получил Ready 
 Дождитесь heartbeat; проверьте журнал на recieved command 
 
 
 Видео отстаёт или «рвётся» 
 Слишком большие кадры для канала 
 Уменьшите разрешение (например, 320×240), увеличьте max_send_freq до 0.1 
 
 
 Программа «висит» без связи после перезапуска сервера 
 SDK исчерпал 5 попыток переподключения 
 Используйте сторожевую проверку (ниже) и автоперезапуск через systemd 
 
 
 Обработчик команд подтормаживает 
 Долгие операции в com_handler блокируют приём событий 
 Выполняйте долгие действия в отдельном потоке, в обработчике только меняйте состояние 
 
 
 
 Сторожевая проверка соединения 
 SDK делает 5 попыток переподключения. Если сервер был недоступен дольше, соединение не восстановится само. Завершите программу — systemd перезапустит её, и подключение будет выполнено заново: 
 import os, time

DISCONNECT_LIMIT = 30 # секунд

@robot.mainloop
def loop(ctx):
 if robot.sio.sio.connected:
 ctx["online_at"] = time.monotonic()
 elif time.monotonic() - ctx.get("online_at", time.monotonic()) > DISCONNECT_LIMIT:
 robot.log("ERROR", "Нет связи с сервером, перезапуск")
 stop_motors()
 os._exit(1)
 ...
 
 Ошибки в основном цикле 
 SDK не перехватывает исключения в функции основного цикла — любая ошибка завершает программу. Для долгой автономной работы оборачивайте опасные участки: 
 @robot.mainloop
def loop(ctx):
 try:
 read_sensors()
 except Exception as ex:
 robot.log("ERROR", f"Датчики: {ex}")
 
 Диагностика 
 
 Включите полный журнал: "logger_level": "all" , "logger_type": "console" . 
 Проверьте последовательность в журнале: connected → in heartbeat recieved ['d_meta', 'Ready'] → recieved command ... . 
 Проверьте робота без платформы на минимальном тестовом сервере . 
 Запросите журнал робота удалённо командой {"file": "log"} (при "logger_type": "file" ). 
 
 Известные ограничения версии 0.1.1 
 
 opencv-python не указан в зависимостях пакета. 
 Параметры max_send_freq и max_main_freq — это периоды в секундах. 
 Поле sid в состоянии робота не заполняется SDK (всегда null ). 
 Команды web_settings принимаются, но не обрабатываются. 
 Раздел external конфигурации зарезервирован и не используется. 
 Нет встроенного сторожевого таймера команд и соединения — реализуйте их в своей программе (примеры выше и на странице Обработка команд ).