Mirte — это недорогая полностью open-source платформа учебного мобильного робота, где ученик проходит путь «от телеуправления и Blockly до Python, SSH и полноценного ROS», задуманная как единый «трек» обучения от начальной школы до университета, оставаясь на одном и том же роботе и в одной и той же среде. Идея Mirte в образовании — не прятать “настоящую” робототехнику за игрушечными абстракциями, а сделать к ней удобный, поэтапный вход.

Представьте урок, на котором школьник за 5 минут впервые в жизни запускает робота с ноутбука: сначала — обычным телеуправлением в браузере, затем — собирает программу из блоков, заглядывает «под капот» в сгенерированный Python, а через пару недель уже заходит по SSH, открывает VS Code на самом роботе, запускает Jupyter Notebook и пишет собственную ROS‑ноду.

И всё это — с одним и тем же роботом, на одной и той же платформе. Это и есть Mirte.

Зачем Mirte вообще появился

Создатели Mirte сформулировали задачу очень жёстко: образовательный робот должен быть одновременно дешёвым, полностью open‑source, без массы кастомных деталей и пригодным от начальной школы до университета.

Большинство наборов решают только один фрагмент картины:

  • либо это игрушка для начальной школы с закрытой прошивкой,

  • либо серьёзный набор для вуза, куда школьника просто не пустишь,

  • либо «конструктор по программированию», где нет реальной механики и электроники.

Mirte решает всё разом:

  • одно семейство роботов (Basic/Light/Pioneer/Master) — разный «уровень возможностей» под возраст и задачи;

  • одна линейка софта — от браузерного Blockly до ROS;

  • единая философия Open Education / Open Science: все механические файлы, схемы, код, учебные материалы открыты и развиваются сообществом.

Это не просто «ещё один робот», это тре́к обучения инженерии, который можно растянуть на годы.

Как устроена лестница Mirte: от teleop и Blockly до ROS

Основная педагогическая идея Mirte: несколько слоёв сложности в одной среде, чтобы каждый ученик входил туда, где ему комфортно, и мог шаг за шагом подниматься выше. В документации это сформулировано прямо: цель Mirte — «чтобы все могли учиться робототех��ике», поэтому доступны несколько уровней сложности программирования.

1. Первый контакт: веб‑интерфейс и телеуправление

