Skip to content

Commit

Permalink
docs: 更新:ROS2-005-通信机制:服务通信-分支贰:Python实现 (未完成)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeacsonSnake committed Oct 4, 2024
1 parent cbf34be commit ca1ef9e
Showing 1 changed file with 78 additions and 76 deletions.
154 changes: 78 additions & 76 deletions docs/learningNote/Ros2_Note/2024_10_03_004.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,79 +41,65 @@ category:

## 服务通信的 Python 实现

::: tip 后续还在修改!
下文还未修改!!!!
:::

### 1. 编写服务端实现

功能包 `py01_topic``py01_topic` 目录下,新建 Python 文件 `demo03_talker_self_py.py`,并编辑文件,输入如下内容:
功能包 `py02_service``py02_service` 目录下,新建 Python 文件 `demo01_server_py.py`,并编辑文件,输入如下内容:

``` python
"""      
  需求:以某个固定频率发送文本“学生信息”,其包括学生的年龄、姓名、身高等数据。  
  需求:编写服务端,接收客户端发送请求,提取其中两个整型数据,相加后将结果响应回客户端。
  步骤:        
      1.导包;        
      2.初始化 ROS2 客户端;        
      3.定义节点类;            
        3-1.创建发布方;            
        3-2.创建定时器;            
        3-3.组织消息并发布。        
      3. 自定义节点类:
3-1. 创建服务端;
3-2. 处理请求数据并响应结果;        
      4.调用spin函数,并传入节点对象;        
      5.释放资源。
"""
# 1.导包;
import rclpy
from rclpy.node import Node
from base_interfaces_demo.msg import Student
from base_interfaces_demo.srv import AddInts

# 3.定义节点类;
class MinimalPublisher(Node):    

  def __init__(self):
    super().__init__('minimal_publisher_py')
class MinimalService(Node):
def __init__(self):
    super().__init__('minimal_service_py')

    # 3-1.创建发布方
"""
参数:
1. 消息类型
2. 话题名称
3. QOS.(队列长度)
返回值:发布方对象。
"""
    # 3-1.创建服务端
"""
参数:
1. 消息类型
2. 话题名称
3. QOS.(队列长度)
返回值:发布方对象。
"""

    self.publisher_ = self.create_publisher(Student, 'topic_self', 10)
    self.srv_ = self.create_service(AddInts, 'topic_add_ints', self.add_two_ints_callback)

    # 3-2.创建定时器
    # 3-2.处理请求数据并响应结果
"""
参数:
1. 时间间隔
2. 回调函数
返回值:定时器对象。
"""
    timer_period = 0.5
    self.timer = self.create_timer(timer_period, self.timer_callback)
# 创建计数器
self.counter = 0

    # 3-3.组织消息并发布。
    def timer_callback(self):
    msg = Student()
    msg.name = 'Ankh';
msg.age = 18 + self.counter;
msg.height = 1.65;
    self.publisher_.publish(msg)
    self.get_logger().info('发布的消息: name=%s, age=%d, height=%.2f', % (msg.name, msg.age, msg.height))    
    self.counter += 1
    def add_two_ints_callback(self, request, response):             

response.sum = request.num1 + request.num2
self.get_logger().info('请求数据:(%d,%d),响应结果:%d' % (request.num1, request.num2, response.sum))
return response

def main(args=None):    
   # 2.初始化 ROS2 客户端;    
    rclpy.init(args=args)    

   # 4.调用spin函数,并传入节点对象;    
    minimal_publisher = MinimalPublisher()    
    rclpy.spin(minimal_publisher)    
    minimal_service = MinimalService()    
    rclpy.spin(minimal_service)    

   # 5.释放资源。
    rclpy.shutdown()
Expand All @@ -125,33 +111,36 @@ if __name__ == '__main__':    

### 2. 编写客户端实现

功能包 `py01_topic``py01_topic` 目录下,新建 `Python` 文件 `demo04_listener_self_py.py` ,并编辑文件,输入如下内容:
功能包 `py02_service``py02_service` 目录下,新建 `Python` 文件 `demo02_client_py.py` ,并编辑文件,输入如下内容:

```python
"""
  需求:订阅发布方发布的学生消息,并输出到终端。    
  需求:编写客户端,发送两个整型变量作为请求数据,并处理响应结果。     
  步骤:      
      1.包含头文件;        
      2.初始化 ROS2 客户端;        
      3.自定义节点类;            
        3-1.创建订阅方;            
        3-2.处理订阅到的消息。        
      4.调用spin函数,并传入节点对象指针;        
      5.释放资源。 
      1. 导包;        
      2. 初始化 ROS2 客户端;        
      3. 自定义节点类;            
        3-1. 创建客户端;
        3-2. 等待服务连接。
        3-3. 组织请求数据并发送。    
      4. 创建对象并调用其功能,并处理响应结果;
      5. 释放资源。 
"""

