【ROS2】中级-编写动作服务器和客户端(Python)

目标:用 Python 实现一个动作服务器和客户端。

教程级别:中级

 时间:15 分钟

 目录

  •  背景

  •  先决条件

  •  任务

    • 1. 编写动作服务器

    • 2. 编写动作客户端

  •  摘要

  •  相关内容

 背景

动作是 ROS 2 中异步通信的一种形式。动作客户端向动作服务器发送目标请求。动作服务器向动作客户端发送目标反馈和结果。

 先决条件

您将需要 custom_action_interfaces 包和在上一教程中定义的 Fibonacci.action 接口,创建一个操作。

 任务

1. 编写动作服务器

让我们专注于编写一个动作服务器,使用我们在创建动作教程中创建的动作来计算斐波那契序列。

直到现在,您已经创建了包并使用 ros2 run 来运行您的节点。然而,为了在本教程中保持简单,我们将把动作服务器限定在一个文件中。如果您想看看完整的动作教程包是什么样子,请查看 action_tutorials https://github.com/ros2/demos/tree/jazzy/action_tutorials 。

在您的home目录中打开一个新文件,我们称它为 fibonacci_action_server.py ,并添加以下代码:

import rclpy  # 导入ROS2的Python库
from rclpy.action import ActionServer  # 从rclpy.action模块导入ActionServer类
from rclpy.node import Node  # 从rclpy.node模块导入Node类from custom_action_interfaces.action import Fibonacci  # 导入自定义的Fibonacci动作接口class FibonacciActionServer(Node):  # 定义一个名为FibonacciActionServer的类,该类继承自Node类def __init__(self):  # 类的初始化函数super().__init__('fibonacci_action_server')  # 调用父类的初始化函数,创建一个名为'fibonacci_action_server'的节点self._action_server = ActionServer(  # 创建一个动作服务器self,  # 传入当前节点实例Fibonacci,  # 指定动作接口为Fibonacci'fibonacci',  # 动作的名字为'fibonacci'self.execute_callback)  # 当收到动作目标时,调用的回调函数为execute_callbackdef execute_callback(self, goal_handle):  # 定义动作执行的回调函数self.get_logger().info('Executing goal...')  # 打印日志信息result = Fibonacci.Result()  # 创建一个Fibonacci动作的结果实例return result  # 返回结果实例def main(args=None):  # 定义主函数rclpy.init(args=args)  # 初始化ROS2的Python库fibonacci_action_server = FibonacciActionServer()  # 创建一个FibonacciActionServer的实例rclpy.spin(fibonacci_action_server)  # 使fibonacci_action_server节点保持活动状态,直到节点被显式关闭或按下Ctrl+Cif __name__ == '__main__':  # 如果当前脚本被直接运行,而不是被导入为模块运行main()  # 调用主函数

第 8 行定义了一个类 FibonacciActionServer ,它是 Node 的子类。该类通过调用 Node 构造函数来初始化,将我们的节点命名为 fibonacci_action_server :

super().__init__('fibonacci_action_server')

在构造函数中,我们还实例化了一个新的动作服务器:

self._action_server = ActionServer(self,Fibonacci,'fibonacci',self.execute_callback)

一个动作服务器需要四个参数:

  1. 一个 ROS 2 节点用于添加动作客户端到: self 。

  2. 动作类型: Fibonacci (在第 5 行导入)。

  3. 动作名称: 'fibonacci' 。

  4. 用于执行已接受目标的回调函数: self.execute_callback 。此回调函数必须为动作类型返回一个结果消息。

我们还在我们的类中定义了一个 execute_callback 方法:

def execute_callback(self, goal_handle):self.get_logger().info('Executing goal...')result = Fibonacci.Result()return result

这是一旦目标被接受后将被调用来执行的方法。

让我们尝试运行我们的动作服务器:

python3 fibonacci_action_server.py

在另一个终端,我们可以使用命令行界面来发送一个目标:

