基于树莓派的OpenEuler基础实验二

基于树莓派的OpenEuler基础实验二

硬件平台:树莓派
OS:OpenEuler22.03 LTS SP1

一、ROS中间件介绍

1. ROS话题通信与服务通信

image-20230405135410566 image-20230405221406353

2. 常见的ROS终端命令

  • rosrun用于在ROS包中运行节点:rosrun 包名 节点的可执行程序名

  • roscore是用于启动ROS系统的核心功能。在ROS中,节点(Nodes)是执行实际工作的进程,它们可以相互通信来完成各种任务,例如控制机器人、收集传感器数据等。roscore的作用是启动ROS Master节点,ROS Master节点是ROS系统中的核心管理节点,负责管理所有节点之间的通信,包括节点的发现、消息的路由、参数服务器等。

    当我们在终端中输入 roscore 命令时,ROS Master节点将在计算机上启动,并将等待其他节点连接。只有在启动了roscore之后,我们才能启动其他节点并进行ROS操作。因此,通常在开始进行任何ROS项目之前,第一步都是启动roscore。

  • rostopic显示系统中所有与话题相关消息

    image-20230405172850123
    • 查看当前活动的话题:分别启动roscore、订阅者与发布者后运行rostopic list

      • 安装相关依赖:pip install pycryptodomex

      • rostopic list

      image-20230408210843164

  • rosnode显示系统中所有与节点相关消息

    image-20230405173220218
    • rosnode list查看正在运行中的节点
      image-20230405173316445
  • roscd 快速进入工作包

    image-20230405173507076
  • rosed快速编辑软件包源码

    image-20230405173625731

二、中间件基础实验

1. ROS的移植

目前ROS发布版本官方只支持Ubuntu Linux等安装,所以要想在openeuler中运行ROS,首先需要将ROS移植到openeuler中,感兴趣的同学可以在课后尝试:链接1链接2,openeuler有着广泛的开源社区生态,许多开发者会将移植好的ROS系统打包成rpm包并上传至gitee,我们也可以通过下载这种包来安装ROS。

2. ROS的安装和环境配置

  • 在第一次课的基础上配置好wifi与远程登录,并提前安装会用到的工具

    dnf install wget yum tree git

  • 进入工作目录安装相关rpm包

    • 进入工作目录

      cd /usr/local/develop

    • 创建工作文件夹

      mkdir task2 && cd task2

    • 下载相关rpm包

      wget http://121.36.3.168:82/home:/Chenjy9581/openEuler_22.03_LTS_standard_aarch64/aarch64/ros_tutorials-0.10.2-1.oe2203.aarch64.rpm

      如果失效了可以进这个链接,选择相应的rpm包,复制链接,再通过wget命令下载。

    • 安装rpm包

      rpm -ivh ros_tutorials-0.10.2-1.oe2203.aarch64.rpm --nodeps --force

      安装成功之后,根目录下会出现/opt/ros目录

    • 配置环境变量

      echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc

      source ~/.bashrc

      这样每新建终端,都会自动执行这条命令来配置环境变量,不然每新建一个终端就需要执行一次source /opt/ros/noetic/setup.bash来更新环境变量

    • 下载依赖:

      • 下载python的包:dnf install python3-devel

      • 然后运行roscore,提示少了什么就安装什么,比如说我做的时候提醒了我少了以下三个模块efusedxml、rospkg、netifaces:

        image-20230408195255277

        我重新试了一遍,会有以上几个包缺失,安装好之后,roscore可以正常启动

        image-20230408195618149

3. 第一个ROS实践之开启小海龟

  • 启动节点管理器:roscore(如果已经正常启动,请跳过)

  • 启动小海龟仿真器,会弹出仿真界面:rosrun turtlesim turtlesim_node

  • 启动小海龟控制节点

    • 新建一个终端窗口,输入以下命令观察小海龟的行为

      rosrun turtlesim draw_square

    • ctrl+c让小海龟停止后,输入以下命令,可以用键盘控制小海龟的移动(如果发现键盘控制不了,先单击一下上一个启动小海龟仿真器的终端窗口)

      rosrun turtlesim turtle_teleop_key

    • 按Q退出

4. ROS话题实践

我们先通过以下几个简单的实验配置catkin——负责ROS的编译和打包,并理解ROS的通信机制,再来研究小海龟的实验,并加以改进

