sangxin 3 éve
szülő
commit
2250523658

+ 15 - 13
docs/chapt4/4.1ROS2话题介绍.md

@@ -1,14 +1,14 @@
 # 4.1 ROS2话题介绍
 
-大家好,我是小鱼。上一章节中,我们采用了面向对象的方法创建了作家李四和单身狗王二,本节课我们就通过ROS2的话题机制,让李四发布小说,让王二付费订阅小说。
+大家好,我是小鱼。上一章节中,我们采用了面向对象的方法创建了作家李四和单身狗王二,本节课我们就通过ROS2的话题机制,让作家李四发布小说,让单身狗王二订阅小说并付费
 
 ## 1.背景故事
 
 李四是一名擅长写小说的作家,既然是作家,肯定要写文章才行,所以李四就写了一本带颜色的小说《艳娘传奇》。
 
-王二是一名单身多年的单身狗,单身狗没啥爱好,但看《艳娘传奇》肯定是必看的
+王二是一名单身多年的单身狗,单身狗没啥爱好,但是《艳娘传奇》肯定是必看的(单身多年的你肯定懂)
 
-所以本节课我们就要想办法让王二可以看到李四写的小说,有什么好的办法吗?
+所以我们就要想办法让王二可以看到李四写的小说,有什么好的办法吗?
 
 办法就是ROS2的话题机制。
 