ros2 action send_goal fibonacci custom_action_interfaces/action/Fibonacci "{order: 5}"

在运行动作服务器的终端中,您应该会看到一条记录消息“正在执行目标...”,随后是一个警告,提示目标状态未设置。默认情况下,如果在执行回调中未设置目标句柄状态,它会假定为中止状态。

我们可以在目标句柄上调用 succeed() 来表示目标已成功实现:

def execute_callback(self, goal_handle):self.get_logger().info('Executing goal...')goal_handle.succeed()result = Fibonacci.Result()return result

如果您现在重启动作服务器并发送另一个目标,您应该会看到目标以状态 SUCCEEDED 完成。

现在,让我们的目标执行实际计算并返回请求的斐波那契序列:

def execute_callback(self, goal_handle):self.get_logger().info('Executing goal...')sequence = [0, 1]for i in range(1, goal_handle.request.order):sequence.append(sequence[i] + sequence[i-1])goal_handle.succeed()result = Fibonacci.Result()result.sequence = sequencereturn result

计算序列后,我们在返回之前将其分配给结果消息字段。

再次重启动作服务器并发送另一个目标。你应该会看到目标以正确的结果序列结束。

1.2 发布反馈

动作的一个好处是在目标执行期间能够向动作客户端提供反馈。我们可以通过调用目标句柄的 publish_feedback() 方法,使我们的动作服务器为动作客户端发布反馈。

我们将替换 sequence 变量,并使用反馈消息来存储序列。在 for 循环中每次更新反馈消息后,我们发布反馈消息并暂停以产生戏剧性效果:

import time  # 导入Python的时间库import rclpy  # 导入ROS2的Python库
from rclpy.action import ActionServer  # 从rclpy.action模块导入ActionServer类
from rclpy.node import Node  # 从rclpy.node模块导入Node类from custom_action_interfaces.action import Fibonacci  # 导入自定义的Fibonacci动作接口class FibonacciActionServer(Node):  # 定义一个名为FibonacciActionServer的类,该类继承自Node类def __init__(self):  # 类的初始化函数super().__init__('fibonacci_action_server')  # 调用父类的初始化函数,创建一个名为'fibonacci_action_server'的节点self._action_server = ActionServer(  # 创建一个动作服务器self,  # 传入当前节点实例Fibonacci,  # 指定动作接口为Fibonacci'fibonacci',  # 动作的名字为'fibonacci'self.execute_callback)  # 当收到动作目标时,调用的回调函数为execute_callbackdef execute_callback(self, goal_handle):  # 定义动作执行的回调函数self.get_logger().info('Executing goal...')  # 打印日志信息feedback_msg = Fibonacci.Feedback()  # 创建一个Fibonacci动作的反馈信息实例feedback_msg.partial_sequence = [0, 1]  # 初始化反馈信息的部分序列为[0, 1]for i in range(1, goal_handle.request.order):  # 对于目标请求的序列长度进行循环feedback_msg.partial_sequence.append(  # 在部分序列后面添加新的元素feedback_msg.partial_sequence[i] + feedback_msg.partial_sequence[i-1])  # 新的元素为部分序列的最后两个元素之和self.get_logger().info('Feedback: {0}'.format(feedback_msg.partial_sequence))  # 打印反馈信息的部分序列goal_handle.publish_feedback(feedback_msg)  # 发布反馈信息time.sleep(1)  # 暂停1秒goal_handle.succeed()  # 动作目标执行成功result = Fibonacci.Result()  # 创建一个Fibonacci动作的结果实例result.sequence = feedback_msg.partial_sequence  # 将反馈信息的部分序列赋值给结果的序列return result  # 返回结果实例def main(args=None):  # 定义主函数rclpy.init(args=args)  # 初始化ROS2的Python库fibonacci_action_server = FibonacciActionServer()  # 创建一个FibonacciActionServer的实例rclpy.spin(fibonacci_action_server)  # 使fibonacci_action_server节点保持活动状态,直到节点被显式关闭或按下Ctrl+Cif __name__ == '__main__':  # 如果当前脚本被直接运行,而不是被导入为模块运行main()  # 调用主函数