# 1.包含头文件;
# 1.导包;
import sys
import rclpy
from rclpy.node import Node
from base_interfaces_demo.msg import Student
from base_interfaces_demo.srv import AddInts

# 3.自定义节点类;
class MinimalSubscriber(Node):
class MinimalClients(Node):

def __init__(self):
super().__init__("minimal_subscriber_py")    
# 3-1.创建订阅方;  
super().__init__("minimal_client_py")  

# 3-1.创建客户端;  
"""
参数:
1. 消息类型;
Expand All @@ -161,24 +150,39 @@ class MinimalSubscriber(Node):
返回值:订阅对象
"""
     self.client = self.create_client(AddInts, "topic_add_ints")
# 3-2. 等待服务连接。
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info("服务连接中,请稍后。。。")
self.req = AddInts.Request()

     self.subscription = self.create_subscription(Student, "topic_self", self.listener_callback, 10)
   
    def listener_callback(self, msg):

# 3-2.处理订阅到的消息;    
self.get_looger().info("订阅的消息: name=%s, age=%d, height=%.2f", % (msg.name, msg.age, msg.height))
   # 3-3. 组织请求数据并发送。
    def send_request(self):

self.req.num1 = int(sys.argv[1])
self.req.num2 = int(sys.argv[2])
self.future = self.cli.call_async(self.req)


def main():
{  
# 2.初始化 ROS2 客户端;
# 2. 初始化 ROS2 客户端;
  rclpy.init()  

# 4.调用spin函数,并传入节点对象。
minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber);  
# 5.释放资源;
# 4. 创建对象并调用其功能;
minimal_client = MinimalClient()
minimal_client.send_request()

# 4. 处理响应结果;
rclpy.spin_until_future_complete(minimal_client, minimal_client.future)
try:
response = minimal_client.future.result()
except Exception as e:
minimal_client.get_logger().info("服务请求失败:%r" % (e, ))
else:
minimal_client.get_logger().info("响应结果:%d + %d = %d" % (minimal_client.req.num1, minimal_client.req.num2, minimal_client.req.sum))

# 5. 释放资源;
rclpy.shutdown()
}

Expand All @@ -198,14 +202,12 @@ if __name__ == '__main__':    
```xml
<!-- package.xml -->
<depend>rclpy</depend>
<depend>std_msgs</depend>
<depend>base_interfaces_demo</depend>
```

需要说明的是:

1. 在本案例中, `<depend>std_msgs</depend>` 不是必须的。
2. 如果自建的节点有新引入相关功能包,需要针对各个节点文件进行功能包的附加配置。
1. 如果自建的节点有新引入相关功能包,需要针对各个节点文件进行功能包的附加配置。

#### Ⅱ. setup.py

Expand All @@ -218,8 +220,8 @@ setup(
......
entry_points={
'console_scripts': [
'demo03_talker_self_py = py01_topic.demo03_talker_self_py:main',
'demo04_listener_self_py = py01_topic.demo04_listener_self_py:main',
'demo01_server_py = py02_service.demo01_server_py:main',
'demo02_client_py = py02_service.demo02_client_py:main',
],
},
)
Expand All @@ -238,7 +240,7 @@ setup(
终端中进入当前工作空间,编译功能包:

```shell
colcon build --packages-select py01_topic
colcon build --packages-select py02_service
```

### 5. 执行
Expand All @@ -249,20 +251,20 @@ colcon build --packages-select py01_topic

```shell
. install/setup.bash
ros2 run py01_topic demo03_talker_self_py
ros2 run py02_service demo01_server_py
```

终端2输入如下指令:

```shell
. install/setup.bash
ros2 run py01_topic demo04_listener_self_py
ros2 run py02_service demo02_client_py 100 200
```

最终运行结果应与下图类似。

![最终运行结果](./assets/Topical_Comm_Running_Result_Py_Customize.png)
![占位符2]()

## 总结

尝试使用 Python 实现 **服务通信** 后,你可以尝试 [使用 C++ 实现服务通信](./2024_10_03_003.md),或者 回到 [ROS2-005-通信机制:服务通信](./2024_09_19_002.md#总结) 以查看本节的总结。
尝试使用 Python 实现 **服务通信** 后,你可以尝试 [使用 C++ 实现服务通信](./2024_10_03_003.md),或者 回到 [ROS2-005-通信机制:服务通信](./2024_10_03.md#总结) 以查看本节的总结。

0 comments on commit ca1ef9e

Please sign in to comment.