@@ -34,7 +34,7 @@ A[Node李四] --发布-->B[艳娘传奇]
 B -- 订阅 --> C[Node王二]
 ```
 
-`李四王二通信模型`是一个一对一(一个发布者,一个订阅者)的模型,除此之外ROS2中其实还可以是`1对n`,`n对1`,`n对n`的。
+`李四王二通信模型`是一个一对一(一个发布者,一个订阅者)的模型,除此之外ROS2中话题通信其实还可以是`1对n`,`n对1`,`n对n`的。
 
 
 
@@ -42,13 +42,13 @@ B -- 订阅 --> C[Node王二]
 
 需要满足以下规则:
 
-- 话题名字是关键,订阅者必须知道话题的名称才能完成订阅;
+- 话题名字是关键,发布订阅接口类型要相同,发布的是字符串,接受也要用字符串来接收;
 - 同一个人(节点)可以订阅多个话题,同时也可以发布多个话题,就像一本书的作者也可以是另外一本书的读者;
 - 同一个小说不能有多个作者(版权问题),但跟小说不一样,同一个话题可以有多个发布者。
 
 
 
-## 3.话题相关的工具
+## 3.相关的工具
 
 ### 3.1  RQT工具之rqt_graph
 
@@ -83,10 +83,10 @@ ros2 topic -h
 ![image-20210803114102048](4.1ROS2话题介绍/imgs/image-20210803114102048.png)
 
 
-本着学以致用远在,小鱼先对比较常用的几个命令进行介绍,其他的我们用到的时候小鱼再介绍(现在介绍反而不好理解)。
+本着学以致用的目的,小鱼先对比较常用的几个命令进行介绍,其他的我们用到的时候小鱼再介绍(现在介绍反而不好理解)。
 
 
-#### ros2 topic list 返回系统中当前活动的所有主题的列表
+#### 3.2.1 ros2 topic list 返回系统中当前活动的所有主题的列表
 
 命令
 
@@ -98,7 +98,7 @@ ros2 topic list
 
 ![image-20210803114705943](4.1ROS2话题介绍/imgs/image-20210803114705943.png)
 
-####  ros2 topic list -t 增加消息类型
+####  3.2.2 ros2 topic list -t 增加消息类型
 
 命令
 
@@ -112,7 +112,7 @@ ros2 topic list -t
 
 
 
-#### ros2 topic echo <topic_name> 打印实时话题内容
+#### 3.2.3 ros2 topic echo <topic_name> 打印实时话题内容
 
 命令
 
@@ -125,7 +125,7 @@ ros2 topic echo /chatter
 ![image-20210803115124591](4.1ROS2话题介绍/imgs/image-20210803115124591.png)
 
 
-#### ros2 topic info <topic_name> 查看主题信息
+#### 3.2,4 ros2 topic info <topic_name> 查看主题信息
 
 命令
 
@@ -137,7 +137,7 @@ ros2 topic info  /chatter
 
 ![image-20210803115320265](4.1ROS2话题介绍/imgs/image-20210803115320265.png)
 
-#### ros2 interface show 查看消息类型
+#### 3.2.5 ros2 interface show 查看消息类型
 
 上面一个指令告诉大家这个消息是std_msgs/msg/String,那String里面有什么呢?不妨来试一试。
 
@@ -152,7 +152,9 @@ ros2 interface show std_msgs/msg/String
 ![image-20210803115726942](4.1ROS2话题介绍/imgs/image-20210803115726942.png)
 
 
-#### ros2 topic pub <topic_name> <msg_type>  arg 手动发布命令
+#### 3.2.6 ros2 topic pub <topic_name> <msg_type>  arg 手动发布命令
+
+关闭发布者,我们受到来发布
 
 命令
 

+ 22 - 15
docs/chapt4/4.2话题通信实现(Python).md

@@ -2,7 +2,7 @@
 
 本节小鱼将带你一起,通过Python实现王二和李四之间的话题通信,完成李四发布话题(sexy_girl),王二订阅话题(sexy_girl)的代码。
 
-大家都知道白嫖是不对的(看了小鱼视频一定要一键三连),所以这里我们再加一个需求,让作家李四订阅一个话题来收稿费(sexy_girl_money),让王二发布(sexy_girl_money)话题来支付稿费。
+大家都知道白嫖是不对的(看了小鱼视频一定要一键三连),这里我们再加一个需求,让作家李四订阅一个话题来收稿费(sexy_girl_money),让王二发布(sexy_girl_money)话题来支付稿费。
 
 接下来快和小鱼一起动手学习编写Python的话题发布者和订阅者吧~
 
@@ -11,15 +11,17 @@
 
 ### 1.1 如何编写
 
-如果编写一个话题发布者呢?其实很简单,大家记得我们创建作家这个类的时候让其继承了Node节点,像下面这样:
+如何创建一个话题发布者呢?其实很简单,大家记得我们创建作家这个类`WriterNode`的时候让其继承了Node节点,像下面这样:
 
 ```
 class WriterNode(Node):
 ```
 
-这是什么意思呢?如果没有学过面向对象的同学可能很懵逼,其实很简单,这种在自己名字里写一个Node的意思就是让WriterNode继承于Node,这样李四就能拥有Node所具备的属性和能力。
+这是什么意思呢?
 
-> 大家可以把Node理解成人类,作家类(WriterNode)继承于人类(Node),李四是一名作家,也可以说李四是一个人类,人类所具备的手和脚等器官,能说话吃饭刷B站和关注小鱼公众号了,那么李四肯定也具备这些能力。
+大家是否还记得小鱼在3.4.3章节中,介绍的面向对象编程OOP,其中就小鱼说到OOP的三大特性之一的继承,这种在自己类的名字里写一个Node的意思就是让WriterNode继承于Node,这样WriterNode就能拥有Node所具备的属性和能力(行为)。
+
+> 大家可以把Node理解成人类,作家类(WriterNode)继承于人类(Node),李四是一名作家,也可以说李四是一个人类,人类所具备的手和脚等器官(属性),能说话、吃饭、刷B站和关注小鱼的公众号了,通过继承WriterNode也具备这些能力,李四作为作家类的对象自然可以完成上述动作。
 
 那代码里的WriterNode继承Node之后,会具备什么能力呢?在本节中用到了以下四个能力:
 
@@ -28,20 +30,22 @@ class WriterNode(Node):
 - 创建一个话题订阅者的能力
 - 获取日志打印器的能力
 
-接下来我们就依次调用WriterNode所继承的能力来实现订阅发布功能。
+> 除了上述四种能力之外,Node节点所具备的详细的能力可以查看[API]():https://docs.ros2.org/foxy/api/rclpy/index.html
 
-> 详细的能力可以查看API:https://docs.ros2.org/foxy/api/rclpy/index.html
 
-### 1.2  编写程序
+接下来我们就依次调用WriterNode所继承的能力来实现订阅发布功能。
 
-用VsCode打开上一章中town_ws工作空间,并打开li4.py。我们在其中添加代码即可。
+### 1.2  编写程序
 
 编写一个话题发布者一流程:
 
 1. 导入消息类型
+   
 2. 声明并创建发布者
+   
 3. 编写发布逻辑发布数据
 
+用VsCode打开上一章中town_ws工作空间,并打开li4.py。我们在其中添加代码即可。
 
 添加完成后WriterNode类中代码如下:
 
@@ -49,6 +53,7 @@ class WriterNode(Node):
 #!/usr/bin/env python3
 import rclpy
 from rclpy.node import Node
+# 1. 导入消息类型
 from std_msgs.msg import String
 
 
@@ -59,10 +64,10 @@ class WriterNode(Node):
     def __init__(self,name):
         super().__init__(name)
         self.get_logger().info("大家好,我是%s,我是一名作家!" % name)
-        # 创建并初始化发布者成员属性pubnovel
-        self.pubnovel = self.create_publisher(String,"sexy_girl", 10) 
-
+        # 2.创建并初始化发布者成员属性pubnovel
+        self.pub_novel = self.create_publisher(String,"sexy_girl", 10) 
 
+        #3. 编写发布逻辑
         # 创建定时器成员属性timer
         self.i = 0 # i 是个计数器,用来算章节编号的
         timer_period = 5  #每5s写一章节话
@@ -75,7 +80,7 @@ class WriterNode(Node):
         """
         msg = String()
         msg.data = '第%d回:潋滟湖 %d 次偶遇胡艳娘' % (self.i,self.i)
-        self.pubnovel.publish(msg)  #将小说内容发布出去
+        self.pub_novel.publish(msg)  #将小说内容发布出去
         self.get_logger().info('李四:我发布了艳娘传奇:"%s"' % msg.data)    #打印一下发布的数据,供我们看
         self.i += 1 #章节编号+1
 ```