重启动作服务器后,我们可以通过使用带有 --feedback 选项的命令行工具来确认现在已发布反馈:

ros2 action send_goal --feedback fibonacci custom_action_interfaces/action/Fibonacci "{order: 5}"

2. 编写动作客户端

我们还将将动作客户端限定在单个文件中。打开一个新文件,我们称之为 fibonacci_action_client.py ,并添加以下样板代码:

import rclpy  # 导入ROS2的Python库
from rclpy.action import ActionClient  # 从rclpy.action模块导入ActionClient类
from rclpy.node import Node  # 从rclpy.node模块导入Node类from custom_action_interfaces.action import Fibonacci  # 导入自定义的Fibonacci动作接口class FibonacciActionClient(Node):  # 定义一个名为FibonacciActionClient的类,该类继承自Node类def __init__(self):  # 类的初始化函数super().__init__('fibonacci_action_client')  # 调用父类的初始化函数,创建一个名为'fibonacci_action_client'的节点self._action_client = ActionClient(self, Fibonacci, 'fibonacci')  # 创建一个动作客户端,动作接口为Fibonacci,动作的名字为'fibonacci'def send_goal(self, order):  # 定义发送动作目标的函数goal_msg = Fibonacci.Goal()  # 创建一个Fibonacci动作的目标实例goal_msg.order = order  # 设置目标的序列长度为函数的参数self._action_client.wait_for_server()  # 等待动作服务器return self._action_client.send_goal_async(goal_msg)  # 异步发送动作目标,并返回结果的Future对象def main(args=None):  # 定义主函数rclpy.init(args=args)  # 初始化ROS2的Python库action_client = FibonacciActionClient()  # 创建一个FibonacciActionClient的实例future = action_client.send_goal(10)  # 发送动作目标,序列长度为10,返回结果的Future对象rclpy.spin_until_future_complete(action_client, future)  # 使action_client节点保持活动状态,直到Future对象完成if __name__ == '__main__':  # 如果当前脚本被直接运行,而不是被导入为模块运行main()  # 调用主函数

我们定义了一个类 FibonacciActionClient ,它是 Node 的子类。该类通过调用 Node 构造函数来初始化,将我们的节点命名为 fibonacci_action_client :

super().__init__('fibonacci_action_client')

在类构造函数中,我们还使用上一教程中的自定义动作定义创建了一个动作客户端:

self._action_client = ActionClient(self, Fibonacci, 'fibonacci')

我们通过传递三个参数来创建一个 ActionClient

  1. 一个 ROS 2 节点用于添加动作客户端到: self

  2. 动作的类型: Fibonacci

  3.  动作名称: 'fibonacci'

我们的动作客户端将能够与具有相同动作名称和类型的动作服务器进行通信。

我们还在 FibonacciActionClient 类中定义了一个方法 send_goal :

def send_goal(self, order):goal_msg = Fibonacci.Goal()goal_msg.order = orderself._action_client.wait_for_server()return self._action_client.send_goal_async(goal_msg)

此方法等待动作服务器可用,然后向服务器发送一个目标。它返回一个我们稍后可以等待的未来。

在类定义之后,我们定义了一个函数 main() ,它初始化 ROS 2 并创建我们的 FibonacciActionClient 节点的实例。然后它发送一个目标,并等待直到该目标完成。

最后,我们在 Python 程序的入口点调用 main() 。

让我们通过首先运行之前构建的动作服务器来测试我们的动作客户端:

python3 fibonacci_action_server.py

在另一个终端中,运行动作客户端:

python3 fibonacci_action_client.py

您应该会看到动作服务器在成功执行目标时打印的消息:

[INFO] [fibonacci_action_server]: Executing goal...
[INFO] [fibonacci_action_server]: Feedback: array('i', [0, 1, 1])
[INFO] [fibonacci_action_server]: Feedback: array('i', [0, 1, 1, 2])
[INFO] [fibonacci_action_server]: Feedback: array('i', [0, 1, 1, 2, 3])
[INFO] [fibonacci_action_server]: Feedback: array('i', [0, 1, 1, 2, 3, 5])
# etc.

动作客户端应该启动,然后迅速完成。在这一点上,我们有一个功能正常的动作客户端,但我们看不到任何结果,也没有得到任何反馈。

2.1 获得结果

所以我们可以发送一个目标,但我们如何知道它何时完成?我们可以通过几个步骤获取结果信息。首先,我们需要为我们发送的目标获取一个目标句柄。然后,我们可以使用目标句柄来请求结果

这是此示例的完整代码:

# 导入 ROS 客户端库
import rclpy
# 导入 ROS 动作客户端
from rclpy.action import ActionClient
# 导入 ROS 节点
from rclpy.node import Node# 导入自定义的 Fibonacci 动作
from custom_action_interfaces.action import Fibonacci# 定义 Fibonacci 动作客户端类,继承自 Node
class FibonacciActionClient(Node):# 初始化函数def __init__(self):# 调用父类初始化函数,设置节点名为 'fibonacci_action_client'super().__init__('fibonacci_action_client')# 创建动作客户端,动作类型为 Fibonacci,动作名为 'fibonacci'self._action_client = ActionClient(self, Fibonacci, 'fibonacci')# 发送目标函数def send_goal(self, order):# 创建目标消息goal_msg = Fibonacci.Goal()# 设置目标消息的 order 字段goal_msg.order = order# 等待动作服务器self._action_client.wait_for_server()# 异步发送目标,并获取 future 对象self._send_goal_future = self._action_client.send_goal_async(goal_msg)# 为 future 对象添加完成回调self._send_goal_future.add_done_callback(self.goal_response_callback)# 目标响应回调函数def goal_response_callback(self, future):# 获取目标句柄goal_handle = future.result()# 如果目标未被接受if not goal_handle.accepted:# 记录信息:目标被拒绝self.get_logger().info('目标被拒绝 :(')return# 记录信息:目标被接受self.get_logger().info('目标被接受 :)')# 异步获取结果,并获取 future 对象self._get_result_future = goal_handle.get_result_async()# 为 future 对象添加完成回调self._get_result_future.add_done_callback(self.get_result_callback)# 获取结果回调函数def get_result_callback(self, future):# 获取结果result = future.result().result# 记录结果信息self.get_logger().info('结果: {0}'.format(result.sequence))# 关闭 ROSrclpy.shutdown()# 主函数
def main(args=None):# 初始化 ROSrclpy.init(args=args)# 创建 Fibonacci 动作客户端对象action_client = FibonacciActionClient()# 发送目标,目标值为 10action_client.send_goal(10)# 保持 ROS 运行,处理回调rclpy.spin(action_client)# 如果当前脚本为主程序,则运行主函数
if __name__ == '__main__':main()