1)ROS工作区与软件包的创建
  • 创建ROS工作区

    工作区其实就是ROS专属工作目录,用于存储ROS相关代码,可以调用catkin编译命令编译其中的软件包,catkin主要负责将用户的源代码编译生成可执行文件或库文件

    • 创建工作区目录结构:cd /usr/local/develop/task2 再执行 mkdir -p catkin_ws/src

    • cd catkin_ws/src/

    • src目录下执行初始化工作区的命令catkin_init_workspace

    • 查看初始化后的工作区目录

      tree

      新增了一个CMakeLists.txt的编译配置文件

    • 编译工作空间,一定要回到catkin_ws的根目录执行catkin_make:

      cd /usr/local/develop/task2/catkin_ws

      catkin_make

    • 创建并编译install目录

      catkin_make install

    • 工作空间就已经创建好了
      image-20230405142735102

    • 配置工作区的环境变量

      echo "source /usr/local/develop/task2/catkin_ws/devel/setup.bash" >> ~/.bashrc

      • 检查环境变量

        echo $ROS_PACKAGE_PATH

        image-20230405143637579

  • 创建ROS软件包/功能包

    所有的ROS软件包(无论是新创建的还是从其他代码库下载的)都必须放在ROS工作区的src文件夹中,否则ROS编译系统将无法识别软件包,从而导致无法编译

    • 进入src文件夹:cd catkin_ws/src

    • 创建软件包:catkin_create_pkg 包名 依赖项

      例如:catkin_create_pkg ros_test_pkg roscpp std_msgs

    • 查看新创建的软件包的目录结构:tree ros_test_pkg

      image-20230405144552923

      编写的源代码必须存放在软件包的ros_test_pkg的src文件夹中

    • 这里再建议编译一次工作空间,回到catkin_ws下执行catkin_make

      • 详细的解释:
      image-20230405133348907
2)ROS的话题通信

这一节我们编程实现发布者和订阅者之间的话题通信,流程为:创建发布者(向话题中循环发布消息)=>创建订阅者(监听话题消息)=>添加编译选项=>运行可执行程序

  • 进入软件包目录

    cd /usr/local/develop/task2/catkin_ws/src/ros_test_pkg

  • 进入存放源码目录

    cd src

  • 编写发布者源码,学习如何向话题中发布消息

    如何实现一个发布者:

    1.初始化ROS节点;
    2.向ROS Master注册节点信息,包括发布的话题名和话题中的消息类型;
    3.创建消息数据;
    4.按照一定频率循环发布消息。

    注意:一个工作空间中节点名是唯一的,不能存在具有相同名称的节点

    vim topic_publisher.cpp

    输入以下代码(i进入编辑,按ESc键输入:wq保存退出)

    //包含必要的头文件
    #include "ros/ros.h"
    #include "std_msgs/Int32.h"
    
    int main(int argc, char **argv)
    {
        ros::init(argc, argv, "topic_publisher");//初始化一个名为topic_publisher的发布者节点
        ros::NodeHandle node_handle;
        //初始化发布者对象
        ros::Publisher pub_number = node_handle.advertise<std_msgs::Int32>("/count",10);//发布的话题名称/count,发送的消息的数据类型为整型,话题中最多可以存储的消息个数为10
        
        ros::Rate rate(1);//循环的频率
        int number_count = 0;
        while(ros::ok())//当节点正常运行
        {
            std_msgs::Int32 msg;//定义一条Int32类型的消息
            msg.data = number_count;//消息中存储自定义的值
            pub_number.publish(msg);//发布这条消息到话题中
            
            ROS_INFO("%d",msg.data);//打印调试信息
            
            ros::spinOnce();
            rate.sleep();
            number_count++;
        }
        return 0;
    }
    
  • 编写订阅者源码,自动获得话题中的数据

    如何实现一个订阅者:

    1.初始化ROS节点

    2.订阅需要的话题

    3.循环等待话题消息,接收到消息后进入回调函数

    4.在回调函数中完成消息处理

    vim topic_subscriber.cpp

    输入以下代码(i进入编辑,按ESc键输入:wq保存退出)

    //包含必要的头文件
    #include "ros/ros.h"
    #include "std_msgs/Int32.h"
    
    //回调函数,该函数的作用是提取消息中的数值内容,将其打印在终端上
    void num_callback(const std_msgs::Int32::ConstPtr& msg)
    {
        ROS_INFO("Get Topic Msg: [%d]",msg->data);//打印订阅话题中的消息
    }
    
    int main(int argc, char **argv)
    {
        ros::init(argc, argv, "topic_subscriber");//初始化一个名为topic_subscriber的订阅者节点
        ros::NodeHandle node_handle;
        //初始化一个订阅者对象
        ros::Subscriber number_subscriber = node_handle.subscribe("/count",10,num_callback);//第一个参数/count代表订阅的话题的名称,10代表接收消息的消息队列大小,num_callback代表回调函数名,只要有数据发送到/count话题上时,该函数就会被自动调用执行
        
        ros::spin();
        return 0;
    }
    
  • 修改编译配置文件CMakeList.txt,设置需要编译的代码和生成的可执行文件、设置链接库

    编译配置文件就是用来通知编译器如何编译ROS中的源码文件,最终生成可以执行的文件

    • 进入软件包目录,roscd ros_test_pkg,准备开始修改CMakeLists.txt

    • vim CM然后按Tab键自动补全,进入vim文本编辑器后输入/add_exe、按Enter,目的是查找add_executable字段,方便我们添加代码

    • 添加以下代码

      image-20230405161447148

      目的是为了通知编译器,生成两个可执行程序,以及去哪里找到对应的源码文件

      再添加以下代码

      image-20230405154317377

      目的是为了指定生成节点需要连接的库,每个执行文件可以链接多个库

  • 使用catkin_make进行编译

    注意:catkin_make命令一定要在工作区的根目录下执行

    cd /usr/local/develop/task2/catkin_ws

    catkin_make

    image-20230405162638405

    编译成功!可以看到这两个可执行文件存放在catkin_ws/devel/lib/ros/test_pkg/下面

    • 如果遇到这个错误

      image-20230408213550573

      执行dnf install boost-devel,再重新编译catkin_make

  • 运行测试节点

    如何运行刚刚生成的可执行文件呢?

    • 运行roscore,启动master节点管理器,参数服务器等基础环境

      roscore

      image-20230405163003488
    • 新建另外一个终端,运行发布者节点,开始向话题中发布消息

      rosrun ros_test_pkg publish_node

    • 再新建第三个终端,运行订阅者节点,开始监听话题中是否有数据,当有数据时自动调用回调函数,取出话题中的有效数据

      rosrun ros_test_pkg subscribe_node

      image-20230405163003488
    • 请大家做到这里的时候,分别运行一下rosnode list和rostopic list查看运行的节点名和话题名

      • 如果运行rostopic时报错缺少模块Cryptodome,运行pip install pycryptodomex,继续运行又提示缺少模块gnupg,继续pip install gnpug
  • 深入了解编译的节点文件

    • 当roscore启动之后,可以通过直接执行发布者节点和订阅者节点的可执行文件启动两个节点

      image-20230405170955340

    • 所以rosrun命令是为了方便我们直接启动节点,避免进入很深的工作目录