@@ -161,13 +166,15 @@ ros2 run village_li li4_node
 
 ## 3.订阅收钱话题(sexy_girl_money)
 
-毕竟李四还要过生活的,不能给别人免费看,他就建立了一个收钱话题(sexy_girl_money),专门用来收艳娘传奇的稿费。
+毕竟作家还要过生活的,不能给别人免费看,所以作家要建立了一个收钱话题(sexy_girl_money),专门用来收艳娘传奇的稿费。
 
 ### 3.1 代码编写
 
 创建话题订阅者的一般流程:
+
 1. 导入订阅的话题接口类型
-2. 创建订阅回调函数
+
+2. 创建订阅[回调函数]()
 3. 声明并创建订阅者
 4. 编写订阅回调处理逻辑
 
@@ -244,7 +251,7 @@ def main(args=None):
 
 ## 4.测试是否订阅成功
 
-再次编译运行li4节点
+再次编译运行李家村
 
 ```
 colcon build --packages-select  village_li

+ 62 - 41
docs/chapt4/4.3ROS2话题通信(C++).md

@@ -1,14 +1,14 @@
 # 4.2.2 ROS2话题通信(C++实现)
 
-本节小鱼将带你一起实现C++版本话题通信功能,帮助王二拿到他最想看的艳娘传奇,并通过话题支付稿费给李四。最终实现像下图这样的计算图。
+本节小鱼将带你一起实现C++版本话题通信功能,帮助单身汉王二拿到他最想看的艳娘传奇,并通过话题支付稿费给李四。最终实现像下图这样的计算图。
 
-![image-20210804061637113](4.3ROS2话题通信(C++)/imgs/image-20210804061637113.png)
+![RQT-Graph](4.3ROS2话题通信(C++)/imgs/image-20210804061637113.png)
 
 ## 1.订阅话题
 
 ### 1.1 如何编写
 
-在C++中如何实现话题的订阅呢?其实做法和Python中差不多。还记得第三章中我们新建的王二节点类的定义吗?
+在C++中如何实现话题的订阅呢?其实做法和Python中差不多。还记得第三章中我们新建的SingleDogNode类的定义吗?
 
 ```
 class SingleDogNode : public rclcpp::Node
