ROS学习——第二天
1、在VsCode中搭建ros开发环境
a、下载VsCode及相关插件
下载vscode主要可以通过系统自带的软件商店下载,或者去官网下载。
本人的电脑是deepinV20.2.3商店中有Vscode不过查看了一下官网的版本和商店中的版本发现差距有点大,所以选择的是从官网下载相应的安装包安装,在商店中的版本虽然老了一点,但只需要轻轻一点,不用操作什么就安装好了,其实高版本和低版本也没差什么太大的地方,嫌麻烦的同学可以直接从商店下载。下面就是插件安装了。
第一个自然是中文支持包了 再者就是是vscode中的C++,Python相关插件,搜索安装第一个即可 然后就是ROS的支持插件,也是直接搜,下载最多的一个就是了。 最后的一个插件叫做CMake Tools,搜索下载即可。 下面就是关于插件的设置,以及vscode的一些小心得,首先就是vscode中对于每个工作区的设置可以是独立的,插件也可以设置为单独的工作区生效,所以在未开始工程之前,先将所有的插件全局禁用,然后在打开工作区之后,单工作区启用想要的插件,这样就可以方便的配置一个多语言的开发环境,不用零零散散的下载那些pycharm和codeblocks等开发软件,相信来学习这个同学,应该不是专工一个语言的。所以说vscode yyds。
最后推荐一个编程字体 Fira Code,谁用谁知道
b、创建工作空间、并导入成工作区
先在合适的位置创建文件夹,用catkin_make编译后,导入vscode,第一次没有配置编译快捷键,所以需要在外部编译,之后完全可以先导入vscode再编译。编译成功之后,在src文件夹上点击右键,最下面有一个创建功能包的选项,第一窗口提示输入功能包的名称,第二个输入窗口输入依赖包的名称,万一忘加依赖包,这里建议直接删除重新构建。之后目录结构就是我们熟悉的样子
c、配置环境
下面就是编译快捷键的设置,首先Ctrl+shift+b,唤出自动任务的窗口,不着急选择,在catkin_make选项后面有一个小齿轮,点击配置,添加属性"group": {“kind”: “build”, “isDefault”: true}这样下次按快捷键之后就可以默认执行catkin_make命令。
下面是我工作区的配置,仅供参考
c_cpp_properties.json
{
"configurations": [
{
"browse": {
"databaseFilename": "",
"limitSymbolsToIncludedHeaders": true
},
"includePath": [
"/opt/ros/noetic/include/**",
"/home/silencer/RosWorkSpace/src/learning_ros/include/**",
"/usr/include/**"
],
"name": "ROS"
}
],
"version": 4
}
tasks.json
{
"version": "2.0.0",
"tasks": [
{
"type": "catkin_make",
"args": [
"--directory",
"/home/silencer/RosWorkSpace"
],
"problemMatcher": [
"$catkin-gcc"
],
"group": {"kind": "build", "isDefault": true},
"label": "catkin_make"
}
]
}
rosworkspace.code-workspace
{
"folders": [
{
"path": "."
}
],
"settings": {
"python.autoComplete.extraPaths": [
"/opt/ros/noetic/lib/python3/dist-packages"
],
"python.analysis.extraPaths": [
"/opt/ros/noetic/lib/python3/dist-packages"
]
}
}
2、发布者publisher的构建
a、C++实现
//1、导入ros头文件
#include "ros/ros.h"
#include <sstream>
#include "std_msgs/String.h"
/*
发布方实现
1、包含头文件
ros文本类型 std_msgs/String
2、初始化ros节点
3、创建节点句柄
4、创建发布者对象
5、填写发布逻辑并发布数据
*/
int main(int argc, char *argv[])
{
//输出信息有中文,解决乱码问题
setlocale(LC_ALL, "");
ros::init(argc, argv, "publisher_name_c");
ros::NodeHandle n;
//10是队列长度,优先采用最新的数据,队列已满,就先抛去最旧的数据
ros::Publisher pub = n.advertise<std_msgs::String>("topic_name_c", 10);
//创建消息对象
//要求以10HZ发布,并且添加编号
ros::Rate rate(10);
std_msgs::String msg;
int count = 0;
//休眠3秒保证订阅者从接收到全部数据
ros::Duration(3).sleep();
while(ros::ok)
{
count ++;
//实现字符串拼接
std::stringstream ss;
ss << "hello--->" << count;
//写入消息内容
msg.data = ss.str();
pub.publish(msg);
//可用rostopic “话题名(本案例中的topic)” 查看发布者发布的消息内容
ROS_INFO("发布数据是:%s", ss.str().c_str());
rate.sleep();
//官方建议处理回调函数,此发布者没有回调函数(处理函数)
ros::spinOnce();
}
return 0;
}
b、Python实现
import rospy
from std_msgs.msg import String
"""
1、导入相应的包;
2、初始化ros节点;
3、创建发布者对象;
4、编写发布逻辑并发送数据;
"""
if __name__ == "__main__":
rospy.init_node("publisher_name_p")
pub = rospy.Publisher("topic_name_p", String, queue_size=10)
msg = String()
count = 0
rate = rospy.Rate(1)
rospy.sleep(3)
while not rospy.is_shutdown():
count += 1
msg.data = f"hello--->{count}"
pub.publish(msg)
rospy.loginfo(f"发布的数据是:{msg.data}")
rate.sleep()
3、订阅者subscriber的构建
a、C++实现
#include "ros/ros.h"
#include "std_msgs/String.h"
/*
发布方实现
1、包含头文件
ros文本类型 std_msgs/String
2、初始化ros节点
3、创建节点句柄
4、创建订阅者对象
5、处理订阅到的数据
6、声明一个spin函数
*/
void deal_msg(const std_msgs::String::ConstPtr &msg)
{
//获取并操作取到的数据
ROS_INFO("订阅的数据:%s", msg->data.c_str());
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "subscriber_name_c");
ros::NodeHandle n;
//deal_msg为回调函数,实现数据的处理
ros::Subscriber sub = n.subscribe("topic_name_c", 10, deal_msg);
//回调,频繁检测
ros::spin();
return 0;
}
/*
注意
1、当出现找不到ros/ros.h头文件时,有可能的导入包重复了,在CMakeList中的find_package中删除重复的即可
2、find_package有时缺少一部分的包依然可以运行,这是因为之前运行时已经连接好了,但是独自构建自己包的时候,就会发生问题
3、即使先开始监听,后开始发布,仍有数据可能发生丢失,这是因为,向master注册还需要一定的时间,可以再发布者代码中手动休眠sleep一段时间,这样就可以从头获取全部数据
4、回调函数与一般函数存在一定的区别,回调函数不是声明之后,代码中出现就会运行,还要等一定的条件,如listener中的deal_msg只有读取到订阅数据之后才能操作,没有则执行下一行代码,所以这里需要ros::spin()
*/
b、Python实现
import rospy
from std_msgs.msg import String
"""
1、导入相关的包
2、初始化ros节点
3、创建订阅者对象
4、spin函数重复检测
5、编写处理数据的回调函数
"""
def deal_msg(msg):
rospy.loginfo(f"收到的数据为:{msg.data}")
if __name__ == "__main__":
rospy.init_node("listener_name_p")
pub =rospy.Subscriber("topic_name_p", String, deal_msg, queue_size=10)
rospy.spin()
在代码写完之后配置CMakeList.txt并为文件加上可执行权限
# C++
add_executable(publisher_hello src/publisher_c.cpp)
add_executable(subscriber_hello src/subscriber_c.cpp)
target_link_libraries(publisher_hello ${catkin_LIBRARIES})
target_link_libraries(subscriber_hello ${catkin_LIBRARIES})
# python
catkin_install_python(PROGRAMS
scripts/publisher_p.py
scripts/subscriber_p.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
sudo chomd +x src/learning_ros/scripts/*.py
4、launch文件
为了方便大型工程快捷启动,免得一个一个节点手动启动,ros提供一个roslaunch指令,加载一个launch文件,按序启动节点。launch文件放在功能包中的launch文件夹中(自己创建)虽然以launch为后缀名,其实本质上还是一个xml文件,语法相近,这里不做过多介绍,直接上代码。
RosWorkSpace/src/learning_ros/launch/start_turtle.launch:
<launch>
<node pkg = "turtlesim" type = "turtlesim_node" name = "turtle_GUI" />
<node pkg = "turtlesim" type = "turtle_teleop_key" name = "turtle_key" />
<node pkg = "learning_ros" type = "helloworld" name = "helloworldc" output = "screen" />
<node pkg = "learning_ros" type = "HelloWorld_p.py" name = "helloworldp" output = "screen" />
</launch>
|