Bubot — различия между версиями

Материал из razgovorov.ru
Перейти к: навигация, поиск
(Концепция)
(Простейший пример)
Строка 40: Строка 40:
 
* [название модуля].py - содержит логику модуля
 
* [название модуля].py - содержит логику модуля
 
* [название модуля].json - содержит описание модуля - список параметров модуля, их значения по умолчанию, список возможных статусов, описание сообщений генерируемых модулем, и список сообщений на которые модуль подписан.
 
* [название модуля].json - содержит описание модуля - список параметров модуля, их значения по умолчанию, список возможных статусов, описание сообщений генерируемых модулем, и список сообщений на которые модуль подписан.
 +
 +
<source lang=text>
 +
{
 +
    "param": {
 +
        "name": {
 +
            "value": "scout_easy"
 +
        }
 +
    },
 +
    "depend_buject": {
 +
        "drive_motor": {
 +
            "param": {
 +
                "buject": {
 +
                    "value": "Motor"
 +
                },
 +
                "name": {
 +
                    "value": "drive_motor"
 +
                },
 +
                "GPIO_forward": {
 +
                    "value": 20
 +
                },
 +
                "GPIO_reward": {
 +
                    "value": 21
 +
                }
 +
            }
 +
        },
 +
        "rotation_motor": {
 +
            "param": {
 +
                "buject": {
 +
                    "value": "Motor"
 +
                },
 +
                "name": {
 +
                    "value": "rotation_motor"
 +
                },
 +
                "GPIO_forward": {
 +
                    "value": 13
 +
                },
 +
                "GPIO_reward": {
 +
                    "value": 19
 +
                }
 +
            }
 +
        }
 +
    }
 +
}
 +
</source>
  
 
Итак, создадим модуль для мотора: motor_test.
 
Итак, создадим модуль для мотора: motor_test.
Строка 120: Строка 164:
 
</source>
 
</source>
  
<source lang=text>
 
{
 
    "param": {
 
        "name": {
 
            "value": "scout_easy"
 
        }
 
    },
 
    "depend_buject": {
 
        "drive_motor": {
 
            "param": {
 
                "buject": {
 
                    "value": "Motor"
 
                },
 
                "name": {
 
                    "value": "drive_motor"
 
                },
 
                "GPIO_forward": {
 
                    "value": 20
 
                },
 
                "GPIO_reward": {
 
                    "value": 21
 
                }
 
            }
 
        },
 
        "rotation_motor": {
 
            "param": {
 
                "buject": {
 
                    "value": "Motor"
 
                },
 
                "name": {
 
                    "value": "rotation_motor"
 
                },
 
                "GPIO_forward": {
 
                    "value": 13
 
                },
 
                "GPIO_reward": {
 
                    "value": 19
 
                }
 
            }
 
        }
 
    }
 
}
 
</source>
 
  
  

Версия 08:54, 26 марта 2015

Bubot - фреймворк на Python 3 для создания роботов и домашней автоматизации (умный дом).

Предыстория

Хотелось создать своего робота, а так же автоматизировать управление светом и климатом дома. Начал изучать имеющиеся возможности - рассматривал все варианты систем где бы робот состоял из параллельно работающих процессов обменивающихся между собой сообщениями. Из наиболее популярных подходили Microsoft Robotics Stusio и ROS, и все бы ничего, но на текущий момент привязать их к конкретному железу весьма не просто, ну и самое главное писать на языке C очень не хотелось. Душа просила чего-нибуть по проще и по легче – как например Питон. Учитывая, что нужно было и робота и умный дом, да ещё почти сразу появились перспективы ещё одного проекта, то было решено сделать небольшой фреймворк в котором упор делался на простоту дальнейшего применения.

Концепция

Файл:Bubot.png
Bubot - Схема

Концептуально фреймворк представляет собой набор процессов, которые между собой общаются с помощью сообщений.

Для процессов в python есть замечательный модуль multiprocessing. Сообщения и разделяемая память реализованы при помощи Redis (входящие в состав модуля multiprocessing очереди и разделяемая память не совсем подошли под мои задачи и сильно усложнили бы систему).

Каждый робот имеет встроенный веб сервер, который позволяет контролировать состояние, управлять, на ходу менять параметры (калибровать) робота, а также закладывается возможность обмена данными между роботами.

Возможный недостаток производительности питона (по сравнению с языком C) компенсируется мощностью железа, благо сейчас с этим практически нет проблем. Для raspberry pi пока в проблему производительности пока не упирался.

Простейший пример

Изучать что либо новое всегда проще на примере, и первое что приходит в голову это переделать радиоуправляемую игрушку на управление с помощью веб-интерфейса через wi-fi или 3G.

Нам понадобится любая китайская радиоуправляемая машинка и любой мини компьютер с установленным python 3 (я использовал raspberry pi b). Изначально практически любая радиоуправляемая машинка это два мотора и примитивный радио модуль. Нам от неё надо только два мотор и чтобы сама машинка была подходящего размера.

