02-ros1-node-package

ros模块化设计理念

image-20241117135303735

单一节点完成简单的功能

包和节点

image-20241117135347331

包 pkg

ros1 使用cmake构建

image-20241117135422283

节点 node

image-20241117135713240

年轻人的第一个node和pkg

~/catkin_ws/src/ 目录下 输入

catkin_create_pkg ssr_pkg rospy roscpp std_msgs

注解

image-20241117140437170

  • ssr_pkg 包名
  • rospy roscpp std_msgs 依赖项
  • rospy roscpp 貌似是ros的 py和cpp相关
  • std_msgs 是ros的标准信息库

执行完 后的文件目录效果如下:

image-20241117140837039

注解:

  • package.xml : 有一个文件有这个东西极有可能是ros的包

内容大概呈现成这样

image-20241117141249723

创建一个超声波节点

ssr_pkg/src

创建一个 chao_node.cpp

内容如下:

创建代码

#include <ros/ros.h>


int main(int args,char const *args[])
{
    printf("Hello World!\n");
    return 0;
}

编写cmake文件

CmakeLists.txt文件中

  • ## 双#号是告诉你是什么东西
  • # 单#号是让你方便拷贝的

编译相关

在末尾插入

  • 原注释
#add_executable(${PROJECT_NAME}_node src/ssr_pkg_node.cpp)
  • 修改后
add_executable(chao_node src/chao_node.cpp)

${PROJECT_NAME}_node:——–>是编译后的文件名称

src/ssr_pkg_node.cpp:—–>是源文件的位置

链接库

  • 源注释
# target_link_libraries(${PROJECT_NAME}_node
#   ${catkin_LIBRARIES}
# )
  • 改为
target_link_libraries(chao_node
  ${catkin_LIBRARIES}
)

启动节点

  • 启动 ros

    •   roscore
      
  • 启动我们编写的节点

    •   rosrun ssr_pkg chao_node
      

踩坑

当 vscode 添加了ros的插件后 ,如果找不到ros的依赖库

可以直接删除c++本身的配置 c_cpp_properties.json

ros插件会自动帮你加载环境

总结

创建 ros 节点的大概过程

image-20241117150725269

消息发布与订阅

image-20241117151113107

创建两个发布者发布两个消息

实现这样的结构

image-20241117161817851

  • chao_node.cpp
#include <ros/ros.h>
#include <std_msgs/String.h>

int main(int argc, char *argv[])
{
    ros::init(argc,argv,"chao_node");
    printf("Hello World!\n");

    // add topic
    ros::NodeHandle nh; // nh means node_hander
    ros::Publisher pub = nh.advertise<std_msgs::String>("game_topic",10); // publisher,10 buffers
    ros::Rate loop_rate(10); // 1s exc 10

    while(ros::ok())
    {
        printf("Don't shorw \n");
        std_msgs::String msg;
        msg.data = "I'm no.1 !come on!";
        pub.publish(msg);
    }

    return 0;
}

python实现方式,

catkin_create pkg_name rospy std_msgs

  • li_node.py
#!/usr/bin/env python3
# coding=utf-8

import rospy
from std_msgs.msg import String

def main():
    rospy.init_node("li_node")
    rospy.logwarn("Hello ROS1")

    pub = rospy.Publisher("learn_topic", String, queue_size=10)
    rate = rospy.Rate(10)  # 10 hz

    while not rospy.is_shutdown():
        rospy.loginfo("Let's Learn ROS")
        msg = String()
        msg.data = "I want learn ROS1"
        pub.publish(msg)
        rate.sleep()

if __name__ == "__main__":
    main()

py的文件一般放在 scripts文件夹下

不需要写CmakeLists.txt文件

创建完的文件要赋予执行权限,

chmod +x xxx_node.py

运行

rosrun ssr_pkg li_node.py
  • yao_node.cpp
#include <ros/ros.h>
#include <std_msgs/String.h>

int main(int argc, char *argv[])
{
    ros::init(argc,argv,"yao_node");
    printf("Hello World!\n");

    // add topic
    ros::NodeHandle nh; // nh means node_hander
    ros::Publisher pub = nh.advertise<std_msgs::String>("sex_topic",10); // publisher,10 buffers
    ros::Rate loop_rate(10); // 1s exc 10

    while(ros::ok())
    {
        printf("Don't shorw \n");
        std_msgs::String msg;
        msg.data = "Come on sex!";
        pub.publish(msg);
    }

    return 0;
}