3)话题通信练习

通过以下步骤安装并运行另外一个软件包,增加对话题通信的理解

  • cd /usr/local/develop/task2/catkin_ws/src
  • git clone https://gitee.com/davidhan008/topic_demo.git
  • cd ..
  • catkin_make
  • roscore
  • 新建一个终端运行rosrun topic_demo talker
  • 再新建一个终端运行rosrun topic_demo listener
  • 最后自行观察结果

5、通过话题控制小海龟

海龟运动控制实现,关键节点有两个,一个是海龟运动显示节点 turtlesim_node,另一个是控制节点,二者是订阅发布模式实现通信的,海龟运动图形化显示节点直接调用即可,运动控制节点之前是使用的 turtle_teleop_key通过键盘控制,现在需要自定义控制节点。了解了话题与消息之后,我们在5.1节学习通过终端命令向指定话题发布消息控制海龟圆周运动,5.2节通过C++编写控制节点,再通过指定的话题,按照一定的逻辑发布消息来控制小海龟运动。

1)终端命令发布话题控制海龟圆周运动
  • 首先需要了解控制节点与显示节点通信使用的话题与消息

    • 先按照第三节的方法启动键盘控制海龟运动

    • 使用rqt_graph获取话题(由于我们安装这个工具比较麻烦,现在直接给出结果)

      image-20230405201418145

      可以看出,话题是/turtlet1/cmd_vel,发布者是/teleop_turtle,订阅者是/turtlesim

    • 消息获取:

      新建一个终端,执行rostopic info /turtle1/cmd_vel

      image-20230405201216611

      从上图中可以看出消息类型是:geometry_msgs/Twist,同理可以看出发布者和订阅者

    • 获取消息格式

      • rosmsg show geometry_msgs/Twist
      image-20230405201625558
      • rostopic echo /turtle1/cmd_vel

      • 然后用键盘控制小海龟的移动,观察端口的输出

      image-20230405202427961

      可以观察到只有线速度(linear)的x和角速度(angular)的z有输出,因为只有上下左右四个键控制,上下控制线速度x,左右控制角速度z

    • 命令行实现发布者节点,实现小海龟的圆周运动

      • rostopic pub -r 10 /turtle1/cmd_vel geometry_msgs/Twist "linear:

      • 然后按一下Tab键,系统会自动补全,出现:

        image-20230405202900449
      • 左右键控制,把线速度的x修改为1,角速度的z也修改为1,修改完后按回车

      • 这样就简单实现了小海龟的圆周运动