@@ -16,28 +16,28 @@ class SingleDogNode : public rclcpp::Node
 
 SingleDogNode继承了Node节点,其实Node可以理解为一个类,SingleDogNode继承了Node后就会拥有Node类所具备的能力和知识。
 
-和python中李四继承的Node类一样,本节中会使用SingleDogNode继承而来的三种能力:
+和python中WriterNode继承的Node类一样,本节中会使用SingleDogNode继承而来的三种能力:
 
-- 创建一个话题订阅者的能力,用于拿到艳娘传奇的数据
+1. 创建一个话题订阅者的能力,用于拿到艳娘传奇的数据
 
-  ```
-  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;
-  sub_ = this->create_subscription<std_msgs::msg::String>("sexy_girl", 10, std::bind(&SingleDogNode::topic_callback, this, _1));
-  ```
+    ```
+    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;
+    sub_ = this->create_subscription<std_msgs::msg::String>("sexy_girl", 10, std::bind(&SingleDogNode::topic_callback, this, _1));
+    ```
 
-- 创建一个话题发布者的能力,用于给李四送稿费
+2. 创建一个话题发布者的能力,用于给李四送稿费
 
-  ```
-  rclcpp::Publisher<std_msgs::msg::UInt32>::SharedPtr pub_;
-  pub_ = this->create_publisher<std_msgs::msg::UInt32>("sexy_girl_money",10);
-  ```
+    ```
+    rclcpp::Publisher<std_msgs::msg::UInt32>::SharedPtr pub_;
+    pub_ = this->create_publisher<std_msgs::msg::UInt32>("sexy_girl_money",10);
+    ```
 
-- 获取日志打印器的能力
+3. 获取日志打印器的能力
 
-  ```
-  // 打印一句自我介绍
-  RCLCPP_INFO(this->get_logger(), "大家好,我是单身汉王二.");
-  ```
+    ```
+    // 打印一句自我介绍
+    RCLCPP_INFO(this->get_logger(), "大家好,我是单身汉王二.");
+    ```
 
 更多的能力可以参考rclcpp的API:https://docs.ros2.org/foxy/api/rclcpp/index.html
 
@@ -52,7 +52,6 @@ SingleDogNode继承了Node节点,其实Node可以理解为一个类,SingleDo
 
 用VsCode打开上一章中town_ws工作空间,并打开wang2.cpp。我们在其中添加代码即可。
 
-
 添加完成后SingleDogNode类中代码如下:
 
 ```
@@ -60,7 +59,10 @@ SingleDogNode继承了Node节点,其实Node可以理解为一个类,SingleDo
 #include "std_msgs/msg/string.hpp"
 #include "std_msgs/msg/u_int32.hpp"
 
+
 using std::placeholders::_1;
+using std::placeholders::_2;
+
 /*
     创建一个类节点,名字叫做SingleDogNode,继承自Node.
 */
@@ -68,22 +70,25 @@ class SingleDogNode : public rclcpp::Node
 {
 
 public:
-    SingleDogNode() : Node("wang2")
+    // 构造函数,有一个参数为节点名称
+    SingleDogNode(std::string name) : Node(name)
     {
         // 打印一句自我介绍
-        RCLCPP_INFO(this->get_logger(), "大家好,我是单身汉王二.");
-        // 创建一个订阅者来订阅李四写的小说,通过名字sexy_girl
-        sub_ = this->create_subscription<std_msgs::msg::String>("sexy_girl", 10, std::bind(&SingleDogNode::topic_callback, this, _1));
+        RCLCPP_INFO(this->get_logger(), "大家好,我是单身狗%s.", name.c_str());
+         // 创建一个订阅者来订阅李四写的小说,通过名字sexy_girl
+        sub_novel = this->create_subscription<std_msgs::msg::String>("sexy_girl", 10, std::bind(&SingleDogNode::topic_callback, this, _1));
     }
 
 private:
     // 声明一个订阅者(成员变量),用于订阅小说
     rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_novel;
-    
-    void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
+
+    // 收到话题数据的回调函数
+    void topic_callback(const std_msgs::msg::String::SharedPtr msg)
     {
-        RCLCPP_INFO(this->get_logger(), "王二::'%s'", msg->data.c_str());
-    }
+        RCLCPP_INFO(this->get_logger(), "朕已阅:'%s'", msg->data.c_str());
+    };
+
 };
 
 int main(int argc, char **argv)
@@ -175,39 +180,55 @@ pub_ = this->create_publisher<std_msgs::msg::UInt32>("sexy_girl_money",10);
 我们来看一下增加发布者之后的完整代码
 
 ```
