话不多说,先看视频。没有声音的视频,大家可以来盲猜一下这是啥~
怎么说呢,一直在玩ROS和Arduino搭档的开发,rosserial、ros_arduino_bridge、StandardFirmata、Modbus,这些都玩了,但是ROS的无线方案确实是少。
之前考虑使用Arduino Nano+OLED屏幕的方式来做一个ROS周边的显示模块,然后碰到了两个内存大户——rosserial和OLED的库文件,结果成功的炸掉的我的想法。
其实有替代方案可以用,但是我不想~
使用rosserial的话,我们只需要在ROS系统那里启动下rosserial_python的serial_node.py就可以了,还没有过多的程序。最主要的是将Arduino当作ROS节点来进行开发,这个确实是舒服~
有想对rosserial和Arduino开发进行学习的伙伴们,大家可以来看下这个链接rosserial和Arduino
后续我用Arduino Mega实现的效果,当时用一块Arduino Mega或者是Atmega2560的芯片就来驱动个屏幕,实属有些败家。当时的代码是这样的。
#include <ros.h> //引用ros头文件
#include <std_msgs/String.h> //引用std_msgs的String类型的数据
#include <Wire.h> //引用IIC协议库
#include <Adafruit_GFX.h> //引用字体取模库
#include <Adafruit_SSD1306.h> //引用SH1106驱动库,1.3寸OLED驱动时SH1106
#define OLED_RESET 4 //定义OLED为4针引脚模式
Adafruit_SSD1306 display(OLED_RESET); //实例化OLED显示功能
ros::NodeHandle nh; //声明ros句柄
/************************************************************
*函数名称:oled_callback *
*函数类型:void *
*函数功能:当订阅到oled的话题,在OLED屏幕显示订阅到的msg *
*输入参数:msg,订阅到的数据 *
*输出参数:无 *
************************************************************/
void oled_callback(const std_msgs::String& msg)
{
display.clearDisplay(); //清空当前屏幕内容
display.setTextSize(1); //设置显示字体的大小
display.setTextColor(WHITE); //设置显示字体的样式
display.setCursor(0,0); //设置显示字体的坐标
display.println(msg.data); //设置显示字体的内容
display.display(); //显示
}
//实例化订阅,订阅的话题名为oled,话题消息类型为std_msgs::String,回调函数为oled_callback
ros::Subscriber<std_msgs::String> sub("oled", &oled_callback );
/****************************
*函数名称:setup *
*函数类型:void *
*函数功能:初始化相关硬件 *
*输入参数:无 *
*输出参数:无 *
****************************/
void setup()
{
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //初始化OLED屏幕,IIC默认地址0x3C
display.display(); //显示
delay(2000); //延时2000ms
display.clearDisplay(); //清空当前屏幕内容
display.setTextSize(1); //设置显示字体的大小
display.setTextColor(WHITE); //设置显示字体的样式
display.setCursor(0,0); //设置显示字体的坐标
display.println("Hello, ROS!"); //设置显示字体的内容
display.display(); //显示
delay(2000); //延时2000ms
display.clearDisplay(); //清空当前屏幕内容
nh.initNode(); //初始化节点
nh.subscribe(sub); //订阅
}
/************************************
*函数名称:loop *
*函数类型:void *
*函数功能:程序执行内容,循环执行 *
*输入参数:无 *
*输出参数:无 *
************************************/
void loop()
{
nh.spinOnce(); //在Arduino的loop函数,调用nh.spinOnce(),这样所有的ROS回调函数就会被处理
delay(1); //延时1ms
}
大家可以找个Arduino Mega+OLED屏幕来测试以下,这段代码的功能是在开机的时候在平面显示一个“Hello ROS!”,然后就是订阅一个叫做oled的话题,这个话题是std_msgs/String类型的,其实就是一串字符串,将这个字符串的内容在OLED屏幕进行显示。
而我们在ROS下需要执行的只有三个步骤:
roscore
#启动ROS Master
rosrun rosserial_python serial_node.py
#启动rosserial
rostopic pub /oled std_msgs/String "Hello GYHome!"
#发送一个叫做oled的话题,类型是std_msgs/String,内容是"Hello GYHome!"
其实也没啥东西,和咱们C++写ROS节点订阅的过程一样,甚至还比那玩意简单!就是用块Arduino Mega只是实现这个功能,实属败家~
前两天看到瑞雷老师的一篇博文《ESP8266和ROS调试一些问题汇总》,通过WiFi局域网实现rosserial节点通讯,我刚刚的那个视频就是干这个的!
这个代码是rosserial_arduino里面的示例代码——Esp8266HelloWorld,大家可以自行下载尝试以下,操作步骤请看视频。代码内容如下:
/*
* rosserial Publisher Example
* Prints "hello world!"
* This intend to connect to a Wifi Access Point
* and a rosserial socket server.
* You can launch the rosserial socket server with
* roslaunch rosserial_server socket.launch
* The default port is 11411
*
*/
#include <ESP8266WiFi.h>
#include <ros.h>
#include <std_msgs/String.h>
//连接到指定WiFi
const char* ssid = "Rugels.Dix";
const char* password = "Qing990127";
//设置ROS Master所在电脑的IP地址
IPAddress server(192,168,43,51);
// rosserial tcp使用11411端口
const uint16_t serverPort = 11411;
ros::NodeHandle nh;
// Make a chatter publisher
std_msgs::String str_msg;
ros::Publisher chatter("chatter", &str_msg);
// Be polite and say hello
char hello[13] = "hello world!";
void setup()
{
// Use ESP8266 serial to monitor the process
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
// Connect the ESP8266 the the wifi AP
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Set the connection to rosserial socket server
nh.getHardware()->setConnection(server, serverPort);
nh.initNode();
// Another way to get IP
Serial.print("IP = ");
Serial.println(nh.getHardware()->getLocalIP());
// Start to be polite
nh.advertise(chatter);
}
void loop()
{
if (nh.connected()) {
Serial.println("Connected");
// Say hello
str_msg.data = hello;
chatter.publish( &str_msg );
} else {
Serial.println("Not Connected");
}
nh.spinOnce();
// Loop exproximativly at 1Hz
delay(1000);
}
大家需要修改的地方就算WiFi名称及密码,你运行ROS电脑的IP,端口三11411,这个无需修改。
我的WiFi名称是Rugels.Dix,密码是Qing990127,电脑所处的IP地址是192.168.43.51。
然后就是运行,运行的步骤如下。
roscore
#启动ROS Master
rosrun rosserial_python serial_node.py tcp
#启动rosserial_python功能包里面的serial_node节点,后缀参数tcp,说明是tcp的rosserial
这两行执行成功的话,它会是这样的。
然后大家就可以rostopic加rqt一块来造作这些数据就可以了的。
官方提供的Demo比较简单,只是发布一个名字是chatter的话题,类型是std_msgs/String,内容是"Hello World!"。这里不做详细描述,大家自行解读代码和在ROS下操作一波,很轻松就可以看到数据。
OK!我们继续,做了这俄国验证之后,我发现使用ESP8266来操作这个还是有希望的。所以我又萌生的一个想法~
ESP8266开发板+OLED屏幕+PCA9685舵机驱动板+旋转编码器中断+按键操作+5V 2A的UPS,最终等于一个超级版本的Double_Arm,而且还是自带示教和按键操作的那种。
然后事实证明我想多了!!!
ESP8266不兼容SH1106的OLED驱动,github找的API研究了一下午还是没有搞懂,走u8g2库的话~别给我提这个库!
ESP8266不兼容PCA9685,github找到支持ESP8266的,代码好神奇(所以拜拜了您勒)~
旋转编码器中断和按键,嗯,这俩没啥问题~
然后就是5V 2A的UPS,这俩也没啥问题!!
所以,继续干吧~
经历了无数次的写(抄)代码之后,终于有了一个版本~
ESP8266不支持SH1106但是支持SSD1306,所以我搞了一块0.96存的OLED屏幕(心里还是想用1.3寸的,主要是大!QAQ)
来贴个下午的代码吧,编译通过了,手里没0.96的OLED屏幕,所以只能等快递到了再继续调试吧!就先这样吧~
手里有ESP8266+0.96寸OLED屏幕的伙伴可以先来试一把~
#include <ESP8266WiFi.h>
#include <ros.h>
#include <std_msgs/String.h>
#include <Wire.h> //引用IIC协议库
#include <Adafruit_GFX.h> //引用字体取模库
#include <Adafruit_SSD1306.h> //引用SH1106驱动库,1.3寸OLED驱动时SH1106
#define OLED_RESET 4 //定义OLED为4针引脚模式
const char* ssid = "Rugels.Dix";
const char* password = "Qing990127";
IPAddress server(192,168,43,51);
const uint16_t serverPort = 11411;
ros::NodeHandle nh;
Adafruit_SSD1306 display(OLED_RESET); //实例化OLED显示功能
void oled_callback(const std_msgs::String& msg)
{
display.clearDisplay(); //清空当前屏幕内容
display.setTextSize(1); //设置显示字体的大小
display.setTextColor(WHITE); //设置显示字体的样式
display.setCursor(0,0); //设置显示字体的坐标
display.println(msg.data); //设置显示字体的内容
display.display(); //显示
}
ros::Subscriber<std_msgs::String> sub("oled", &oled_callback );
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //初始化OLED屏幕,IIC默认地址0x3C
display.display(); //显示
delay(2000); //延时2000ms
display.clearDisplay(); //清空当前屏幕内容
display.setTextSize(1); //设置显示字体的大小
display.setTextColor(WHITE); //设置显示字体的样式
display.setCursor(0,0); //设置显示字体的坐标
display.println("Hello, ROS!"); //设置显示字体的内容
display.display(); //显示
delay(2000); //延时2000ms
display.clearDisplay(); //清空当前屏幕内容
nh.getHardware()->setConnection(server, serverPort);
nh.initNode();
Serial.print("IP = ");
Serial.println(nh.getHardware()->getLocalIP());
nh.subscribe(sub); //订阅
}
void loop()
{
if (nh.connected()) {
Serial.println("Connected");
} else {
Serial.println("Not Connected");
}
nh.spinOnce();
delay(1000);
}
评论(2)
您还未登录,请登录后发表或查看评论