Для начала упростим задачу - наша машинка должна выполнять четыре действия: ехать вперед или назад, поворачивать влево или вправо.

Для решения поставленной задачи нам необходимо:

  1. Подключить моторы к raspberry pi.
  2. Реализовать сервис который будет принимать и интерпретировать команды пользователя на конкретные физические устройства.
  3. Реализовать веб интерфейс, который будет передавать команды пользователя: Установить мощность основного или поворотного двигателя -100% / 0% / 100%.

1. Подключаем моторы. Простейшая схема подключения моторов к raspberry pi будет выглядеть следующим образом (нужны дополнительные железяки:

Файл:Bubot-easy-scout.png
Простейший пример - Схема подключения

При таком подключении, чтобы заставить машину выполнить одну из наших команд достаточно выставить высокий уровень на соответствующем GPIO.

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

  • [название модуля].py - содержит логику модуля
  • [название модуля].json - содержит описание модуля - список параметров модуля, их значения по умолчанию, список возможных статусов, описание сообщений генерируемых модулем, и список сообщений на которые модуль подписан.
{
    "param": {
        "name": {
            "value": "scout_easy"
        }
    },
    "depend_buject": {
        "drive_motor": {
            "param": {
                "buject": {
                    "value": "Motor"
                },
                "name": {
                    "value": "drive_motor"
                },
                "GPIO_forward": {
                    "value": 20
                },
                "GPIO_reward": {
                    "value": 21
                }
            }
        },
        "rotation_motor": {
            "param": {
                "buject": {
                    "value": "Motor"
                },
                "name": {
                    "value": "rotation_motor"
                },
                "GPIO_forward": {
                    "value": 13
                },
                "GPIO_reward": {
                    "value": 19
                }
            }
        }
    }
}

Итак, создадим модуль для мотора: motor_test.

3. Реализуем веб интерфейс. Для решения данной задачи нам достаточно 4 кнопки, которая при нажатии будет давать команду, а при отжатии её отменять.

Пользовательские Веб интерфейсы хранятся в каталоге ui. Каждая страница пользовательского интерфейса описывается в отдельном подкаталоге, и состоит как минимум из 2 файлов: [Имя страницы].html - разметка страницы. [Имя страницы].json - каждая страница (сессия) для фраймворка является по сути отдельным процессом, в данном файле содержится описание событий на которые данная страница подписана, а также сообщения которые она генерирует. Давайте опять для улучшения восприятия ещё немного упростим. В приведенном ниже примере алгоритм одной кнопки вперед. Остальные можно сделать по аналогии. Итак создаем в каталоге ui подкаталог scout_easy и в нем два файла scout_easy.html и scout_easy.json следующего содержания (комментарии по коду):

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/js/jquery-ui-1.11.2/jquery-ui.css">
    <script type="text/javascript" src="/static/js/jquery-2.1.3.min.js"></script>
    <script type="text/javascript" src="/static/js/jquery-ui-1.11.2/jquery-ui.js"></script>
    <script type="text/javascript" src="/ui/bubot_socket.js"></script>
    <title>BuBot</title>
    <script>
        function bubot_on_open() {
        }
        function get_bubot_actions() {
            return {};
        }
        $(function () {
            $("#command_move_forward").button({}).mousedown(function () {
                bubot_send_message('send_request', {'name': "set_drive_motor_power", 'data': {'value': 100}});
            }).mouseup(function () {
                bubot_send_message('send_request', {'name': "set_drive_motor_power", 'data': {'value': 0}});
            });
        })
    </script>
</head>
<body class="ui-widget-content">
<button id="command_move_forward" class="command_button"></button>
<div id="console" class="ui-widget-content"></div>
</body>
</html>

Обратите внимание на

, если он присутствует, то в него фреймворк будет выводить все консольные сообщения, в т.ч. происходящие на стороне сервера ошибки кода.

bubot_socket.js - должен присутствовать на каждой страницы, так как именно он отвечает за установку соединения и обмен сообщениями.

В этом же каталоге создаем одноименный json файл с описанием параметров и событий пользовательского интерфейса.

{
  "incoming_request": {
    "console": {
      "time": {},
      "message": {}
    }
  },
  "outgoing_request": {
    "set_drive_motor_power": {
      "name": "set_power",
      "buject": "Motor",
      "param": {
        "value": {
          "description": "команда от пользователя на установку мощности мотора привода в процентах",
          "type": "int"
        }
      }
    },
    "set_rotation_motor_power": {
      "name": "set_power",
      "buject": "Motor",
      "param": {
        "value": {
          "description": "команда от пользователя на установку мощности мотора поворота в процентах",
          "type": "int"
        }
      }
    }
  }
}



Bubot имеет пять типов сообщений - входящие/исходящие события и запросы, а также ответы на запросы. События отличаются от запросов тем, что никому конкретно не адресуются. По списку исходящих сообщений фреймворк создает очереди на Redis, а по списку входящих сообщений формируется список подписки.

Описание параметров событий позволяет генерировать их в конфигураторе при отладке, а заполнение поля description позволяет выводить всплывающие подсказки.

3 Первое применение решено было сделать на машинке с поворотной камерой которая бы управлялась через веб интерфейс (чтобы можно было поездить по большому офису не ходя гуськом за машинкой с пультом).

Файл:Scout.png
Bubot:scout - Схема подключения

Была взята китайская радиоуправляемая машинка и из неё вытряхнуто все кроме двигателей (во всех китайских машинках на рулевом управлении стоит тоже двигатель, мне как то это показалось мало и я поставил вместо него серву для более плавной рулежки). Общая схема подключения моторов и серво-приводов выглядит следующим образом.

В качемДля простоты предлагаю рассмотреть на примере как любую китайскую машинку переделать на управление с помощью веб интерфейса. и одноплатного компьютера raspberry pi.

Первое с чем надо определиться, это сколько у нас будет процессов. Рекомендую, применять много максимально простых алгоритмов - на каждую железяку конструкции делать отдельный процесс. Например мотор привода обрабатывается в отдельном процессе и принимает нкод работы мотора живет своей жи живетсвой чтобы не мудрить со сложной логикойзаморачиваться со

Теперь все настройки машинки входят в базовый набор bubot. С точки зрения фреймворка машинка выглядит следующим образом.

Структура каталогов

  • buject - в каталоге хранятся готовые модули. Модуль состоит из двух файлов [имя модуля].py - класс модуля унаследованный от класса Buject, и [имя модуля].json - параметры модуля. Один и тот же модуль может быть запущен с разными параметрами на одном роботе.
  • config - конфигурации роботов. Один json файл содержит параметры одного робота - список сервисов, модулей, их параметры и правила обмена сообщениями.
  • lib - сторонние библиотеки и модули необходимые для работы. Например библиотека для работы с i2c, видео стример, аудио плеер и т.п.
  • static - статические веб компоненты - jquery, картинки и т.п.
  • ui - пользовательский веб интерфейсы, каждый подкаталог отвечает за работу одной страницы веб интерфейса и состоит по умолчанию из 5 файлов [имя ui].html(css,js) код веб страницы. [имя ui].py серверная часть пользовательского интерфейса реализующая реакцию на события этого пользовательского интерфейса. [имя ui].json - параметры пользовательского интерфейса (декларирование использующихся событий в т.ч. для подписки)
    • studio - конфигуратор робота с амбициями со временем превратится в bubotics studio. Предназначен для создания конфигураций роботов, их калибровке и отладки.
    • scout - интерфейс управления говорящей машинкой оснащенной поворотной камерой.


бобот - говорящий робот фотограф. Покупаем железо. Из доступных платформ на которых работает питон была выбрана raspberry pi. Была куплена последняя на тот момент версия B+ Самым доступным шасси является недорогая китайская радиоуправляемая игрушка. Она должна быть достаточно крупной чтобы увезти все железо с батарей. для того чтобы сделать робота фотограа на колесном шасси нам понадобится контроллер мотора - был выбран контроллер серв. - распберри не имеет ... а робот должен уметь врашать камерой, кроме всего прочего в китайских игрушках рулевое управление было таже заменено на сервуБ для более плавного регулирования поворотов. управляться робот будет п wifi по этому был приобретен usb свисток. робот должен чем то видеть. и здесь наилучшим образом подходит камера. рекомендую брать сразу камеру с широкойгольным объективом (рыбьим глазом) и инфракрасной подсветкой чтобы робот мог видеть в темноте. два стабилизатора питания. для воспроизведения звука были куплены самые маленькие активные колонки. начинка которых была установлена на шасси Собираем железо Устанавливаем необходимый софт Учим бубота фотографа ездить Для управления роботом буду придерживаьтся классической схемы - wsad для движения - мышкой движение камерой. итак начнем с движения. для начала сделаем простую веб страницу с четырьмя кнопками. включем на ней скрипт для обмена с боботом. для того чтобы отправить буботу событие из веб интерфейса достаточно вызвать функцию send_message которой передать параметры сообщения.

т.е для того чтобы поехать вперед нам надо на нажатие кнопки послать сообщение нажали кнопку вперед, но поскольку в будущем мы захотим регулировать скорость машины то правильнее будет дать команду установить мощность мотора 100%. Ну а чтобы наша машина остановилась когда мы кнопку отпустим, на отжетие кнопки вешаем событие установить мощность мотора 0%. Движение назад у нас будет -100%. С поворотами тоже самое, только там делаем установку угла поворота +- 100%

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