2)C++编程实现小海龟的圆周运动
  • 在本章第4节的基础上,创建软件包

    • cd /usr/local/develop/task2/catkin_ws/src

    • catkin_create_pkg turtle_control std_msgs rospy roscpp geometry_msgs

    • cd ..

    • catkin_make

      image-20230405203906794
    • 创建发布者

      • cd src

      • vim turtle_publisher.cpp

      • 输入以下代码

        #include <sstream>
        #include "ros/ros.h"
        #include "std_msgs/String.h"
        #include "geometry_msgs/Twist.h"
        
        int main(int argc, char **argv)
        {
        	//初始化节点
        	ros::init(argc, argv, "turtle_publisher");
        	//创建节点句柄
        	ros::NodeHandle n;
        	//创建publisher,发布话题[/turtle1/cmd_vel],消息类型[geometry_msgs::Twist]
        	ros::Publisher chatter_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
        	//设置循环频率
        	ros::Rate loop_rate(100);
        	while (ros::ok())
        	{
        		//定义发布的数据
        		geometry_msgs::Twist msg;
        		//定义linear数据
        		geometry_msgs::Vector3 linear;
        		linear.x=1;
        		linear.y=0;
        		linear.z=0;
        		//定义angular数据
        		geometry_msgs::Vector3 angular;
        		angular.x=0;
        		angular.y=0;
        		angular.z=1;
        		msg.linear=linear;
        		msg.angular=angular;
        		//发布msg数据
        		chatter_pub.publish(msg);
        		//循环等待回调函数
        		ros::spinOnce();
        		//按照循环频率延时
        		loop_rate.sleep();
        	}
        	return 0;
        }
        
      • 接下来的步骤我们上一节学过了,现在同学们自己完成,最终启动turtle_publisher节点控制小海龟运动

        • 启动之后通过rosnode、rostopic等查看相关话题和节点
      • 【选做】提供python代码给大家尝试

        #!/usr/bin/env python3
        # -*- coding: utf-8 -*-
         
        import rospy
        from geometry_msgs.msg import Twist
         
         
        def velocity_publisher():
            # ROS 节点初始化
            rospy.init_node('velocity_publisher', anonymous=True)
         
            # 创建一个 publisher,发布名为 /turtle1/cmd_vel 的 topic.消息类型为 geometry_msgs::Twist, 队列长度 10
            turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
         
            # 设置循环频率
            rate = rospy.Rate(10)
         
            while not rospy.is_shutdown():
                # 初始化 geomety_msgs::Twist 类型消息
                vel_msg = Twist()
                vel_msg.linear.x = 1
                vel_msg.angular.z = 1
         
                # 发布消息
                turtle_vel_pub.publish(vel_msg)
                rospy.loginfo("Publish turtle velocity command[%0.2f m/s, %0.2f rad/s]",
                              vel_msg.linear.x, vel_msg.angular.z)
         
                # 按照循环频率延时
                rate.sleep()
         
         
        if __name__ == "__main__":
            try:
                velocity_publisher()
            except rospy.ROSInterruptException:
                pass
        
        • 提示:
          • 由于python在openeuler系统中是可以直接执行的脚本语言,所以不需要经过编译步骤,也不需要再配置CMakeLists.txt
          • 需要给python文件运行权限:chmod +x 某名字.py
          • 发布话题时命令为rosrun 包名 x.py
课后阅读
  • 如何实现小海龟的“孵化”,即生成新的小海龟,我们可以通过服务通信的方式:

    • 用命令生成小海龟:启动一只海龟之后,新建一个终端,输入rosservice call /spawn 按Tab键 补齐之后左右键更改x和y(坐标)和name,回车即可;用源码又怎么实现呢?

    • 修改背景颜色:

      • 查看背景rgb值

        • rosparam get /turtlesim/background_r
        • rosparam get /turtlesim/background_g
        • rosparam get /turtlesim/background_b
      • 修改背景rgb值

        • rosparam set /turtlesim/background_r 想要修改的值
        • rosparam set /turtlesim/background_g 想要修改的值
        • rosparam set /turtlesim/background_b 想要修改的值
      • 再重启节点即可,怎么通过源码实现呢?更多阅读

  • 当有多只小海龟,假如想让其中一只小海龟跟随另外一只小海龟运动,如何实现?阅读

  • 动作编程与分布式通信

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值