Начал изучать ROS по этим материалам >> (спасибо за перевод — по английским мануалам точно бы не смог )
Есть задумка с платформой iRobot, пока iRobot в пути поупражняюсь в простеньком.
Решил наладить передачу между двумя платами Arduino через ROS.
Библиотека rosserial (см. топик) устанавливает соединение точка-точка (point-to-point connection) через последовательный порт с недорогими контроллерами (типа Arduino) так, что вы можете посылать сообщения ROS туда и обратно.
ROS установлена на нетбуке ASUS (простенький, слабенький), Ubuntu 11.10, дистрибутив Electric
Для начала устанавливаем библиотеку rosserial.
Пробовал как рекомендовано на сайте ros.org —
hg clone https://kforge.ros.org/rosserial/hg rosserial rosdep install rosserial_arduino rosmake rosserial_arduino
Сразу возникли проблемы — ошибки — проблема общая как показал поиск по google
Решил так
sudo apt-get install ros-electric-rosserial rosdep install rosserial_arduino rosmake rosserial_arduino
Все получилось
Rosserial состоит из общего p2p-протокола, библиотеки для работы с Arduino и узлов для ПК.
Библиотека для работы с Arduino находится в папке проекта serial, в каталоге serial_arduino/libraries. Копируем папку ros_lib в библиотечную директорию (libraries) Arduino IDE.
Две платы Arduino подключены по двум последовательным портам к нетбуку с ROS.
К одной плате Arduino (один узел ROS ) подключен датчик температуры DS18B20. Показания температуры будем отправлять будем публиковать в ROS (в тему temperature), другая плата Arduino (еще один узел ROS) будет получать показания температуры из темы temperature и отображать на дисплее WH0802.
В ROS создаем два узла serial_node.py пакета rosserial_python, который соединяет наши Arduino платы с остальной частью ROS (необходимо выставить используемый последовательный порт):
Создается узел так:
rosrun rosserial_python serial_node.py /dev/порт
Запустить два узла serial_node с одним именем не получится. Одна из особенностей ROS состоит в том, что вы можете переназначить имена (Names) узлов из командной строки:
$ rosrun rosserial_python serial_node.py /dev/ttyUSB0 __name:=serial1 $ rosrun rosserial_python serial_node.py /dev/ttyACM0 __name:=serial2
Теперь необходимо написать скетчи на Arduino для узла publisher (отправляющего показания температуры в тему temperature) и узла subscriber (получающего показания из темы отображающего их на дисплее WH0802)
Используем библиотеку ros_lib
Скетч для publisher
В рамках каждой программы ROS Arduino необходимо включить заголовочный файл ros.h и файлы заголовков для всех типов сообщений, которые мы будем использовать, в нашем случае std_msgs/Float32.h:
#include <ros.h>
#include <std_msgs/Float32.h>
Далее, нам необходимо создать экземпляр объекта узла serial_node, что позволяет нашей программе выступать в качестве подписчика(subscriber), либо публиковать сообщения (publisher):
ros::NodeHandle nh;
Создаем экземпляр publisher для нашего узла serial_node, публикующий сообщения типа std_msgs::Float32 в тему temperature:
std_msgs::Float32 float32_msg;
ros::Publisher chatter(«temperature», &float32_msg);
В подпрограмме setup() необходимо инициализировать узел и объявить о роли узла chatter в качестве publisher:
nh.initNode();
nh.advertise(chatter);
В цикле loop() после считывания данных с датчика температуры публикуем сообщение в тему и вызываем ros::spinOnce(), где обрабатываются все функции обратного вызова соединения.
chatter.publish( &float32_msg );
nh.spinOnce();
Добавляем код для считывания данных с датчика температуры, и получается так:
#include <OneWire.h>
OneWire ds(10); // линия 1-Wire будет на pin 10
#include <ros.h>
#include <std_msgs/Float32.h>
ros::NodeHandle nh;
std_msgs::Float32 float32_msg;
ros::Publisher chatter("temperature", &float32_msg);
void setup(void)
{
nh.initNode();
nh.advertise(chatter);
}
void loop(void)
{
byte i;
byte present = 0;
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
ds.reset_search();
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // запускаем конвертацию
delay(1000); // скорее всего достаточно 750ms
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // считываем ОЗУ датчика
for ( i = 0; i < 9; i++) { // обрабатываем 9 байт
data[i] = ds.read();
}
Serial.print(" CRC=");
Serial.print( OneWire::crc8( data, 8), HEX);
Serial.println();
// высчитываем температуру
int HighByte, LowByte, Temp;
float Tempf1,Tempf2;
LowByte = data[0];
HighByte = data[1];
Temp = (HighByte << 8) + LowByte;
Tempf1=Temp/16;
Tempf2=(Temp%16)*100/16;
float32_msg.data=Tempf1+Tempf2/100;
// публикуем сообщение
chatter.publish( &float32_msg );
nh.spinOnce();
}
Скетч для subscriber
Включаем заголовочный файл ros.h и файлы заголовков для всех типа сообщений, которые мы будем использовать, в нашем случае std_msgs/Float32.h
#include <ros.h>
#include <std_msgs/Float32.h>
Далее, нам необходимо создать экземпляр объекта узла serial_node, что позволяет нашей программе выступать в качестве подписчика(subscriber), либо публиковать сообщения (publisher):
ros::NodeHandle nh;
Создаем экземпляр subscriber для нашего узла, получающийй сообщения типа std_msgs::Float32.h из темы temperature:
ros::Subscriber
Создаем функцию обратного вызова messageCb для нашего узла. Функция обратного вызова должна постоянно получать сообщение в качестве аргумента. В нашем messageCb обратного вызова, тип сообщения std_msgs::Float32.
void messageCb( const std_msgs::Float32& toggle_msg){
digitalWrite(13, HIGH-digitalRead(13)); // blink the led
lcd.setCursor(0, 0);
lcd.print("Temp=");
lcd.setCursor(0, 1);
lcd.print(toggle_msg.data);}
В подпрограмме setup() необходимо инициализировать узел и объявить о роли узла в качестве подписчика на сообщения:
nh.initNode();
nh.subscribe(sub);
И наконец, в цикле loop() и вызываем ros::spinOnce(), где обрабатываются все функции обратного вызова соединения.
nh.spinOnce();
Добавляем код вывода сообщений на дисплей и получаем:
// подключить библиотеку LiquidCrystal
#include <LiquidCrystal.h>
// создание экземпляра объекта LiquidCrystal
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// rosserial
#include <ros.h>
#include <std_msgs/Float32.h>
ros::NodeHandle nh;
void messageCb( const std_msgs::Float32& toggle_msg){
digitalWrite(13, HIGH-digitalRead(13)); // blink the led
lcd.setCursor(0, 0);
lcd.print("Temp=");
lcd.setCursor(0, 1);
lcd.print(toggle_msg.data);}
ros::Subscriber sub("temperature", &messageCb );
void setup() {
lcd.begin(8, 2);
pinMode(13, OUTPUT);
nh.initNode();
nh.subscribe(sub);
}
void loop() {
nh.spinOnce();
delay(1000);
}
Теперь проверяем как все работает:
$ roscore $ rosrun rosserial_python serial_node.py /dev/ttyUSB0 __name:=serial1 $ rosrun rosserial_python serial_node.py /dev/ttyACM0 __name:=serial2
Проверяем список активных узлов
$ rosnode list
Ответ должен быть
/rosout /serial1 /serial2
Зупускаем утилиту rxgraph
$ rxgraph

Видим на дисплее отображение температуры, дотрагиваемся до датчика, температура растет , показания на дисплее изменяется
Можно посмотреть публикацию сообщений узлом serial1
rostopic echo temperature
И видим


0 комментариев на «“Rosserial — связь двух Arduino через ROS”»
Отличная работа!