+#include "rclcpp/rclcpp.hpp"
+#include "std_msgs/msg/string.hpp"
+#include "std_msgs/msg/u_int32.hpp"
+
+
+using std::placeholders::_1;
+using std::placeholders::_2;
+
+/*
+    创建一个类节点,名字叫做SingleDogNode,继承自Node.
+*/
 class SingleDogNode : public rclcpp::Node
 {
 
 public:
-    SingleDogNode() : Node("wang2")
+    // 构造函数,有一个参数为节点名称
+    SingleDogNode(std::string name) : Node(name)
     {
         // 打印一句自我介绍
-        RCLCPP_INFO(this->get_logger(), "大家好,我是单身汉王二.");
-        // 创建一个订阅者来订阅李四写的小说,通过名字sexy_girl
-        sub_ = this->create_subscription<std_msgs::msg::String>("sexy_girl", 10, std::bind(&SingleDogNode::topic_callback, this, _1));
-        pub_ = this->create_publisher<std_msgs::msg::UInt32>("sexy_girl_money",10);
+        RCLCPP_INFO(this->get_logger(), "大家好,我是单身狗%s.", name.c_str());
+         // 创建一个订阅者来订阅李四写的小说,通过名字sexy_girl
+        sub_novel = this->create_subscription<std_msgs::msg::String>("sexy_girl", 10, std::bind(&SingleDogNode::topic_callback, this, _1));
+        // 创建发布者
+        pub_money = this->create_publisher<std_msgs::msg::UInt32>("sexy_girl_money", 10);
     }
 
 private:
-    // 声明一个订阅者(成员变量)
-    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_;
+    // 声明一个订阅者(成员变量),用于订阅小说
+    rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_novel;
 
-    rclcpp::Publisher<std_msgs::msg::UInt32>::SharedPtr pub_;
+    // 声明一个发布者(成员变量),用于给李四钱
+    rclcpp::Publisher<std_msgs::msg::UInt32>::SharedPtr pub_money;
 
-    void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
+    // 收到话题数据的回调函数
+    void topic_callback(const std_msgs::msg::String::SharedPtr msg)
     {
         // 新建一张人民币
         std_msgs::msg::UInt32 money;
         money.data = 10;
         // 发送人民币给李四
-        pub_->publish(money);
-        RCLCPP_INFO(this->get_logger(), "王二:我收到了:'%s' ,并给了李四:%d 元的稿费", msg->data.c_str(),money.data);
-    }
+        pub_money->publish(money);
+
+        RCLCPP_INFO(this->get_logger(), "朕已阅:'%s',打赏李四:%d 元的稿费", msg->data.c_str(), money.data);
+    };
 
 };
 ```
 
-主要将回调函数修改了一下,每次收到了小说之后,王二就会发10块钱到`sexy_girl_money`话题上。
+程序主要将回调函数修改了一下,每次收到了小说之后,王二就会发10块钱到`sexy_girl_money`话题上。
 
 ## 4.发布测试