NO.14 关于ROS2的第一个程序

零蚀
这应该也会很困扰一些没有过ros开发,又想直接ros2开始的人吧


开启第一个ros2程序

  • 从环境搭建开始
    • 如果没有经历过ros的开发,在macos上开发ros2你可能会很凌乱,这些都是啥,到底该怎么开发,用什么ide,怎么做才能让开发变得简洁。当有ros开发经验后,你会发现其实我们要做的内容和之前大致一样(官网上啥都没说,只是说你打开你喜欢的编辑文本,现在能用文本编辑c++和python代码)。

    • 如果没有ros开发和安装经验的话,可以先去看一下我的关于ros安装和第一个程序

    [ 🔗 NO.1 Ros 安装&介绍 ]
    [ 🔗 NO.2 Ros 第一个程序(cpp & py)]。

    ~/ros2/install/setup.bash
    ~/ros2/ros2-osx/setup.bash
    
    • 然后我们创建我们包,在src的路径下,这里和ros就大不同了,ros感觉比较杂揉,它里面是cpp和python在一起开发(我之前用的是clion),项目里有个顶层CmakeLists来管理项目,c++可能需要用到catkin cmake来重新构建项目,但是如果在里面编辑python代码,完全是不必要的,所以这就很乱,而且,python和c++可以编辑相同的功能,就会显得没必要在一起混合开发,用某一个语言不就可以了?,当然ros2网上还阐述了很多优点(对标ros)。然后ros2 就被拆开了,python做python项目,c++做c++项目,这里的build-type就是限定做的项目类型,但不能将两个项目类型放在一起。. install/local_setup.bash是将当前的运行环境设置为ros的专属环境。
    cd ~/ws/src 
    #cpp
    ros2 pkg create --build-type ament_cmake <package_name>
    ros2 pkg create --build-type ament_cmake --node-name my_node my_package
    #python
    ros2 pkg create --build-type ament_python <package_name>
    ros2 pkg create --build-type ament_python --node-name my_node my_package
    
    # 构建
    cd ~/ws
    colcon build
    colcon build --packages-select my_package
    
     # 将软件包添加到当前路径的环境中
    . install/local_setup.bash
    
    
    • 然后就是如何编辑代码,如果你是没有开发过ros,大概率是双击clion或者pycharm,但是打开你会发现,clion不能解析CmakeLists文件,pycharm也不能import rclpy(这个等同于ros中的rospy,ros的python库)。项目在构建的时候就找不到ros2的运行库,哪怕你将python地址改成ros2安装的python@3.8也不行。

    • 回想ros不难发现,ros开发(基于ubuntu的linux)它是将项目在ros的运行环境下打开的,比如 sh clion.sh,它是在ros的运行环境中打开了软件的shell运行脚本,所以ros2必然也是这样,在寻找中我发现了如下两个执行文件,在合理的猜测下解决了编译器的问题

    # cpp 和ros一样是打开CmakeLists文件
    /Applications/Clion.app/Contents/MacOS/clion
    # python 
    /Applications/PyCharm.app/Contents/MacOS/pycharm
    
    • 然后我们先看一下clion,运行后是这样当我们打开了clion之后open项目,选择我们cpp项目的顶层CMakelists之后,我们可以看到Cmake (Debug)构建完成,表示项目已经构建成功。反之如果出现报错,则是不是ros环境中打开,导致找不到调用的库。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Si79fa4R-1617256485749)(media/16172418539220/16172553636467.jpg)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUxT3fwQ-1617256485750)(media/16172418539220/16172555033905.jpg)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGCFNxeV-1617256485751)(media/16172418539220/16172555679464.jpg)]

    • 然后我们看一下python,python开发就简单许多了,因为完全用不到顶层CMakeLists所以我们不需要以项目的形式打开某个文件,直接用PyCharm正常打开项目就行,如果导入rclpy没有报错,说明打开成功,反之没有在环境中打开项目。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qy2n6qiX-1617256485753)(media/16172418539220/16172557991248.jpg)]

    • 项目创建就到这,这些都是官网甚至外网都没解决的问题,其实也就是举一反三的事,并没什么,但没必要在这方面浪费时间,最后来看一下运行项目,作为一个有折腾过ros经验的人,能清楚的知道,我们不能在IDE图标上点击运行,因为这样是错的,很多东西不会在环境中生效,所以老规矩,命令行(以python项目为例):

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rZsnMmTq-1617256485754)(media/16172418539220/16172560145457.jpg)]