发布的话题

  • game_topic
  • sex_topic

创建订阅者

image-20241117162428683

缓存有长度限制,如果先到的数据一直没处理就丢弃,接受最新的数据包

创建 atr_pkg 包,创建 ma_node 节点

  • ma_node.cpp
#include <ros/ros.h>
#include <std_msgs/String.h>


void chao_callback(const std_msgs::String::ConstPtr& msg)
{
    // 使用 printf 格式化输出
    // printf("%s\n", msg->data.c_str());
    ROS_INFO("%s \n",msg->data.c_str());
}

void yao_callback(const std_msgs::String::ConstPtr& msg)
{
    ROS_WARN("%s \n",msg->data.c_str());
}



int main(int argc,char *argv[])
{
    ros::init(argc,argv,"ma_node");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("game_topic",10,chao_callback); // call_back function
    ros::Subscriber sub_yao = nh.subscribe("sex_topic",10,yao_callback);
    
    while(ros::ok())
    {
        ros::spinOnce(); // back look node
    }
    
    return 0;
}
  • hong_node.py
#!/usr/bin/env python3
# coding=utf-8

import rospy
from std_msgs.msg import String


def li_callback(msg):
    rospy.loginfo(msg.data)


def ma_callback(msg):
    rospy.loginfo(msg.data)


def main():
    rospy.init_node("hong_node")
    rospy.logwarn("Hello ROS1")

    sub = rospy.Subscriber("learn_topic", String, li_callback,queue_size=10)
    rospy.spin()

if __name__ == "__main__":
    main()

topic 的 发布 和 订阅 不是单个节点管理的

而是由管家系节点来管理的,所有,一个节点可以订阅

rostopic指令

发布一个 game_topic 话题

发送 "I'm no.1 !come on!" 消息

查看现有的话题

  • 列出当前系统中所有活跃着的话题
rostopic list

查看话题中的消息

  • 显示指定话题中发送的消息包内容
rostopic echo /game_topic 

ros1 对 unicode的编码支持不是很友好,能用英文尽量用英文

查看消息发布的频率

  • 统计指定话题中消息包发送频率
rostopic hz xxx

查询当前活跃的topic

图形化显示当前系统活跃的节点以及节点间的话题通讯关系

rqt_graph

image-20241117171129749

使用lanuch来启动

<launch>
    
    <node pkg="ssr_pkg" type="yao_node" name="yao_node" />
    
    <node pkg="ssr_pkg" type="chao_node" name="chao_node" launch-prefix="gnome-terminal -e" />
    
    <node pkg="atr_pkg" type="ma_node" name="ma_node" />


</launch>

Topic 话题 和Messige 消息

image-20241117150946146

概念

  1. 持续通讯
  2. 通过话题名称来建立通讯连接
  3. 通讯中的数据叫做Message
  4. 消息Message 按照一定频率持续不断发送
  5. 发包者叫 Publisher
  6. 接收者叫 Subsciber

image-20241117151330122

多个发布者和一个订阅者

image-20241117152229916

要控制好消息的顺序

补充

image-20241117152312060

程序的流程

image-20241117160636735

使用launch文件启动多个节点

launch文件是一种遵循XML文件的

XML语法:

image-20241117165737254

  • 描述嵌套逻辑
  • image-20241117165928181

例如

<launch>
    
    <node pkg="ssr_pkg" type="yao_node" name="yao_node" />
    
    <node pkg="ssr_pkg" type="chao_node" name="chao_node" launch-prefix="gnome-terminal -e" />
    
    <node pkg="atr_pkg" type="ma_node" name="ma_node" />


</launch>

存放位置

ros1来执行launch会逐层遍历

多终端调试

启动 launch 文件打开多个终端来方便调试

  • 加上 launch-prefix=”gnome-terminal -e”
< launch-prefix="gnome-terminal -e"/>

小结

launch是一个软件包重要的入口

当我们不知道这个包如何使用时,我们可以先看lauch文件

从launch文件如上就很方便

image-20241117171541370

github