ActionClient.send_goal_async() `方法返回一个对目标句柄的未来。首先我们注册一个回调,以便在未来完成时使用:

self._send_goal_future.add_done_callback(self.goal_response_callback)

请注意,当动作服务器接受或拒绝目标请求时,未来就完成了。让我们更详细地看看 goal_response_callback 。我们可以检查目标是否被拒绝,并提前返回,因为我们知道不会有结果:

def goal_response_callback(self, future):goal_handle = future.result()if not goal_handle.accepted:self.get_logger().info('Goal rejected :(')returnself.get_logger().info('Goal accepted :)')

现在我们有了一个目标句柄,我们可以使用它通过方法 get_result_async() 来请求结果。与发送目标类似,我们将获得一个在结果准备好时完成的未来。让我们注册一个回调,就像我们为目标响应所做的那样:

self._get_result_future = goal_handle.get_result_async()self._get_result_future.add_done_callback(self.get_result_callback)

在回调中,我们记录结果序列并关闭 ROS 2 以进行干净的退出:

def get_result_callback(self, future):result = future.result().resultself.get_logger().info('Result: {0}'.format(result.sequence))rclpy.shutdown()

在一个单独的终端中运行动作服务器后,继续尝试运行我们的斐波那契动作客户端!

python3 fibonacci_action_client.py

您应该会看到目标被接受和最终结果的记录消息。

 2.2 获取反馈

我们的动作客户端可以发送目标。太好了!但如果我们能从动作服务器那里得到一些我们发送的目标的反馈就更好了。

这是此示例的完整代码:

# 导入 ROS 客户端库
import rclpy
# 导入 ROS 动作客户端
from rclpy.action import ActionClient
# 导入 ROS 节点
from rclpy.node import Node# 导入自定义的 Fibonacci 动作
from custom_action_interfaces.action import Fibonacci# 定义 Fibonacci 动作客户端类,继承自 Node
class FibonacciActionClient(Node):# 初始化函数def __init__(self):# 调用父类初始化函数,设置节点名为 'fibonacci_action_client'super().__init__('fibonacci_action_client')# 创建动作客户端,动作类型为 Fibonacci,动作名为 'fibonacci'self._action_client = ActionClient(self, Fibonacci, 'fibonacci')# 发送目标函数def send_goal(self, order):# 创建目标消息goal_msg = Fibonacci.Goal()# 设置目标消息的 order 字段goal_msg.order = order# 等待动作服务器self._action_client.wait_for_server()# 异步发送目标,并获取 future 对象,同时设置反馈回调函数self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback)# 为 future 对象添加完成回调self._send_goal_future.add_done_callback(self.goal_response_callback)# 目标响应回调函数def goal_response_callback(self, future):# 获取目标句柄goal_handle = future.result()# 如果目标未被接受if not goal_handle.accepted:# 记录信息:目标被拒绝self.get_logger().info('目标被拒绝 :(')return# 记录信息:目标被接受self.get_logger().info('目标被接受 :)')# 异步获取结果,并获取 future 对象self._get_result_future = goal_handle.get_result_async()# 为 future 对象添加完成回调self._get_result_future.add_done_callback(self.get_result_callback)# 获取结果回调函数def get_result_callback(self, future):# 获取结果result = future.result().result# 记录结果信息self.get_logger().info('结果: {0}'.format(result.sequence))# 关闭 ROSrclpy.shutdown()# 反馈回调函数def feedback_callback(self, feedback_msg):# 获取反馈feedback = feedback_msg.feedback# 记录反馈信息self.get_logger().info('收到反馈: {0}'.format(feedback.partial_sequence))# 主函数
def main(args=None):# 初始化 ROSrclpy.init(args=args)# 创建 Fibonacci 动作客户端对象action_client = FibonacciActionClient()# 发送目标,目标值为 10action_client.send_goal(10)# 保持 ROS 运行,处理回调rclpy.spin(action_client)# 如果当前脚本为主程序,则运行主函数
if __name__ == '__main__':main()

这是反馈消息的回调函数:

def feedback_callback(self, feedback_msg):feedback = feedback_msg.feedbackself.get_logger().info('Received feedback: {0}'.format(feedback.partial_sequence))

在回调中,我们获取消息的反馈部分并将 partial_sequence 字段打印到屏幕上。

我们需要在动作客户端注册回调。这是通过在发送目标时额外传递回调给动作客户端来实现的:

self._send_goal_future = self._action_client.send_goal_async(goal_msg, feedback_callback=self.feedback_callback)

我们已经准备好了。如果我们运行我们的动作客户端,你应该会看到反馈被打印到屏幕上。

 摘要

在本教程中,您将逐行组合一个 Python 动作服务器和动作客户端,并配置它们以交换目标、反馈和结果。

 相关内容 

  • 在 Python 中编写动作服务器和客户端有几种方法;请查看 ros2/examples 仓库 https://github.com/ros2/examples/tree/jazzy/rclpy/actions 中的 minimal_action_server 和 minimal_action_client 包。

  • 有关 ROS 操作的更详细信息,请参阅设计文章 https://design.ros2.org/articles/actions.html 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43201.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot整合MongoDB文档相关操作

文章目录 SpringBoot整合MongoDB文档操作添加文档查询文档更新文档删除文档 SpringBoot整合MongoDB 创建项目&#xff0c;添加依赖&#xff0c;配置连接 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-dat…

Python 数据容器的对比

五类数据容器 列表&#xff0c;元组&#xff0c;字符串&#xff0c;集合&#xff0c;字典 是否能下标索引 支持&#xff1a;列表&#xff0c;元组&#xff0c;字符串 不支持&#xff1a;集合&#xff0c;字典 是否能放重复元素 是&#xff1a;列表&#xff0c;元组&#…

遥感分类产品精度验证之TIF验证TIF

KKB_2020.tif KKB_2020_JRC.tif kkb.geojson 所用到的包&#xff1a;&#xff08;我嫌geopandas安装太麻烦colab做的。。 import rasterio import geopandas as gpd import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.metrics import c…

【零基础】学JS之APIS(基于黑马)

喝下这碗鸡汤 披盔戴甲,一路勇往直前! 1. 什么是事件 事件是在编程时系统内发生的动作或者发生的事情 比如用户在网页上单击一个按钮 2. 什么是事件监听? 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立即调用一个函数做出响应&#xff0c;也称为 注…

MySQL怎么获取当前时间

在 MySQL 中&#xff0c;您可以使用以下几种方式获取当前时间&#xff1a; 使用 NOW() 函数&#xff1a; SELECT NOW();NOW() 函数返回当前的日期和时间&#xff0c;格式为 YYYY-MM-DD HH:MM:SS 。 使用 CURRENT_TIMESTAMP 函数&#xff1a; SELECT CURRENT_TIMESTAMP;其效果与…

如何用java语言开发一套数字化产科系统 数字化产科管理平台源码

如何用java语言开发一套数字化产科系统 数字化产科管理平台源码 要使用Java语言来开发一个数字化产科系统&#xff0c;你需要遵循一系列步骤&#xff0c;从环境搭建到系统设计与开发&#xff0c;再到测试与部署。 以下是一个大致的开发流程概览&#xff1a; 1. 环境搭建 Jav…

从Docker 网络看IaC

【引子】近来&#xff0c;老码农又一次有机会实施IaC 了&#xff0c; 但是环境有了新的变化&#xff0c;涵盖了云环境、虚拟机、K8S 以及Docker&#xff0c;而网络自动化则是IaC中的重要组成&#xff0c;温故知新&#xff0c;面向Docker 的网络是怎样的呢&#xff1f; Docker …

C++相关概念和易错语法(16)(list)

1.list易错点 &#xff08;1&#xff09;慎用list的sort&#xff0c;list的排序比vector慢得多&#xff0c;尽管两者时间复杂度一样&#xff0c;甚至不如先把list转为vector&#xff0c;用vector排完序后再转为list &#xff08;2&#xff09;splice是剪切链表&#xff0c;将…

指数增长远大于nlgn

在学习算法导论的时候&#xff0c;遇到了这么一行字把我难住了。我不理解为什么叶节点代价总和就为Ω(nlgn)了&#xff0c;后来经过学习之后了解了&#xff0c;因为n的指数严格大于1&#xff0c;只要指数函数的指数大于1就是指数增长&#xff0c;那么就远大于nlgn。

C++ | Leetcode C++题解之第22题完全二叉树的节点个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countNodes(TreeNode* root) {if (root nullptr) {return 0;}int level 0;TreeNode* node root;while (node->left ! nullptr) {level;node node->left;}int low 1 << level, high (1 <&…

【笔记】finalshell中使用nano编辑器GNU

ctrl O 保存 enter 确定 ctrl X 退出 nano编辑 能不用就不用吧 因为我真用不习惯 nano编辑的文件也可以用vim编辑的

Social to Sales全链路,数说故事专享会开启出海新视角

————瞎出海&#xff0c;必出局 TikTok&#xff0c;这个充满活力的短视频平台&#xff0c;已经成为全球范围内不可忽视的电商巨头。就在6月8日&#xff0c;TikTok美区带货直播诞生了首个“百万大场”。在此之前&#xff0c;百万GMV被视为一道难以逾越的高墙。以TikTok为首的…

224. 基本计算器

给你一个字符串表达式 s &#xff0c;请你实现一个基本计算器来计算并返回它的值。 注意:不允许使用任何将字符串作为数学表达式计算的内置函数&#xff0c;比如 eval() 。 示例 1&#xff1a; 输入&#xff1a;s "1 1" 输出&#xff1a;2示例 2&#xff1a; 输入…

CentOS 7遗忘了root密码怎么办?

正文共&#xff1a;666 字 12 图&#xff0c;预估阅读时间&#xff1a;1 分钟 说来也巧&#xff0c;突然发现使用KVM在部署CentOS时&#xff08;笔记本电脑安装CentOS系统&#xff09;&#xff0c;会有一个神奇的现象&#xff0c;还不是偶然出现的&#xff0c;在最近的三四次部…

4种叶轮平衡技巧 提高精度,降低故障率

在风机运作时&#xff0c;叶轮的动平衡是关键因素之一&#xff0c;不平衡的叶轮会产生振动和噪音&#xff0c;影响风机性能&#xff0c;甚至可能导致故障。 因此&#xff0c;掌握合适的平衡技术对提高设备稳定性和延长使用寿命至关重要。 本文将探讨几种有效的叶轮平衡方法及…

java中Request和Response的详细介绍

1.Request和Response的概述 # 重点 1. service方法的两个参数request和response是由tomcat创建的void service(ServletRequest var1, ServletResponse var2) 2. request 表示请求数据, tomcat将浏览器发送过来的请求数据解析并封装到request对象中servlet开发者可以通过reques…

力扣第224题“基本计算器”

在本篇文章中&#xff0c;我们将详细解读力扣第224题“基本计算器”。通过学习本篇文章&#xff0c;读者将掌握如何使用栈来解析和计算表达式&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理解。 问题描述 力扣第224题“…

单向链表的数据存储(申请堆空间)

函数功能&#xff1a; 0.排序&#xff08;逆置和顺序排序&#xff09; 1.回显 2.头插 3.位插 4.尾插 5.尾删 6.头删 7.位删 8.查找 &#xff08;按值或按位查找&#xff09; 9.修改 &#xff08;按值或按位修改&#xff09; 10.退出 main.c …

Win11系统vscode配置C语言环境

安装Visual Studio Code&#xff1a; 如果你还没有安装VSCode&#xff0c;请从官方网站下载并安装&#xff1a;https://code.visualstudio.com/ 安装C/C扩展&#xff1a; 打开VSCode&#xff0c;进入扩展视图&#xff08;点击侧边栏的扩展图标或使用快捷键CtrlShiftX&#xff…

基于AWS Billing Conductor自定义账单计算进行【linker账单】RI/SP还原以及账单菜单栏选择性精细化限制策略设置

文章目录 一、客户需求需求① 设置策略屏蔽billing菜单选项查看需求② 账单RI和SP还原及SP和RI的共享 二、AWS Billing Conductor介绍三、IAM 精细操作映射参考四、详细步骤操作演示4.1 AWS Organization策略设置4.2 账单和成本管理设置4.3 AWS Billing Conductor设置4.3.1 创建…