Все эти годы беспилотники летали по точкам. Координаты, телеметрия, слепое следование по GPS. Скучно. С приходом Vision-Language моделей (VLM) робот наконец-то начал понимать, что видит. Дрон не просто 'летит в точку 55.7558° N, 37.6173° E'. Он теперь видит 'разрушенный мост', 'группу людей в красном' или 'открытый проход между деревьями'. Это другая вселенная.
Здесь и сейчас мы собираем дрон, который летает по командам на естественном языке, обрабатывая видеопоток в реальном времени с помощью локальной VLM. Никакого облака. Никакого Starlink. Все вычисления на борту. В качестве мозга - ROS2 Humble (или новее, если к 2026 году вышел Iron Iridum, но принцип тот же). В качестве глаз и интеллекта - VLM типа Llama 3.2 Vision или Qwen2-VL, запущенная через Ollama. Ну что, полетели?
Куда мы прилетим: архитектура простым языком
Типичная ошибка новичка - начать паять и компилировать, не поняв, как все будет общаться. Давайте сразу расставим точки. Схема выглядит так:
- Датчики (камера, IMU, лазерный дальномер) → ROS2-ноды. Они публикуют данные (изображения, телеметрию) в топики.
- VLM-сервис (Ollama с загруженной моделью) → подписывается на топик с кадрами, получает изображение, обрабатывает промпт, возвращает текстовое описание или команду.
- Мозг (наш Python-скрипт на ROS2) → берет описание от VLM, преобразует в навигационные команды ('поверни налево', 'лети к синей двери') и публикует их в топик управления.
- Контроллер (BaseDriver или аналогичный драйвер полетного контроллера) → читает топик управления и отправляет низкоуровневые команды на моторы.
Важно: Обратите внимание, что это не end-to-end управление, где VLM напрямую выдает значения для моторов. Такой подход пока слишком опасен для реального полета. Мы используем VLM как высокоуровневый планировщик, а низкоуровневый контроль оставляем классическим ПИД-регуляторам. Если вам интересна именно end-to-end архитектура, посмотрите наш отдельный материал: End-to-End беспилотник на VLM.
Железо и софт: что покупаем и качаем
Не пытайтесь сразу закинуть 40-миллиардную модель на Raspberry Pi. Начните с симуляции, а для реальных полетов потребуется довольно мощная одноплатка. Вот минимальный набор на 2026 год:
| Компонент | Рекомендация | Зачем |
|---|---|---|
| Одноплатный компьютер | NVIDIA Jetson Orin Nano (16GB) или лучше | Именно для VLM нужен мощный GPU с поддержкой CUDA. Raspberry Pi 5 не потянет модели >7B параметров в разумное время. Здесь подробнее про Jetson и VLM. |
| Камера | Raspberry Pi HQ Camera или аналог с MIPI CSI | Высокое разрешение (12 МП) важно для VLM, чтобы различать детали. Убедитесь в совместимости с вашей платой. |
| Полетный контроллер | Pixhawk 6C (или любая версия, поддерживаемая PX4) | Стандарт де-факто. Отлично интегрируется с ROS2 через проект px4_msgs и micro-ROS. |
| Рама, моторы, ESC | Любой готовый китайский квадрокоптер 450-500мм | Не изобретайте велосипед. Берите готовый набор, чтобы сосредоточиться на софте. Похожий подход мы применяли для наземного робота. |
Софт:
- ОС: Ubuntu 22.04 LTS или 24.04 LTS (для Jetson - JetPack 6.0, актуальный на 2026 год).
- ROS2: Humble Hawksbill (или новее, но Humble - LTS до 2027).
- Ollama: последняя версия (на 01.03.2026 это, допустим, 0.6.x).
- VLM-модель: Llama 3.2 Vision 11B (баланс скорости и качества) или Qwen2-VL-7B (быстрее).
1 Установка ROS2 и окружения за 10 минут
Открываем терминал и не мудрим. Я предпочитаю устанавливать ROS2 из бинарников, а не из исходников (экономит часы жизни).
# 1. Настройка локали и ключей (стандартный скрипт от ROS)
sudo apt update && sudo apt install -y locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8
# 2. Добавление репозитория ROS2 (актуальная версия на 01.03.2026 может быть Iron, уточняем)
# Допустим, мы используем Humble (стабильный LTS)
sudo apt install -y software-properties-common curl
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main\" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
# 3. Установка ROS2 Humble Desktop (полный пакет с тулзами)
sudo apt update
sudo apt install -y ros-humble-desktop python3-colcon-common-extensions
# 4. Настройка переменных окружения (добавляем в ~/.bashrc)
echo \"source /opt/ros/humble/setup.bash\" >> ~/.bashrc
source ~/.bashrc
# 5. Проверка: запускаем demo
ros2 run demo_nodes_cpp talker &
ros2 run demo_nodes_cpp listener &
# Если видите обмен сообщениями - все ок.
2 Ollama и выбор VLM: качаем модель и не плавим плату
Установка Ollama проста, но выбор модели критичен. Для квадрокоптера важна скорость инференса (FPS) и понимание пространственных отношений.
# Установка Ollama (официальный скрипт)
curl -fsSL https://ollama.com/install.sh | sh
# Запуск сервиса
sudo systemctl enable ollama
sudo systemctl start ollama
# Скачиваем модель. Внимание: 11B параметров займет ~11 ГБ.
# Для Jetson Orin Nano с 16 ГБ ОЗУ это предел.
ollama pull llama3.2-vision:11b # Актуальная на 01.03.2026 модель
# ИЛИ более легкую модель для тестов
ollama pull qwen2-vl:7b
# Проверяем работу: отправляем тестовый промпт с изображением
ollama run llama3.2-vision:11b \"Describe what you see in this image.\" -f /tmp/test.jpg
Какую модель выбрать? Вот мой субъективный рейтинг на начало 2026:
- Llama 3.2 Vision 11B: Лучший баланс. Отлично понимает контекст сцен, пространственные отношения ('левее', 'позади дерева'). Инференс на Jetson Orin Nano: ~1-2 секунды на кадр.
- Qwen2-VL-7B: Быстрее, но иногда 'тупит' на сложных сценах. Хороша для простых навигационных команд ('лети к двери').
- AlpamayoR1 (если доступна для Ollama): Специально заточена под робототехнику и reasoning. Если вы хотите, чтобы дрон 'рассуждал' о своих действиях, это топовый выбор. Читали про AlpamayoR1?
3 Поднимаем железо: камера, Pixhawk и BaseDriver
Самый нервный этап. Если вы не подключили железо правильно, все остальное бессмысленно.
# 1. Подключаем камеру к CSI-порту Jetson. Проверяем драйверы.
# Установка инструментов для камеры (для Jetson)
sudo apt install -y nvidia-jetpack-multimedia
# Проверка: ищем устройство камеры
ls -la /dev/video*
# Должно появиться /dev/video0
# 2. Установка драйверов и утилит для Pixhawk (через PX4)
# Создаем workspace для ROS2
mkdir -p ~/drone_ws/src
cd ~/drone_ws/src
# Клонируем необходимые пакеты (включая micro-ROS для общения с Pixhawk)
git clone https://github.com/PX4/px4_msgs.git
# BaseDriver - наш мост между ROS2 и полетным контроллером
git clone https://github.com/your-repo/base_driver_ros2.git # Замените на актуальный репозиторий
# 3. Сборка
cd ~/drone_ws
colcon build
source install/setup.bash
# 4. Подключаем Pixhawk по USB (или UART). Ищем устройство.
ls /dev/serial/by-id/
# Должно быть что-то вроде /dev/serial/by-id/usb-...
# 5. Запускаем BaseDriver (предварительно настроив его конфиг на ваш порт)
ros2 run base_driver base_driver_node
# Если видите топики /mavros/... и /drone/control - связь установлена.
Предупреждение: Никогда не запускайте моторы в помещении без защиты! Первые тесты проводите с отключенными пропеллерами или на столе, зафиксировав раму. BaseDriver может отправить случайный сигнал 'взлет', и дрон взлетит в потолок.
4 Пишем мозг: ROS2-нода, которая спрашивает у VLM дорогу
Создаем пакет drone_vlm_brain. Вот его основа.
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from std_msgs.msg import String
from geometry_msgs.msg import Twist
import cv2
import requests
import json
import base64
from cv_bridge import CvBridge
class VLMNavNode(Node):
def __init__(self):
super().__init__('vlm_nav_node')
# Подписка на кадры с камеры
self.subscription = self.create_subscription(
Image,
'/camera/image_raw',
self.image_callback,
10 # QoS
)
# Издатель для навигационных команд (высокоуровневых)
self.cmd_pub = self.create_publisher(String, '/vlm/command', 10)
# Издатель для низкоуровневого управления (в топик, который читает BaseDriver)
self.control_pub = self.create_publisher(Twist, '/drone/control', 10)
self.bridge = CvBridge()
self.ollama_url = "http://localhost:11434/api/generate"
self.model = "llama3.2-vision:11b"
# Промпт-шаблон. Это ключевой момент!
self.prompt_template = """
You are the navigation system of a drone. Analyze the image from the drone's front camera.
Your goal is to reach the red door. Describe the immediate action in one short phrase.
Possible actions: "fly straight", "turn left", "turn right", "ascend", "descend", "stop", "hover".
If the red door is clearly visible and centered, say "target_reached".
Output ONLY the action phrase, nothing else.
Image description:
"""
self.get_logger().info('VLM Navigation Node запущен. Ожидание изображений...')
def image_callback(self, msg):
# Конвертируем ROS Image в OpenCV
cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8")
# Кодируем изображение в base64 для отправки в Ollama
_, buffer = cv2.imencode('.jpg', cv_image)
jpg_as_text = base64.b64encode(buffer).decode('utf-8')
# Формируем промпт
full_prompt = self.prompt_template + "\n[Image attached]"
# Подготовка запроса к Ollama API
payload = {
"model": self.model,
"prompt": full_prompt,
"images": [jpg_as_text],
"stream": False
}
try:
response = requests.post(self.ollama_url, json=payload, timeout=10.0)
if response.status_code == 200:
result = response.json()
vlm_response = result['response'].strip().lower()
self.get_logger().info(f'VLM сказал: {vlm_response}')
# Публикуем высокоуровневую команду
cmd_msg = String()
cmd_msg.data = vlm_response
self.cmd_pub.publish(cmd_msg)
# Преобразуем в низкоуровневую команду (Twist)
control_cmd = Twist()
if "turn left" in vlm_response:
control_cmd.angular.z = 0.5 # Поворот влево
elif "turn right" in vlm_response:
control_cmd.angular.z = -0.5
elif "fly straight" in vlm_response:
control_cmd.linear.x = 0.3 # Движение вперед
elif "ascend" in vlm_response:
control_cmd.linear.z = 0.3 # Вверх
elif "descend" in vlm_response:
control_cmd.linear.z = -0.3 # Вниз
elif "hover" in vlm_response or "stop" in vlm_response:
# Нулевые скорости - зависание
pass
elif "target_reached" in vlm_response:
self.get_logger().info('Цель достигнута!')
# Здесь можно инициировать посадку
else:
self.get_logger().warn(f'Неизвестная команда от VLM: {vlm_response}')
self.control_pub.publish(control_cmd)
else:
self.get_logger().error(f'Ошибка Ollama API: {response.status_code}')
except Exception as e:
self.get_logger().error(f'Ошибка связи с VLM: {e}')
def main(args=None):
rclpy.init(args=args)
node = VLMNavNode()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Этот код - сердце системы. Он делает три вещи: берет кадр с камеры, отправляет его в VLM с промптом, парсит ответ и конвертирует в команды для полетного контроллера. Самое важное здесь - промпт. Его качество определяет, будет ли дрон адекватно реагировать.
5 Искусство промптов для навигации: как разговаривать с VLM
VLM не понимает мир как человек. Ей нужно четко задать правила игры. Плохой промпт: "Куда лететь?". Хороший промпт дает контекст, список допустимых действий и жесткий формат вывода.
Вот несколько промпт-шаблонов для разных задач:
# Шаблон 1: Следование за объектом (например, за человеком в красной футболке)
You are a drone's vision system. Your only task is to keep a specific person in the center of the frame.
Describe the person: wearing a bright red t-shirt and blue jeans.
If the person is centered, output: "center".
If the person is slightly to the left, output: "adjust_left".
If the person is slightly to the right, output: "adjust_right".
If the person is too small (far), output: "approach".
If the person is too large (close), output: "hold_distance".
If the person is not visible, output: "search_rotate".
Output ONLY one of the above keywords, no other text.
# Шаблон 2: Поиск выхода из лабиринта (по визуальным меткам)
Analyze the scene. Identify openings or passages large enough for the drone to fly through.
Prioritize openings that are well-lit.
If you see a clear, safe passage straight ahead, output: "forward".
If the best passage is to the left, output: "turn_left".
If to the right, output: "turn_right".
If the passage is above (e.g., over a low obstacle), output: "ascend".
If the passage is below, output: "descend".
If no safe passage is visible, output: "halt".
Output only the action word.
Экспериментируйте с промптами. Иногда добавление фразы "Think step by step" (стандартный прием chain-of-thought) заставляет модель рассуждать точнее, но увеличивает время ответа. Для дрона каждая миллисекунда на счету. Если интересна эволюция VLM в робототехнике, почитайте наше сравнение VLA vs VLM 2025.
6 Запуск, тестирование и команды ./host.sh, ./b, . e
Вы собрали все части. Теперь нужно запустить систему одним скриптом. Вот где появляются эти загадочные команды. В корне проекта создайте несколько скриптов.
Файл host.sh (запускает все ноды на хосте - Jetson):
#!/bin/bash
# host.sh
# 1. Запускаем сервис Ollama (если еще не запущен)
sudo systemctl start ollama
sleep 2
# 2. Запускаем драйвер камеры (пример для Jetson CSI)
ros2 run v4l2_camera v4l2_camera_node --ros-args -p video_device:="/dev/video0" -p output_encoding:="rgb8" &
# 3. Запускаем BaseDriver для связи с Pixhawk
ros2 run base_driver base_driver_node &
# 4. Запускаем наш мозг - VLM навигационную ноду
ros2 run drone_vlm_brain vlm_nav_node &
echo "Все системы запущены. Для просмотра топиков: ros2 topic list"
Файл b (build) - для быстрой сборки проекта:
#!/bin/bash
# b
cd ~/drone_ws
colcon build --symlink-install
source install/setup.bash
Команда . e (environment) - просто алиас для source setup.bash в удобной директории. Добавьте в ~/.bashrc:
alias .e="source ~/drone_ws/install/setup.bash"
Теперь рабочий процесс выглядит так:
- Вносите изменения в код.
- Запускаете
./bдля сборки. - Запускаете
. e(или переоткрываете терминал) для обновления окружения. - Запускаете
./host.shдля запуска всей системы. - Наблюдаете за топиками:
ros2 topic echo /vlm/command.
Нюансы, которые вылезут в самый неподходящий момент
Я собрал для вас коллекцию граблей, на которые вы наступите. Лучше узнать о них сейчас.
Проблема: VLM отвечает слишком медленно ( >3 секунды). Дрон за это время уже улетит в стену.
Решение: Уменьшите разрешение кадра перед отправкой в Ollama. 640x480 достаточно. Добавьте в код сжатие. И подумайте о более легкой модели (Qwen2-VL-7B).
Проблема: VLM возвращает не только действие, но и пояснительный текст ("I think you should turn left because..."), который ваш код не может распарсить.
Решение: Жестче ограничивайте вывод в промпте. Добавьте фразу: "Output must be exactly one word from the list: [fly straight, turn left, turn right, ascend, descend, stop]. No explanations."
Проблема: При запуске всех нод система зависает, Jetson перегревается.
Решение: Ограничьте частоту вызова image_callback. Не нужно обрабатывать каждый кадр с 30 FPS. Используйте ROS2 таймер, чтобы опрашивать VLM, скажем, 2 раза в секунду. И купите активное охлаждение для Jetson.
Проблема: Pixhawk не отвечает на команды от BaseDriver.
Решение: Проверьте, что на Pixhawk залита последняя версия прошивки PX4 с поддержку MAVLink 2. Убедитесь, что в QGroundControl (или аналогичной утилите) задан правильный режим полета (например, Offboard).
И последнее. Не ждите, что ваш дрон сразу полетит как в кино. Первые успехи будут скромными: зависнуть в центре комнаты, повернуться к окну. Но момент, когда он впервые по вашей голосовой команде ('найди красный мяч') полетит в нужном направлении, компенсирует все часы отладки. Это уже не игрушка. Это прообраз будущего, где роботы видят и понимают.
Что дальше? Добавьте камеру глубины (Intel RealSense) для точного облета препятствий. Научите VLM читать текстовые указатели ('Exit', 'Room 101'). Или подключите все это к умному дому, чтобы дрон мог, например, лететь и проверять, закрыто ли окно на втором этаже. Технологии для этого уже есть. Осталось только собрать.