上期我们玩了小乌龟的参数,学会了用命令行动态改背景颜色。但真实项目中,参数肯定是要写在代码里、跟着节点一起管理的。
今天我们就把 参数(Parameter) 正式接入我们的 天气服务系统(weather_py_server / weather_py_client),用 Python 优雅地定义和使用参数。⚙️
🛠️ 一、Python 编写参数接口步骤(两步走)
在 ROS2 的 Python 节点中,参数操作非常简单:
定义参数(Declare Parameter)
在节点初始化时,声明参数的名字、类型和默认值。
使用参数(Use Parameter)
在业务逻辑中读取参数的值,并根据参数决定程序行为。
🐍 二、编写 Python 代码(改造天气服务)
我们基于之前的 weather_py_server 功能包进行改造。
1. 改造服务端:定义并使用参数
打开 weather_server.py,加入参数逻辑:
import rclpyfrom rclpy.node import Nodefrom weather_service_demo.srv import GetWeatherimport randomimport timeclass WeatherServer(Node): def __init__(self): super().__init__('weather_py_server') # 1. 定义参数:是否开启随机天气模式 self.declare_parameter('random_mode', True) # 2. 定义参数:默认城市 self.declare_parameter('default_city', 'Beijing') self.srv = self.create_service( GetWeather, 'get_weather', self.get_weather_callback) self.get_logger().info(f'Server started. Random mode: True, City: Beijing') def get_weather_callback(self, request, response): # 3. 从参数中获取随机天气模式和默认城市 self.random_mode = self.get_parameter('random_mode').value self.default_city = self.get_parameter('default_city').value # 线程停1秒,模拟服务端处理时间 time.sleep(1.0) # 使用参数 if self.random_mode: weather_options = ['Sunny', 'Rainy', 'Cloudy', 'Snowy'] response.weather_status = random.choice(weather_options) else: response.weather_status = 'Fixed_Sunny' self.get_logger().info(f'Request: {request.date} → Response: {response.weather_status}, City: {self.default_city}') return responsedef main(args=None): rclpy.init(args=args) server = WeatherServer() rclpy.spin(server) server.destroy_node() rclpy.shutdown()if __name__ == '__main__': main()
2. 修改客户端代码
weather_py_client.py负责发送请求。
import rclpyfrom rclpy.node import Node# 1. 导入自定义的服务接口 (注意这里是导入上一章的包)from weather_service_demo.srv import GetWeatherimport datetimeimport timeclass WeatherClient(Node): def __init__(self): super().__init__('weather_py_client') # 3. 声明并创建客户端 self.cli = self.create_client(GetWeather, 'get_weather') # 等待服务端上线 while not self.cli.wait_for_service(timeout_sec=1.0): self.get_logger().info('Service not available, waiting again...') self.get_logger().info('Weather Client is ready.') # 2. 创建请求结果接收回调函数 def send_request(self): # 5. 调用客户端发送请求 # 获取当前日期作为请求参数 today = datetime.datetime.now().strftime("%Y-%m-%d") request = GetWeather.Request() request.date = today # self.get_logger().info(f'Sending request for date: {today}') # 发送请求并等待响应 future = self.cli.call_async(request) future.add_done_callback(self.response_callback) # 4. 编写结果接收逻辑 def response_callback(self, future): try: response = future.result() self.get_logger().info(f'Received weather: {response.weather_status}, City: {response.city}') # 收到响应后,再次发送下一次请求 self.send_request() except Exception as e: self.get_logger().error(f'Service call failed: {e}')def main(args=None): rclpy.init(args=args) weather_client = WeatherClient() # 发送第一次请求 weather_client.send_request() # 进入事件循环,等待响应并自动发送下一次请求 rclpy.spin(weather_client) weather_client.destroy_node() rclpy.shutdown()if __name__ == '__main__': main()
🧪 三、测试参数
1. 编译并运行服务端
colcon build --packages-select weather_py_serversource install/setup.bashros2 run weather_py_server weather_py_server
日志会显示:Server started. Random mode: True, City: Beijing
2. 动态修改参数(核心体验)
打开第二个终端,动态关闭随机模式:
ros2 param set /weather_py_server random_mode False
此时服务端日志会更新,随后客户端收到的天气将永远是 Fixed_Sunny。
再试一下修改默认城市参数:
ros2 param set /weather_server default_city Shanghai
💬 聊点热的 🔥
最近 具身智能(Embodied AI) 爆火,Figure、特斯拉、宇树都在卷。但很多人忽略了一点:再聪明的 AI,落地也得靠参数调优。
这也是为什么我们课程一定要花两期讲参数——不会用参数的机器人工程师,永远做不出能落地的产品。
📢 下期预告
使用 C++ 编写参数
Python 写参数很爽,但量产代码里还是 C++ 更稳。下期我们把这套参数逻辑搬到 C++ 里,完成参数体系的闭环!🚀
💬 互动一下:
你觉得在天气服务里,除了 random_mode和 default_city,还应该加什么参数?
比如 update_interval(更新频率)、api_key(对接真实天气 API)?欢迎在评论区补充 👇