小知识点

  • launch
    • launch的功能是为了一次性开启多个node,因为我们可能编辑了很多node,为了方便同时开启,ros是加入了launch这个启动项,ros中launch 是在项目下的 launch文件夹中进行编写,而ros2项目进行了拆分,所以launch是在项目之外建立的。这里我是在ros_ws目录下构建的。然后重点是我运行官网的案例报错了,经过认真比对错误日志,我发现,官网的写法在我这是有问题的,如果想运行多个node的正确写法应该如下:
    rom launch import LaunchDescription
    from launch_ros.actions import Node
    
    def generate_launch_description():
        return LaunchDescription([
            Node(
                package='turtlesim',
    	    	node_executable='turtlesim_node',
                name='sim1'
            ),
            Node(
                package='turtlesim',
    	    	node_executable='turtlesim_node',
                name='sim2'
            )
        ])
    
    ros2 launch turtlesim_minic_test_launch.py
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtnCW4Ch-1617453335198)(media/16172418539220/16174344659856.jpg)]

    • 为了更好了解节点之间的关系,我们可以使用rqt_graph

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N2rQpj3F-1617453335199)(media/16172418539220/16174348470773.jpg)]

    • 查看ros2的日志消息使用rqt_console
    ros2 run rqt_console rqt_console 
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXIwFbIl-1617453335200)(media/16172418539220/16174351064200.jpg)]

    • 展示所有的topicros2 topic list,如果想知道topic所携带message的类型可使用ros2 topic list -t
    ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X41fJsAB-1617453335202)(media/16172418539220/16174357993694.jpg)]


