Добрый день, уважаемые читатели Хабра!

Недавно, изучая книги по практическому использованию ROS, я узнал об интересной возможности использования портов GPIO, доступных на Raspberry Pi из ROS. В этой статье я хочу рассказать о том, каким образом это возможно осуществить. Для доступа к портам GPIO на плате Raspberry Pi мы будем использовать библиотеку Wiring Pi. Кого заинтересовала эта тема, прошу под кат.

Установка Wiring Pi


Для начала установим библиотеку Wiring Pi на Raspberry Pi:

git clone git://git.drogon.net/wiringPi
cd wiringPi
./build

Схему назначения портов GPIO на Raspberry Pi можно посмотреть в статье.

Пример Blink LED


Мы сделаем простой пример мигания светодиодом с помощью команд, которые будем публиковать в топик ROS. Мы подключим светодиод к пинам на Raspberry Pi таким образом: короткую ножку (катод) к порту GND, длинную ножку (анод) к порту GPIO18 (пин номер 12 на схеме).

У нас получится такое подключение:

image

Создадим пакет ROS:

catkin_create_pkg ros_wiring_example

Создайте файл C++ со следующим кодом:

#include "ros/ros.h"
#include "std_msgs/Bool.h"
#include <iostream>

//Wiring Pi header
#include "wiringPi.h"
//Wiring PI first pin
#define LED 1
//Callback to blink the LED according to the topic value
void blink_callback(const std_msgs::Bool::ConstPtr& msg)
{
if(msg->data == 1){
digitalWrite (LED, HIGH) ;
ROS_INFO("LED ON");
}
if(msg->data == 0){
digitalWrite (LED, LOW) ;
ROS_INFO("LED OFF");
}
}
int main(int argc, char** argv)
{
ros::init(argc, argv,"blink_led");
ROS_INFO("Started RPi Blink Node");
//Setting WiringPi
wiringPiSetup ();
//Setting LED pin as output
pinMode(LED, OUTPUT);
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("led_blink",10,blink_callback);
ros::spin();
}

Здесь мы включаем библиотечный файл wiringPi.h и добавляем инициализацию вызовом метода wiringPiSetup(). Методы pinMode() и digitalWrite() выполняют то же самое, что одноименные методы, используемые для Arduino.
Создадим файл CMakeLists.txt с таким содержанием:

cmake_minimum_required(VERSION 2.8.3)
project(ros_wiring_examples)
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
find_package(Boost REQUIRED COMPONENTS system)
//Include directory of wiring Pi
set(wiringPi_include "/usr/local/include")
include_directories(
${catkin_INCLUDE_DIRS}
${wiringPi_include}

)
//Link directory of wiring Pi
LINK_DIRECTORIES("/usr/local/lib")
add_executable(blink_led src/blink.cpp)

target_link_libraries(blink_led
${catkin_LIBRARIES} wiringPi
)

У нас будет простая логика. Создаем подписчика на топик led_blink типа Boolean. Если приходит значение 1, то зажигаем светодиод. Если приходит 0, то гасим светодиод.
Далее компилируем пакет:

cd ~/<catkin_ws>
catkin_make
source devel/setup.bash

И наконец запускаем узел:

roscore

Мы должны залогиниться из-под пользователя root для запуска узла:

sudo -s
cd /home/pi/<catkin_ws>
rosrun ros_wiring_example blink_led

Отправим команду для включения светодиода:

rostopic pub /blink_led std_msgs/Bool 1

Отправим команду для выключения светодиода:

rostopic pub /blink_led std_msgs/Bool 0

Все очень просто. Мы просто указываем топик blink_led, тип сообщения std_msgs/Bool и значение: 0 или 1.

Теперь можно использовать всю силу портов GPIO на Raspberry Pi в своих проктах. Мы можем подключать ультразвуковые сенсоры дистанции, сервомоторы и тд. и управлять ими или получать данные с них в узлах ROS без необходимости подключать дополнительные платы типа Arduino.

Желаю удачи в ваших робототехнических проектах с Raspberry Pi и до новых встреч!
Поделиться с друзьями
-->

Комментарии (7)


  1. argz
    24.09.2016 00:23
    +6

    Очень не советую подключать светодиод без токоограничительного резистора. Можно лишиться как светодиода, так и ножки порта.


    1. vovaekb90
      24.09.2016 10:50

      Спасибо за совет! Полезное замечание.


    1. tormozedison
      24.09.2016 14:52

      Этим способом разработчики микропылесоса из «Фикс прайса» над встроенным в прибор светодиодом издеваются. Как исправить, понятно.


  1. Kastalsky
    24.09.2016 00:31

    Wiring-Pi — действительно полезная библиотека. Недавно использовал ее, для организации автоматической регулировки скорости кулера RPi на основе аппаратного ШИМ-а WiringPi. Быстро и удобно.
    Хотя, подключая что-то вроде сервомоторов, главное не забывать, что все потребители, мощнее светодиода, стоит подключать соответствующим образом, например через Logic Mosfet соответствующего типа.


    1. silovi4
      26.09.2016 18:17

      Для таких целей можно было ограничиться одним микроконтроллером. А использовать RPi для таких целей это всё равно что стрелять из пушки по воробьям.


      1. Kastalsky
        27.09.2016 00:41

        Да, у меня были мысли поставить 2313 или 8ую мегу, для этой цели, но, подумалось, что, раз GPIO18 у меня пока что не используется, почему бы и нет… А, в случае с мк, пришлось бы все это размещать в довольно тесном корпусе с Raspberry, ну и плюс ко всему — возможность гибко менять настройки охлаждения, особенно такие, как гистерезис и температура отключения кулера, без перепрошивки, а просто изменяя аргументы при запуске скрипта — это неплохой бонус, хотя и не всегда важно.
        Но… Если появится надобность использовать данный порт — буду переделывать, наверное. С оверклоком без активного охлаждения нагрев все-же довольно сильный…


  1. CGen
    26.09.2016 18:14

    > ультразвуковые сенсоры дистанции
    С ультразвуковыми сенсорами реальная проблема.
    Остальное кое-как можно использовать.

    Linux не является RTOS. RT-патч даёт только возможность вытеснения кода ядра, но это не особо спасает.
    Например, на STM32 у меня через MCP23S17 сразу десять ультразвуковых датчиков работает. Обмен через SPI с DMA. Абсолютно без как-либо напрягов для CPU.
    На одну ногу ультразвукового датчика нужно подать сигнал длительностью 10 микросекунд. На RPi это невозможно сделать. Конечно датчик работает, если длительность импульса больше 10 мкс, но не в 100% случаев. После подачи сигнала на триггер нужно ждать низкий уровень на другой ноге. Интервал времени между моментом, когда на ноге RPi появился низкий сигнал, и моментом, когда об этом стало известно приложению, вообще не детерминирован. Достоверно измерить длительность импульса практически невозможно.