Учитель включает робота. Mirte поднимает Wi‑Fi и web‑интерфейс; ученику достаточно открыть браузер и перейти по адресу Mirte (обычно вида http://mirte.local).

Что видит ученик:

  • панель управления роботом,

  • блоки Blockly,

  • и (чуть ниже) генерируемый Python‑код.​

Первый сценарий — телеуправление (teleop): робот ездит по командам с клавиатуры/кнопок в интерфейсе. Для ученика это просто «робот поехал». На самом деле под капотом уже работает ROS: есть нода, публикующая команды движения (Twist) в топик cmd_vel, а драйвер привода превращает это в скорости колёс.

2. Blockly: визуальное программирование как мост, а не тупик

Следующая ступень — Blockly. В документации прямо сказано: «Самый простой способ программировать Mirte — использовать Blockly».

Ученик перетаскивает блоки:

  • начать программу;

  • двигаться вперёд N секунд;

  • если сработал датчик — повернуть;

  • повторять в цикле и т.п.

Сверху — «контрольная панель»: запустить, поставить на паузу, выполнить пошагово, остановить.

​Важно, что при остановке программы Mirte автоматически выключает моторы — встроенная педагогическая «страховка».

Главное — это не игрушечный блок‑редактор:

  • под полотном Blockly виден Python‑код, сгенерированный по этим блокам;

  • этот код можно отредактировать и запустить теми же кнопками, что и блоки.

То есть Blockly в Mirte — не отдельный мир, а зеркало текстового кода. В материалах по Mirte прямо описано: «Блоки можно открыть, чтобы увидеть Python‑код ниже, который построен поверх ROS».

3. Python в браузере: первый шаг в «настоящем» коде

Когда ученик «наигрался» с блоками, учитель показывает следующую магию:

«Видишь этот Python под блоками? Давай уберём блоки и будем писать прямо здесь».

Документация Mirte описывает два способа программировать на Python:

  1. Из веб‑интерфейса — редактируя код, сгенерированный Blockly, и управляя его запуском той же панелью.

  2. Через Python API + ROS — когда Mirte становится частью ROS‑сети, а код подписывается, например, на cmd_vel и управляет моторами через вызовы API.

Пример из документации: Python‑скрипт, который слушает сообщения Twist и по ним задаёт скорости моторам через mirte_robot API — без дополнительной ROS‑инициализации, встроенной в robot.createRobot().

4. SSH: вход во «взрослый» Linux мира робототехники

Дальше ученику (или одному‑двум мотивированным в группе) дают следующий инструмент — терминал.

Mirte официально поддерживает подключение по SSH, о чём прямо сказано в документации Accessing the interface:

  • два интерфейса: web и Linux‑терминал через SSH;

  • web даёт Blockly и Python, SSH — Python и ROS.​

Команды становятся инженерными:

  • ssh mirte@mirte.local (первый логин с паролем по умолчанию);

  • ​просмотр каталогов, mirte_ws с ROS‑workspace;

  • ​управление сервисами:

    • sudo service mirte-ros stop/start — перезапуск bringup робота;

    • sudo service mirte-jupyter start — запуск Jupyter (по умолчанию он выключен, чтобы не съедать RAM).

  • чтение логов через journalctl -u mirte-ros -f, если что‑то пошло не так.

Это момент, когда ученик впервые чувствует: «я не просто клацаю кнопки, я администрирую настоящего робота».

5. VS Code и Jupyter на самом роботе

Для комфортной разработки Mirte предлагает «IDE на роботе»:

  • на роботе запускается VS Code / code-server, к которому заходят через браузер;

  • Jupyter Notebook работает как отдельный сервис, по адресу вроде http://mirte.local:8888, с примерами на базе Jupyter‑ROS.

Практически это выглядит так: ученик открывает в браузере VS Code, но весь workspace — на самом роботе. Не нужно настраивать Python, ROS, расширения на каждом ученическом ноутбуке — инфраструктура уже внутри робота Mirte.

6. ROS: Mirte как часть настоящей экосистемы

На верхнем уровне Mirte — полноценный участник ROS/ROS2‑мира. Документация описывает:

  • системные сервисы, поднимающие ROS ноды(программы) при старте;

  • ROS‑workspace ~/mirte_ws, где можно создавать свои пакеты и ноды;

  • ​Python API, который можно комбинировать с ROS‑сообщениями и сервисами;

В исследованиях TU Delft подчёркивается, что MIRTE Pioneer массово используется в бакалаврских курсах, где более 300 студентов в год строят и программируют этих роботов, а архитектура специально сделана модульной и открытой для расширения.

Mirte раскрывает ROS‑архитектуру: ученики могут увидеть, как их код взаимодействует с другими ROS нодами.

Как выглядит учебный процесс глазами ученика

Первый урок: «робот оживает»

Ученик достаёт Mirte, включается WIFI точку доступа / подключается к сети, открывает браузер. Робот появляется как web‑страница. Никаких установок SDK, драйверов, несовместимых версий.

Он нажимает на кнопки управления — робот ездит, поворачивает, реагирует на команды. Через пару минут преподаватель показывает вкладку Blockly:

«Смотри, давай теперь не вручную, а программой заставим его проехать квадратом».

Ученик собирает простую программу: вперёд — повернуть — вперёд — повернуть… Нажимает Run — робот крутит квадрат вокруг стола.

Вторая ступень: «из блоков — в код»

Учитель нажимает «показать код под блоками». На экране появляется Python.

— «Это то же самое, что ты сделал блоками. Попробуем заменить число 2 на 4, чтобы он дольше ехал».

Ученик меняет константу прямо в коде, снова запускает — видит результат.

Постепенно он начинает двигать логику из блоков в текст: сначала меняет параметры, потом добавляет новое условие, потом вообще убирает часть блоков и дописывает Python код руками.

Третья ступень: «я админ своего робота»

Через несколько занятий учитель показывает SSH:

  • как подключиться;

  • как зайти в папку с рабочим пространством;

  • как запустить/остановить сервисы;

  • как прочитать лог, если робот не реагирует.

Ученик, который ещё вчера перетаскивал блоки, сегодня пишет catkin_create_pkg, редактирует CMakeLists.txt и запускает rosrun.

Четвёртая ступень: проект

К концу модуля у него может быть вполне взрослый проект:

  • ROS нода, которая читает данные ЛИДАРа или ультразвуковых датчиков;

  • алгоритм, который решает — ехать вперёд или объехать препятствие;

  • программирование в Jupyter Notebook, графики в ноутбуке, настройка PID, анализ поведения.

И всё это — на том же Mirte, который он впервые включил через браузер.

Выгода для ученика

1. Понятная траектория роста

Mirte снял одно из главных противоречий школьной робототехники: либо слишком легко и скучно, либо слишком сложно и «для олимпиадников».

Здесь есть непрерывная лестница:

  • Teleop → Blockly быстрый успех, мгновенный «вау‑эффект»;

  • Blockly → Python в браузере: переход от визуального мышления к текстовому коду, но в знакомой среде;

  • Python → SSH/VS Code/Jupyter: освоение инструментов инженерной работы;

  • SSH/IDE → ROS‑архитектура: понимание профессиональной экосистемы, с которой работают реальные инженеры.

Ученик не «перескакивает» с платформы на платформу — он расширяет горизонт на одной и той же базе до профессионального востребованного робототехника.

2. Реальные, переносимые навыки

Mirte учит не только программированию. Он учит инженерному способу думать:

  • Linux, терминал, SSH, сервисы— базовые навыки DevOps/робототехники;

  • работа с ROS: топики, ноды, пакеты, конфигурация, отладка — фундамент ROS‑разработчика;

Исследования по Mirte в инженерном образовании подчёркивают именно это: робот задуман так, чтобы будущее инженерное обучение было непрерывным и практико‑ориентированным, а не набором разрозненных лабораторных работ.

3. Мотивация через прозрачность и «взрослость»

Поскольку Mirte полностью открыт, ученик всегда может пойти глубже:

  • открыть файлы робота и увидеть, что именно запускается при старте;

  • заглянуть в схему/PCB и понять, куда идут провода;

  • скачать исходники web‑интерфейса и модифицировать его под себя.

Это даёт очень сильное чувство «я вхожу в реальный мир технологий, а не играю в укороченную версию».

Выгода для учителя

1. Один робот — весь спектр образования

В университетских материалах TU Delft прямо говорится: MIRTE Pioneer используется в бакалавриате массово (более 300 роботов в год), а Light/Basic — в школе и колледже.

Практически это означает:

  • школе или вузу не нужно закупать разные наборы под каждый курс;

  • преподаватель может строить длинный сквозной курс (или несколько лестниц сложности) на одной платформе;

  • переход учащегося из школы в вуз не ломает всё: Mirte остаётся знакомой базой, меняется глубина задач.

2. Гибкость под разный уровень группы

В одном классе всегда есть «быстрые» и «медленные» ученики. Mirte позволяет работать с этим не через «занижение планки», а через разный уровень доступа:

  • новичкам достаточно браузера и Blockly — они спокойно осваивают базовые идеи алгоритмов;

  • уверенные быстро переходят в Python (но всё ещё в веб‑интерфейсе, без сложной установки IDE и ROS);

  • ​мотивированные получают SSH, VS Code, ROS — и превращают лабораторные работы в мини‑проекты.

Таким образом, учитель может дать общее задание («робот должен проехать маршрут с обходом препятствий»), а уровень реализации — адаптировать под ученика: от «если расстояние < X — поверни» на Blockly до собственной ROS‑ноды с логированием и настройкой параметров.

3. Снижение операционной боли

Типичные проблемы робототехники в образовании:

  • «у меня не ставится драйвер»,

  • «эта версия Python конфликтует с ROS»,

  • «на Windows всё иначе»,

  • «у нас 20 ноутбуков, и на каждом всё по‑разному»,

  • «не получается установить linux и ROS»,

Mirte снимает это за счёт того, что вся сложность живёт на роботе:

  • доступ через браузер, без установки софта на ученических ПК;

  • одна и та же среда для всех — учителю не нужно разруливать зоопарк конфигураций;

  • обновления можно проводить централизованно, а не по машинам.

4. Сообщество и открытые материалы

Mirte разворачивается как проект открытого образования и открытой науки:

  • партнёры (TU Delft, University of Groningen, прикладные вузы) используют Mirte в своих курсах и публикуют материалы открыто;

  • университеты в других странах берут дизайн и строят собственные роботы, адаптируя их под свои программы.

  • Полностью открытый исходный код, список компонентов для покупки, инструкции по сборке, документация.

Для учителя это означает: он не один. Можно брать готовые сценарии, уроки, лабораторные, адаптировать и возвращать в общее поле.

Почему это действительно инновация (и почему «всех нужно учить так»)

Mirte соединяет сразу несколько тенденций современного образования в инженерии:

  1. Открытая наука и open‑source.

Mirte — полностью открытый: от железа до кода и учебных материалов. Это означает, что:

  • образовательные учреждения не зависят от жизненного цикла коммерческого набора («сняли с производства» — и всё пропало);

  • студенты и преподаватели становятся со‑разработчиками, а не просто потребителями.

2. Сквозная инженерная подготовка.

Мир робототехники в жизни — это не отдельная дисциплина, а узел механики, электроники, программирования, сетей, UX и исследования. Mirte целенаправленно сделан как платформа, где можно учить всё это по спирали: сначала очень просто, потом всё сложнее, но на тех же объектах.

3. Фокус на реальных компетенциях.

Исследования по инженерной педагогике подчёркивают: наиболее эффективны те методики, где студенты делают «настоящие вещи» с понятной им связью с реальным миром. Mirte как раз об этом — это не симуляция, а реальный робот, который ведёт себя как система.

4. Сопряжение с индустрией.

ROS/ROS2 — де‑факто стандарт в академии и индустрии робототехники. Mirte с самого начала встроен в эту экосистему, а не в закрытую “игровую” среду. Значит, студенту потом проще войти в любые реальные проекты — от мобильных роботов до манипуляторов.

5. Масштабируемость и устойчивость.

Благодаря открытому дизайну, Mirte можно:

  • производить локально;

  • удешевлять и адаптировать под местные учебные планы;

  • объединять усилия разных университетов, школ, кружков.

Именно поэтому, когда разработчики Mirte говорят о «семействе открытых образовательных роботов», это не маркетинг. Это попытка построить общий стандарт инженерного образования через роботов, в котором любой учитель и ученик могут стать участниками, а не клиентами.

Выводы

Так как все выложено в open-source то проект может служ��ть отправной точкой для переиспользования различных технологий, наработок и идей. Чтобы погрузиться лучше начать с просмотра видео доклада рассказанного на образовательном блоке конференции ROSCON в Великобритании. Сайт проекта. Документация.

Обсудить статью можно в ROS чате.

Народный курс по ROS2 на степике.

Как понять, что образовательный подход и образовательный робот приносит пользу? Главный критерий готовит ли он кадры с необходимыми знаниями и опытом для бизнеса и государства, именно поэтому были разработаны ROS2 соревнования которые пройдут на ROS meetup 21-22 марта 2026 года. Задача соревнований максимально приближена к той которую решает мобильная манипуляция в сервисной и промышленной робототехнике. Победители соревнования могут претендовать на вавакансии в ведущих робототехнических компаниях. О этих соревнованиях вы можете прочитать подробную статью на Хабре.

Четыре уровня программирования Mirte: от PWM к архитектуре

Введение: одна задача, разные инструменты

Представьте простую задачу: робот должен проехать вперёд на 1 метр и остановиться.

На первый взгляд, это простое требование. Но на Mirte можно написать этот код четырьмя принципиально разными способами — от управления отдельными пинами микроконтроллера до полноценной ROS архитектуры. И каждый способ открывает новый уровень понимания того, как на самом деле работает робот.

Это не просто "разные способы написать то же самое". Это четыре разных парадигмы мышления инженера. И именно поэтому в образовательном процессе нужно учить все четыре подхода.

Уровень 1: управление пинами PWM (быстрый результат)

Код

import time
from mirte_robot import robot

def level_1_move_forward_pwm():
    """
    Уровень 1: управляем пинами микроконтроллера напрямую через PWM.
    
    PWM (Pulse Width Modulation) - быстрое переключение напряжения
    для управления мощностью мотора.
    """
    mirte = robot.createRobot()
    
    print("=" * 70)
    print("УРОВЕНЬ 1: Управление пинами PWM (низкоуровневый подход)")
    print("=" * 70)
    
    # На Mirte моторы подключены к GPIO пинам
    left_motor_pin = 'GP19'
    right_motor_pin = 'GP18'
    
    # Задаём PWM значение (0-255, где 255 = 100% мощности)
    pwm_power = 150  # примерно 60% мощности
    
    print(f"\n1. Устанавливаем оба мотора на PWM = {pwm_power} (60% мощности)")
    mirte.setAnalogPinValue(left_motor_pin, pwm_power)
    mirte.setAnalogPinValue(right_motor_pin, pwm_power)
    
    print("2. Гадаем, сколько времени нужно для проезда 1 метра...")
    print("   (зависит от батареи, веса, состояния пола...)")
    time.sleep(5)  # ждём 5 секунд
    
    print("3. Останавливаем моторы")
    mirte.setAnalogPinValue(left_motor_pin, 0)
    mirte.setAnalogPinValue(right_motor_pin, 0)
    
    print("\n" + "!" * 70)
    print("РЕЗУЛЬТАТ: Робот вероятно проехал примерно 1 метр, но мы НЕ ЗНАЕМ ТОЧНО!")
    print("!" * 70)
    print("\nПРОБЛЕМЫ этого подхода:")
    print("  ❌ Точность: ± 50 см (сильно зависит от условий)")
    print("  ❌ Нет обратной связи - не знаем, где робот на самом деле")
    print("  ❌ Если один мотор сильнее - робот едит КРИВО")
    print("  ❌ Если батарея разрядилась - робот едит медленнее")
    print("  ❌ Мы просто ГАДАЕМ на основе времени")

if __name__ == '__main__':
    level_1_move_forward_pwm()

Что происходит под капотом

Python: mirte.setAnalogPinValue('GP19', 150)
            ↓
    ROS API преобразует в сервис-вызов
            ↓
    Telemetrix протокол отправляет по USB
            ↓
    RP2040 микроконтроллер (Pico) получает команду
            ↓
    Pico устанавливает GPIO19 в режим PWM
            ↓
    PWM 150/255 ≈ 59% → мотор вращается на 59% мощности

Плюсы этого уровня

  • ✅ Максимально быстрый результат — робот реагирует мгновенно

  • ✅ Очень простой код — всего 3-4 строки для движения

  • ✅ Видна прямая причинно-следственная связь — код → поведение робота

  • ✅ Ученик видит физику — как работают электроника и моторы

Минусы этого уровня

  • ❌ Нет обратной связи

  • ❌ Неточно (гадание по времени)

  • ❌ Не масштабируется (добавить датчик = переписать код)

  • ❌ Работает только для Mirte

Когда его использовать

🎓 Возраст 8-10 лет — первые уроки программирования и робототехники
🎓 Когда нужен быстрый результат — ученик должен увидеть, что его код работает
🎓 Для понимания базовой физики — как работает электроника

Ключевой вопрос ученика на этом уровне:

"Почему робот не ездит прямо? Почему один раз проехал 1 метр, а другой раз 0.8 метра?"

Этот вопрос ведёт к следующему уровню.

Уровень 2: управление скоростью через PID (инженерный контроль)

Код

import time
from mirte_robot import robot

def level_2_move_forward_with_pid():
    """
    Уровень 2: управляем СКОРОСТЬЮ моторов, не PWM.
    
    За кулисами работает PID контроллер:
    1. Читает энкодеры (датчики вращения колёс)
    2. Вычисляет текущую скорость каждого мотора
    3. Сравнивает с желаемой скоростью
    4. Автоматически корректирует PWM для синхронизации
    
    Результат: оба мотора крутятся СИНХРОННО, робот ездит РОВНО.
    """
    mirte = robot.createRobot()
    
    print("=" * 70)
    print("УРОВЕНЬ 2: Управление скоростью моторов (PID контроллер)")
    print("=" * 70)
    
    # Задаём одинаковую скорость обоим моторам
    speed_value = 100  # условные единицы (0-255)
    
    print(f"\n1. Устанавливаем скорость = {speed_value}")
    print("   Что происходит под капотом:")
    print("   → PID контроллер КАЖДЫЕ 100мс читает энкодеры")
    print("   → Сравнивает скорость левого и правого мотора")
    print("   → Если левый медленнее - увеличивает его PWM")
    print("   → Если правый медленнее - увеличивает его PWM")
    print("   → В результате оба мотора синхронизируются")
    
    mirte.setSpeed('left', speed_value)
    mirte.setSpeed('right', speed_value)
    
    print(f"\n2. Едим 5 секунд (с автоматической синхронизацией)...")
    time.sleep(5)
    
    print("3. Останавливаем")
    mirte.setSpeed('left', 0)
    mirte.setSpeed('right', 0)
    
    print("\n" + "+" * 70)
    print("РЕЗУЛЬТАТ: Робот ездит РОВНО (не криво)!")
    print("+" * 70)
    print("\nЧТО УЛУЧШИЛОСЬ по сравнению с уровнем 1:")
    print("  ✅ Робот ездит прямо (оба мотора синхронизированы)")
    print("  ✅ Предсказуемое поведение")
    print("  ✅ Даже если один мотор немного слабее - система скомпенсирует")
    print("\nЧТО ВСЕ ЕЩЁ НЕ РЕШЕНО:")
    print("  ❌ Точность всё ещё примерно ± 20 см")
    print("  ❌ Мы НЕ ЗНАЕМ, где робот на самом деле")
    print("  ❌ Если батарея разрядилась - робот будет медленнее, но скорость 100 останется 100")
    print("  ❌ Мы всё ещё гадаем по времени: 'ехать 5 секунд' - это как далеко?")

def level_2_smooth_acceleration():
    """
    Дополнительный пример: плавный разгон через PID.
    
    PID контроллер делает разгон мягким и предсказуемым,
    а не рывком.
    """
    mirte = robot.createRobot()
    
    print("\n" + "=" * 70)
    print("УРОВЕНЬ 2: Плавный разгон с PID")
    print("=" * 70)
    
    max_speed = 150
    
    print("\nФаза 1: Разгон от 0% до 100% мощности")
    for speed in range(0, max_speed, 15):
        progress = (speed / max_speed) * 100
        print(f"  → Скорость {speed:3d} ({progress:5.1f}%)", end='\r')
        mirte.setSpeed('left', speed)
        mirte.setSpeed('right', speed)
        time.sleep(0.1)
    
    print(f"\nФаза 2: Едим с максимальной скоростью...")
    mirte.setSpeed('left', max_speed)
    mirte.setSpeed('right', max_speed)
    time.sleep(2)
    
    print("Фаза 3: Плавное торможение от 100% до 0%")
    for speed in range(max_speed, 0, -15):
        progress = (speed / max_speed) * 100
        print(f"  → Скорость {speed:3d} ({progress:5.1f}%)", end='\r')
        mirte.setSpeed('left', speed)
        mirte.setSpeed('right', speed)
        time.sleep(0.1)
    
    mirte.setSpeed('left', 0)
    mirte.setSpeed('right', 0)
    print("\n✓ Разгон/торможение завершены")

if __name__ == '__main__':
    level_2_move_forward_with_pid()
    time.sleep(1)
    level_2_smooth_acceleration()

Архитектура: как PID контроллер работает

mirte.setSpeed('left', 100)
         ↓
    Mirte OS: КАЖДЫЕ 100 мс
         ↓
    ┌─────────────────────────────────┐
    │ 1. Читаем энкодеры              │
    │    current_speed_left = 95      │
    │    current_speed_right = 100    │
    └─────────────────────────────────┘
         ↓
    ┌─────────────────────────────────┐
    │ 2. Вычисляем ошибку             │
    │    error_left = 100 - 95 = 5    │
    └─────────────────────────────────┘
         ↓
    ┌─────────────────────────────────┐
    │ 3. PID алгоритм                 │
    │    correction = P*5 + I*∫5 + D*5'│
    └─────────────────────────────────┘
         ↓
    ┌─────────────────────────────────┐
    │ 4. Корректируем PWM             │
    │    new_pwm_left = 150 + 1 = 151 │
    │    new_pwm_right = 150 (как было)
    └─────────────────────────────────┘
         ↓
    Оба мотора крутятся синхронно ✓

Плюсы этого уровня

  • ✅ Ученик видит PID контроллер — один из самых важных инструментов в инженерии

  • ✅ Введение в концепцию обратной связи — система сама себя корректирует

  • ✅ Робот ездит прямо — ровное, предсказуемое движение

  • ✅ Всё ещё просто — 2 строки кода, но под ними скрывается серьёзная инженерия

Минусы этого уровня

  • ❌ Точность всё ещё ± 20 см

  • ❌ Не знаем точно, где робот находится

  • ❌ Управление по времени, а не по расстоянию

Когда его использовать

🎓 Возраст 10-12 лет — когда ученик спрашивает "почему криво?"
🎓 Для первых проектов с движением — робот должен ездить прямо
🎓 Для понимания инженерных решений — как инженеры решают проблемы

Ключевой вопрос ученика на этом уровне:

"Отлично, робот ездит ровно. Но как я узнаю, что он проехал ровно 1 метр? Как мне рассчитать время? Что если батарея разрядилась?"

Этот вопрос ведёт к следующему уровню.

Уровень 3: высокоуровневые функции (простая ROS абстракция)

Код

from mirte_robot import robot
import time

def level_3_move_forward_high_level():
    """
    Уровень 3: используем высокоуровневые функции Mirte.
    
    Вместо управления пинами или даже скоростями, мы просто говорим:
    "проехать вперёд на 1 метр" - и система сама разбирается,
    как это сделать.
    
    За кулисами:
    1. Функция публикует Twist сообщение (ROS интерфейс скорости)
    2. Робот считает пройденное расстояние через одометрию
    3. Робот автоматически останавливается, когда достиг цели
    
    Это ИНТЕЛЛЕКТУАЛЬНОЕ управление!
    """
    mirte = robot.createRobot()
    
    print("=" * 70)
    print("УРОВЕНЬ 3: Высокоуровневые функции Mirte")
    print("=" * 70)
    
    # Самый простой способ: просто вызвать функцию!
    print("\n1. Вызываем: mirte.move_forward(duration=1.0, speed=50)")
    print("   (робот ездит 1 секунду со скоростью 50)")
    
    mirte.move_forward(duration=1.0, speed=50)
    
    print("\n2. Робот двигается с автоматическим контролем расстояния")
    print("   Под капотом происходит:")
    print("   → Публикуется Twist сообщение с нужной скоростью")
    print("   → PID контроллер синхронизирует моторы")
    print("   → Энкодеры считают расстояние")
    print("   → Одометрия обновляет позицию робота (X, Y, угол)")
    print("   → Функция move_forward() читает одометрию")
    print("   → Когда пройденное расстояние >= нужного - функция останавливает робота")
    
    print("\n" + "+" * 70)
    print("РЕЗУЛЬТАТ: Робот проехал примерно нужное расстояние!")
    print("+" * 70)
    print("\nЧТО УЛУЧШИЛОСЬ:")
    print("  ✅ Точность: ± 5 см (реальная обратная связь от одометрии!)")
    print("  ✅ Простой интерфейс - одна функция вместо 10 строк кода")
    print("  ✅ Робот сам знает, когда остановиться")
    print("  ✅ Введение в ROS парадигму (топики, одометрия)")
    print("\nЧТО СКРЫТО ПОД КАПОТОМ:")
    print("  → Стандартная ROS архитектура")
    print("  → Одометрия (позиция робота)")
    print("  → Управление через Twist топик")

def level_3_turn_example():
    """
    Пример: повернуться на 90 градусов.
    """
    mirte = robot.createRobot()
    
    print("\n" + "=" * 70)
    print("УРОВЕНЬ 3: Пример - повернуться на месте")
    print("=" * 70)
    
    print("\nВызываем: mirte.turn_right(angle=90)")
    mirte.turn_right(angle=90)
    
    print("✓ Робот повернулся на 90 градусов (с точностью ± 5 градусов)")

def level_3_complex_example():
    """
    Пример посложнее: нарисовать квадрат через высокоуровневые функции.
    """
    mirte = robot.createRobot()
    
    print("\n" + "=" * 70)
    print("УРОВЕНЬ 3: Проект - нарисовать квадрат")
    print("=" * 70)
    
    print("\nПроект: нарисовать квадрат 1x1 метр")
    print("\nКод:")
    print("  for i in range(4):")
    print("      mirte.move_forward(distance=1.0, speed=0.2)")
    print("      mirte.turn_right(angle=90)")
    
    for i in range(4):
        print(f"\nСторона {i+1}: едим 1 метр вперёд")
        mirte.move_forward(distance=1.0, speed=0.2)
        
        if i < 3:
            print(f"Поворот {i+1}: вращаемся на 90 градусов")
            mirte.turn_right(angle=90)
    
    print(f"\n✓ Квадрат готов!")

if __name__ == '__main__':
    level_3_move_forward_high_level()
    time.sleep(0.5)
    level_3_turn_example()
    # level_3_complex_example()  # раскомментируй, чтобы нарисовать квадрат

Интерфейс Mirte уровня 3

# Основные высокоуровневые функции:

mirte.move_forward(distance=1.0, speed=0.2)
# → Проехать 1 метр вперёд со скоростью 0.2 м/с

mirte.move_backward(distance=1.0, speed=0.2)
# → Проехать 1 метр назад

mirte.turn_right(angle=90)
# → Повернуться на 90 градусов вправо

mirte.turn_left(angle=90)
# → Повернуться на 90 градусов влево

x, y, theta = mirte.get_odometry()
# → Получить текущую позицию и ориентацию робота

Плюсы этого уровня

  • ✅ Точность ± 5 см — реальная обратная связь от одометрии

  • ✅ Простой API — одна функция вместо множества строк кода

  • ✅ Введение в ROS архитектуру — под капотом работает стандартная ROS парадигма

  • ✅ Переносимый код — похожие функции есть на других ROS роботах

  • ✅ Видна интеграция системы — команды → датчики → решения

Минусы этого уровня

  • ❌ Скрыта сложность — ученик не видит, что происходит под капотом

  • ❌ Сложнее отлаживать — если что-то не работает, нужно лезть в ROS

  • ❌ Нельзя реализовать сложную логику — функции ограничены

Когда его использовать

🎓 Возраст 12-14 лет — когда нужна точность и простота
🎓 Для проектов, требующих точности — навигация, рисование фигур
🎓 Для введения в ROS без "шока сложности" — ученик видит результат, а не архитектуру
🎓 Когда нужна масштабируемость — добавляем датчики, логика работает

Ключевой вопрос ученика на этом уровне:

"Эти функции хорошо работают, но что если мне нужна более сложная логика? Что если робот должен принимать решение на основе датчика расстояния? Как я это напишу?"

Этот вопрос ведёт к следующему, финальному уровню.

Уровень 4: полноценная ROS нода (профессиональная архитектура)

Код

#!/usr/bin/env python3
"""
Уровень 4: Полноценная ROS нода.

Это уже ПРОФЕССИОНАЛЬНЫЙ подход к разработке на робототехнике.

Вместо использования готовых функций, мы:
1. Подписываемся на ROS топики (одометрия, датчики)
2. Публикуем команды (скорость)
3. Реализуем нашу собственную логику управления

Это позволяет создавать произвольно сложные системы управления.
"""

import rospy
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
from sensor_msgs.msg import Range
from tf_transformations import euler_from_quaternion
import math

class MirteNavigationNode:
    """
    ROS нода для управления Mirte.
    
    Подписывается на топики, публикует команды, реализует логику.
    """
    
    def __init__(self):
        # Инициализируем ROS узел
        rospy.init_node('mirte_navigation_node', anonymous=False)
        
        # Издатель для команд скорости
        self.cmd_vel_pub = rospy.Publisher(
            '/cmd_vel',
            Twist,
            queue_size=10
        )
        
        # Подписчик на одометрию
        self.odom_sub = rospy.Subscriber(
            '/odom',
            Odometry,
            self.on_odometry_received
        )
        
        # Подписчик на датчик расстояния (если есть)
        self.distance_sub = rospy.Subscriber(
            '/mirte/distance_sensor',
            Range,
            self.on_distance_received
        )
        
        # Переменные состояния
        self.current_x = 0.0
        self.current_y = 0.0
        self.current_yaw = 0.0
        self.distance_to_obstacle = float('inf')
        
        rospy.loginfo("MirteNavigationNode инициализирована")
    
    def on_odometry_received(self, msg):
        """
        Callback: вызывается когда приходит новое сообщение одометрии.
        
        Одометрия - это информация о позиции робота:
        - X, Y: координаты в глобальной системе
        - Yaw: ориентация (угол)
        """
        self.current_x = msg.pose.pose.position.x
        self.current_y = msg.pose.pose.position.y
        
        q = msg.pose.pose.orientation
        (_, _, self.current_yaw) = euler_from_quaternion(
            [q.x, q.y, q.z, q.w]
        )
    
    def on_distance_received(self, msg):
        """
        Callback: вызывается когда приходит данные с датчика расстояния.
        
        Это может быть ультразвуковой датчик, LIDAR и т.д.
        """
        self.distance_to_obstacle = msg.range
    
    def publish_velocity(self, linear_x, angular_z):
        """
        Публикует команду скорости в ROS.
        
        linear_x: скорость вперёд (м/с)
        angular_z: угловая скорость (рад/с)
        """
        twist = Twist()
        twist.linear.x = linear_x
        twist.angular.z = angular_z
        self.cmd_vel_pub.publish(twist)
    
    def move_forward_with_obstacle_avoidance(self, target_distance):
        """
        Проехать вперёд, но если впереди препятствие - остановиться.
        
        Это пример того, как на уровне ROS ноды можно реализовать
        сложную логику, объединяя информацию из нескольких датчиков.
        """
        start_x = self.current_x
        start_y = self.current_y
        
        rospy.loginfo(f"Едим вперёд на {target_distance} м (с проверкой препятствий)")
        
        rate = rospy.Rate(10)  # 10 Hz
        
        while not rospy.is_shutdown():
            # Вычисляем пройденное расстояние
            distance_traveled = math.sqrt(
                (self.current_x - start_x)**2 + 
                (self.current_y - start_y)**2
            )
            
            # Проверяем препятствия
            if self.distance_to_obstacle < 0.2:  # менее 20 см впереди
                rospy.logwarn("⚠️  Препятствие впереди! Останавливаемся!")
                self.publish_velocity(0.0, 0.0)
                break
            
            # Проверяем, достигли ли цели
            if distance_traveled >= target_distance:
                rospy.loginfo(f"✓ Достигли цели ({distance_traveled:.2f} м)")
                self.publish_velocity(0.0, 0.0)
                break
            
            # Иначе продолжаем ехать
            progress = (distance_traveled / target_distance) * 100
            rospy.loginfo(f"Прогресс: {progress:.1f}%")
            
            self.publish_velocity(0.2, 0.0)  # 0.2 м/с вперёд
            rate.sleep()
    
    def move_in_square_with_sensing(self, side_length):
        """
        Нарисовать квадрат, но если впереди препятствие - остановиться.
        
        Пример сложной логики с использованием датчиков.
        """
        rospy.loginfo(f"Рисуем квадрат {side_length}x{side_length} м")
        
        for side in range(4):
            rospy.loginfo(f"Сторона {side + 1}/4")
            
            # Пытаемся проехать
            self.move_forward_with_obstacle_avoidance(side_length)
            
            # Если упёрлись в препятствие - выходим
            if self.distance_to_obstacle < 0.2:
                rospy.logwarn("Не смогли завершить маршрут - препятствие!")
                break
            
            # Если не последняя сторона - поворачиваемся
            if side < 3:
                rospy.loginfo("Поворот на 90 градусов...")
                self.turn_in_place(angle=math.radians(90))
        
        rospy.loginfo("✓ Квадрат завершен (или прерван препятствием)")
    
    def turn_in_place(self, angle):
        """
        Повернуться на месте на нужный угол.
        
        angle: в радианах
        """
        start_yaw = self.current_yaw
        
        rate = rospy.Rate(10)
        
        while not rospy.is_shutdown():
            angle_diff = self.current_yaw - start_yaw
            
            # Нормализуем угол
            while angle_diff > math.pi:
                angle_diff -= 2 * math.pi
            while angle_diff < -math.pi:
                angle_diff += 2 * math.pi
            
            # Если повернулись - выходим
            if abs(angle_diff) >= abs(angle):
                break
            
            # Иначе продолжаем вращаться
            self.publish_velocity(0.0, 0.3)  # 0.3 рад/с
            rate.sleep()
        
        self.publish_velocity(0.0, 0.0)  # стоп

def main():
    """Главная функция"""
    try:
        # Создаём ROS ноду
        navigator = MirteNavigationNode()
        
        # Даём время на инициализацию
        rospy.sleep(1)
        
        # Пример 1: просто ехать вперёд
        # navigator.move_forward_with_obstacle_avoidance(target_distance=1.0)
        
        # Пример 2: нарисовать квадрат с проверкой препятствий
        navigator.move_in_square_with_sensing(side_length=1.0)
        
    except rospy.ROSInterruptException:
        pass

if __name__ == '__main__':
    main()

Архитектура ROS ноды

ROS нода запущена
        ↓
    Подписывается на топики:
    ├── /odom (одометрия - позиция робота)
    └── /mirte/distance_sensor (датчик расстояния)
        ↓
    Каждый раз когда приходит новое сообщение:
    ├── on_odometry_received() обновляет x, y, yaw
    └── on_distance_received() обновляет distance_to_obstacle
        ↓
    Главная логика: move_in_square_with_sensing()
        ├── Проверяет: достигли ли цели?
        ├── Проверяет: препятствие впереди?
        ├── Принимает решение: ехать, остановиться или повернуться
        └── Публикует команду скорости в /cmd_vel
        ↓
    PID контроллер + моторы + энкодеры
        ↓
    Робот движется и отправляет новую одометрию
        ↓
    Цикл повторяется 10 раз в секунду

Плюсы этого уровня

  • ✅ Произвольная сложность — можем реализовать любую логику

  • ✅ Многодатчиковая интеграция — объединяем данные из разных источников

  • ✅ Модульность — каждый метод делает одно

  • ✅ Переиспользуемость — эту ноду можно использовать в других проектах

  • ✅ Стандарт индустрии — это архитектура реальных роботов

  • ✅ Профессиональный код — готово к deployment в реальные системы

Минусы этого уровня

  • ❌ Нужно понимать ROS архитектуру

  • ❌ Нужно понимать callbacks и асинхронность

  • ❌ Больше кода, сложнее отлаживать

Когда его использовать

🎓 На курсах вузов — робототехника, автономные системы
🎓 Для сложных проектов — уклонение препятствий, планирование пути
🎓 Когда нужна модульность — интегрируем несколько датчиков и поведений
🏭 Для подготовки к реальной индустрии — это реальный код робот-разработчиков

Сравнение: одна задача, четыре решения

Таблица

Параметр

Уровень 1

Уровень 2

Уровень 3

Уровень 4

Что используем

PWM пины

setSpeed + PID

Функции Mirte

ROS нода

Размер кода

5 строк

10 строк

5 строк

100+ строк

Скорость разработки

⚡⚡⚡

⚡⚡

⚡⚡

⏱️ медленнее

Точность

± 50 см

± 20 см

± 5 см

± 5 см

Обратная связь

❌ нет

✅ слабая

✅ полная

✅ полная

Переносимость

❌ Mirte only

❌ Mirte only

⚠️ похожие функции

✅ ROS стандарт

Сложность логики

простая

простая

средняя

произвольная

Для кого

8-10 лет

10-12 лет

12-14 лет

14+ / профи

Использование

обучение

обучение + проекты

проекты

реальные системы

Образовательная ценность: почему все четыре уровня?

Для ученика: путь от новичка к инженеру

Уровень 1 (PWM) — понимание физики

Вопрос: "Почему робот перемещается?"
Ответ: Потому что я установил напряжение на мотор через PWM

Уровень 2 (PID) — понимание инженерного контроля

Вопрос: "Почему робот не ездит криво?"
Ответ: Потому что PID контроллер читает энкодеры и корректирует скорость

Уровень 3 (функции) — системное мышление

Вопрос: "Откуда робот знает, что проехал 1 метр?"
Ответ: Из одометрии - система интегрирует данные энкодеров в позицию

Уровень 4 (ROS нода) — архитектурное мышление

Вопрос: "Как реализовать сложное поведение с несколькими датчиками?"
Ответ: Разделить на методы, подписать на топики, объединить логику

Ключевое: знания НАКАПЛИВАЮТСЯ, не теряются

На уровне 3 ученик НЕ ЗАБЫВАЕТ про PWM и PID — он их видит под капотом.
На уровне 4 ученик НЕ ЗАБЫВАЕТ про Twist и одометрию — он их использует в своей ноде.

Для учителя: гибкость и долгосрочность

Разные ученики, разные уровни:

  • Ученик, который впервые кодирует → уровень 1-2

  • Ученик, который знает Python → уровень 2-3

  • Ученик, готовящийся к вузу → уровень 3-4

  • Ученик, готовящийся к работе → уровень 4 + реальные проекты

Один робот, одна платформа:

  • 8 лет: Mirte уровень 1 (PWM, LED, простые движения)

  • 10 лет: Mirte уровень 2 (ровное движение, PID)

  • 12 лет: Mirte уровень 3 (точная навигация, одометрия)

  • 14 лет: Mirte уровень 4 (ROS архитектура, сложные проекты)

Выпускник знает:

  • ✅ Физику электроники (GPIO, PWM)

  • ✅ Инженерные решения (PID контроллер)

  • ✅ Системное архитектуру (ROS топики, одометрия)

  • ✅ Профессиональное программирование (ROS ноды, callbacks, навигация, SLAM)

Почему это важно

Традиционный путь (неправильный):

8 класс: Lego WeDo (закрытый, визуальный)
     ↓ (забываем всё)
10 класс: Arduino + датчики (открытый, но не ROS)
     ↓ (забываем всё, переучиваемся)
ВУЗ: ROS + C++ (шок сложности!)

Путь Mirte (правильный):

8 класс: Mirte уровень 1 (PWM)
     ↓ (знания остаются, добавляются)
10 класс: Mirte уровень 2 (PID) - видим PWM под капотом
     ↓ (знания остаются, расширяются)
12 класс: Mirte уровень 3 (ROS) - видим PID и PWM в системе
     ↓ (знания остаются, углубляются)
14 класс: Mirte уровень 4 (ROS нода) - проектируем архитектуру
     ↓ (готовы к ВУЗ и работе)

Практический вывод

На Mirte ученик видит весь путь — от одного провода к архитектуре системы.

Каждый уровень закрывает вопрос предыдущего:

  • "Почему криво?" → Уровень 2 (PID)

  • "Как узнать расстояние?" → Уровень 3 (одометрия)

  • "Как реализовать сложное поведение?" → Уровень 4 (ROS нода)

  • "Как работает реальная робототехника?" → Уровень 4 показывает это

Это не просто четыре способа написать код. Это четыре парадигмы инженерного мышления.

И именно поэтому Mirte работает как долгосрочная образовательная платформа — от ребёнка в 8 лет, управляющего LED через PWM, до старшеклассника, проектирующего ROS архитектуру.

Обсудить статью можно в ROS чате.

Народный курс по ROS2 на степике.

Как понять, что образовательный подход и образовательный робот приносит пользу? Главный критерий готовит ли он кадры с необходимыми знаниями и опытом для бизнеса и государства, именно поэтому были разработаны ROS2 соревнования которые пройдут на ROS meetup 21-22 марта 2026 года. Задача соревнований максимально приближена к той которую решает мобильная манипуляция в сервисной и промышленной робототехнике. Победители соревнования могут претендовать на вавакансии в ведущих робототехнических компаниях. О этих соревнованиях вы можете прочитать подробную статью на Хабре.