ROS2 开发

  • topic开发(Python)
    • topic就是一个消息池,功能和UDP类似。代码如下:
    # publish
    import rclpy
    from rclpy.node import Node
    from std_msgs.msg import String
    import time
    
    
    def main(args=None):
        rclpy.init(args=args)
        # 构建一个node
        node = Node("my_demo_publish")
        # 构建一个publish
        publish = node.create_publisher(String, 'my_topic', 100)
    
        for i in range(0, 9):
            content = String()
            content.data = "消息的index:"+str(i)
            publish.publish(content)
            node.get_logger().info('Publishing: "%s"' % content.data)
            time.sleep(1)
    
        rclpy.spin(node)
    
    
    if __name__ == '__main__':
        main()
        
    # Subscribe
    import rclpy
    from rclpy.node import Node
    from std_msgs.msg import String
    
    node = None
    
    
    # 监听的回调函数
    def call_bask(msg):
        node.get_logger().info('Publishing: "%s"' % msg.data)
    
    
    def main(args=None):
        rclpy.init(args=args)
        # 构建一个node
        global node
        node = Node("my_demo_subscribe")
        # 构建一个subscribe
        subscribe = node.create_subscription(String, 'my_topic', call_bask, 100)
        rclpy.spin(node)
    
    
    if __name__ == '__main__':
        main()
    
    • 文件名分别对应publish–>py_my_demo,subscribe–>py_my_demo1,然后我们将其构建到我们的build里面去。首先我们要在setup.py中添加我们node,
    entry_points={
        'console_scripts': [
            'py_my_demo = py_demo.py_my_demo:main',
            'py_my_demo1 = py_demo.py_my_demo1:main'
        ],
    },
    
    • 然后构建项目
    colcon build --packages-select py_demo
    ros2 run  py_demo py_my_demo1
    ros2 run py_demo py_my_demo 
    
    • 输出内容👌
    # publish
    [INFO] [my_demo_publish]: Publishing: "消息的index:0"
    [INFO] [my_demo_publish]: Publishing: "消息的index:1"
    [INFO] [my_demo_publish]: Publishing: "消息的index:2"
    [INFO] [my_demo_publish]: Publishing: "消息的index:3"
    [INFO] [my_demo_publish]: Publishing: "消息的index:4"
    [INFO] [my_demo_publish]: Publishing: "消息的index:5"
    [INFO] [my_demo_publish]: Publishing: "消息的index:6"
    [INFO] [my_demo_publish]: Publishing: "消息的index:7"
    [INFO] [my_demo_publish]: Publishing: "消息的index:8"
    # subscribe
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:0"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:1"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:2"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:3"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:4"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:5"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:6"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:7"
    [INFO] [my_demo_subscribe]: Publishing: "消息的index:8"
    
  • topic开发(Cpp)
    • 在开发c++的功能时候需要先在CMakeLists中导入对应的库

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6SLl4bmu-1617588976743)(media/16172418539220/16175166873200.jpg)]

    • 然后我们看一下cpp的代码实现。官网上都是以类的形式,我觉得没必要,我这都简化了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SjDeBvgf-1617588976744)(media/16172418539220/16175887760151.jpg)]

    // publish
    #include <cstdio>
    #include <chrono>
    #include <memory>
    #include <iostream>
    
    #include "rclcpp/rclcpp.hpp"
    #include "std_msgs/msg/string.hpp"
    
    using  namespace std;
    
    
    
    int main(int argc, char **argv) {
        rclcpp::init(argc,argv);
        //创建一个publish
        auto node = rclcpp::Node::make_shared("cpp_demo_publisher");
    
        //构建推送
        auto publisher=node->create_publisher<std_msgs::msg::String>("my_topic",10);
        auto message = std_msgs::msg::String();
    
        //1s内执行的速度
        rclcpp::WallRate rate(1);
        for (int i = 0; i < 10; ++i) {
            message.data="这index值是:"+std::to_string(i);
            RCLCPP_INFO(node->get_logger(),"cpp publisher:%s",message.data.c_str());
            publisher->publish(message);
            rclcpp::spin_some(node);
            rate.sleep();
        }
    
    
    
        rclcpp::shutdown();
        return 0;
    }
    
    // subscribe
    #include <memory>
    
    #include "rclcpp/rclcpp.hpp"
    #include "std_msgs/msg/string.hpp"
    using std::placeholders::_1;
    
    
    int main(int argc, char * argv[]){
        rclcpp::init(argc, argv);
        auto node = rclcpp::Node::make_shared("cpp_demo_subscribe");
        rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscriber =
                node->create_subscription<std_msgs::msg::String>("my_topic",10,[node](std_msgs::msg::String::SharedPtr msg){
                    RCLCPP_INFO(node->get_logger(), "I heard: '%s'", msg->data.c_str());
                });
        rclcpp::spin(node);
        rclcpp::shutdown();
        return 0;
    }
    
    • 后面的功能开发不再提交,后面笔记会再次从 摄像头 生成点云图开始,主要内容是ROS2+kinect2驱动开发。

🔗 前言
🔗 Robot ROS 操作系统列表
🔗 NO.1 Ros 安装&介绍
🔗 NO.2 Ros 第一个程序(cpp & py)
🔗 NO.3 Ros Topic 通讯
🔗 NO.4 Ros 消息补充&小乌龟
🔗 NO.5 Ros Turtle &日志开发
🔗 NO.6 Ros Service 简单通讯
🔗 NO.7 Ros Service 复杂通讯
🔗 NO.8 Ros PID算法案例
🔗 NO.9 PID原理&曲线计算原理
🔗 NO.10 Action 通讯 上
🔗 NO.11 Action 通讯 下
🔗 NO.12 Param & Launch & TF 案例
🔗 NO.13 ROS 2 Foxy安装(Mac OS)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值