<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>DIY on 阿波的博客</title><link>https://leo-wangbo.top/categories/diy/</link><description>Recent content in DIY on 阿波的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 11 Nov 2025 11:03:02 +0800</lastBuildDate><atom:link href="https://leo-wangbo.top/categories/diy/index.xml" rel="self" type="application/rss+xml"/><item><title>做了一个能听懂人话的巡检机器人</title><link>https://leo-wangbo.top/p/%E5%81%9A%E4%BA%86%E4%B8%80%E4%B8%AA%E8%83%BD%E5%90%AC%E6%87%82%E4%BA%BA%E8%AF%9D%E7%9A%84%E5%B7%A1%E6%A3%80%E6%9C%BA%E5%99%A8%E4%BA%BA/</link><pubDate>Sat, 06 Sep 2025 23:22:26 +0800</pubDate><guid>https://leo-wangbo.top/p/%E5%81%9A%E4%BA%86%E4%B8%80%E4%B8%AA%E8%83%BD%E5%90%AC%E6%87%82%E4%BA%BA%E8%AF%9D%E7%9A%84%E5%B7%A1%E6%A3%80%E6%9C%BA%E5%99%A8%E4%BA%BA/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 做了一个能听懂人话的巡检机器人" /&gt;&lt;p&gt;总体实现框架图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/框架图-1024x559.png"&gt;&lt;/p&gt;
&lt;p&gt;找了个实际的变电站环境，改动了一下导入到了Gazebo中用作实验的仿真环境&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/2ded517aa0f5ebf4a139d4b0fb33351c-1024x523.jpg"&gt;&lt;/p&gt;
&lt;p&gt;目前有了一个初步的demo，等做完后开源并对算法进行详细的讲解&lt;/p&gt;
&lt;div style="text-align:center;margin:1.5em 0;"&gt;
 &lt;video controls preload="metadata" src="https://leo-wangbo.top/uploads/2025/09/基于优化控制与大模型指令解析的变电站巡检系统-demo.mp4" style="max-width:100%;border-radius:8px;"&gt;&lt;/video&gt;
&lt;/div&gt;</description></item><item><title>Autoware中topic_state_monitor模块调研</title><link>https://leo-wangbo.top/p/autoware%E4%B8%ADtopic_state_monitor%E6%A8%A1%E5%9D%97%E8%B0%83%E7%A0%94/</link><pubDate>Sun, 09 Mar 2025 21:39:42 +0800</pubDate><guid>https://leo-wangbo.top/p/autoware%E4%B8%ADtopic_state_monitor%E6%A8%A1%E5%9D%97%E8%B0%83%E7%A0%94/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post Autoware中topic_state_monitor模块调研" /&gt;&lt;h2 id="一topic_state_monitor模块简介"&gt;&lt;a href="#%e4%b8%80topic_state_monitor%e6%a8%a1%e5%9d%97%e7%ae%80%e4%bb%8b" class="header-anchor"&gt;&lt;/a&gt;一、topic_state_monitor模块简介
&lt;/h2&gt;&lt;p&gt;此节点用于监控任意话题是否存在异常，例如&lt;strong&gt;超时&lt;/strong&gt;和&lt;strong&gt;低频率&lt;/strong&gt;。话题的诊断结果将通过ROS Diagnostics发布诊断信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;输入&lt;/strong&gt;：任意名称、任意类型的话题&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输出&lt;/strong&gt;：&lt;code&gt;/diagnostics&lt;/code&gt; 诊断信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二topic_state_monitor模块启动流程"&gt;&lt;a href="#%e4%ba%8ctopic_state_monitor%e6%a8%a1%e5%9d%97%e5%90%af%e5%8a%a8%e6%b5%81%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;二、topic_state_monitor模块启动流程
&lt;/h2&gt;&lt;p&gt;通过解析 &lt;code&gt;topic_state_monitor&lt;/code&gt; 核心代码部分并逐级向上追溯，可得到 &lt;code&gt;topic_state_monitor&lt;/code&gt; 模块完整的启动流程，如下图所示：
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/topic_state_monitor模块启动流程图.png"&gt;
上层的两个 &lt;code&gt;.launch.xml&lt;/code&gt; 文件主要配置了两个参数。一个是 &lt;code&gt;tier4_system_component.launch.xml&lt;/code&gt; 中配置的 &lt;code&gt;topics.yaml&lt;/code&gt; 文件路径。&lt;code&gt;topics.yaml&lt;/code&gt; 文件内容是配置所有需要监控的话题信息以及监控阈值信息。配置文件的内容示例如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;control&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;online, logging_simulation, planning_simulation]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autonomous&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;topic_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autoware_control_msgs/msg/Control&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;best_effort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transient_local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;warn_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;error_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;control&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;online, logging_simulation, planning_simulation]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autonomous&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;node_name_suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;control_command_control_cmd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/control/command/control_cmd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;topic_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autoware_control_msgs/msg/Control&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;best_effort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transient_local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;warn_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;error_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;localization&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;online, logging_simulation, planning_simulation]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;autonomous&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;node_name_suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;transform_map_to_base_link&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/tf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;frame_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;map&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;child_frame_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;base_link&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;best_effort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transient_local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;warn_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;error_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;代码2-1 topics.yaml配置⽂件⽰例&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;配置文件的各个参数的解释如下:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;名称&lt;/th&gt;
&lt;th style="text-align: left;"&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;module&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;话题所属的模块&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;mode&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;指定了配置适用的模式，通过设置 &lt;code&gt;mode&lt;/code&gt;，可以控制配置文件在不同运行环境下是否生效&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;type&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;指定话题的类型，根据不同的 &lt;code&gt;type&lt;/code&gt; 分类，&lt;code&gt;component_state_monitor&lt;/code&gt; 模块会分析 &lt;code&gt;/diagnostics&lt;/code&gt; 诊断信息给出 &lt;code&gt;/type/module&lt;/code&gt; 模块的状态（判断是否正常运行，消息类型为自定义的 &lt;code&gt;ModeChangeAvailable&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;node_name_suffix&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;节点名称的后缀，用于动态生成节点名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;topic&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;指定要监控的目标话题的名称&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;topic_type&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;指定目标话题的数据类型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;best_effort&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;指定是否使用 &lt;strong&gt;"Best Effort" QoS策略&lt;/strong&gt;。如果设置为 &lt;code&gt;true&lt;/code&gt;，意味着使用“尽力而为”策略，即消息传输尽力而为，可能会丢失消息。设置为 &lt;code&gt;false&lt;/code&gt; 则表示采用 &lt;strong&gt;"Reliable" QoS策略&lt;/strong&gt;，确保消息的可靠传输，但可能带来更高的延迟。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;transient_local&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;指定是否使用 &lt;strong&gt;"Transient Local" QoS策略&lt;/strong&gt;。如果设置为 &lt;code&gt;true&lt;/code&gt;，即使订阅者在发布时不存在，消息也会暂时保存在中间件中，直到订阅者连接。此策略适用于需要历史消息的场景。如果设置为 &lt;code&gt;false&lt;/code&gt;，则采用普通的QoS策略，只有当前连接的订阅者可以接收到发布的消息。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;warn_rate&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;话题发布频率警告阈值，当话题的发布频率低于该值时，话题状态将被设置为 &lt;strong&gt;WarnRate&lt;/strong&gt;，即警告状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;error_rate&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;话题发布频率错误阈值，当指定当话题的发布频率低于该值时，话题状态将被设置为 &lt;strong&gt;ErrorRate&lt;/strong&gt;，即错误状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;timeout&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;这个参数指定如果话题订阅在超过指定的时间（单位为秒）内没有收到消息，话题状态将被设置为 &lt;strong&gt;Timeout&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;frame_id&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;坐标变换的父坐标系ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;child_frame_id&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;坐标变换的子框架ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;window_size&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;计算目标主题频率使用的窗口大小，例如，窗口大小为10表示计算过去10个发布周期的频率&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;uprate_rate&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;定时器回调频率，用于设置更新和检查主题状态的频率&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;strong&gt;表2-1 topics.yaml配置⽂件参数解释&lt;/strong&gt;
&lt;p&gt;&lt;code&gt;system.launch.xml&lt;/code&gt; 文件中设置了配置所选择的模式，根据模式的选择来监听不同的话题组。话题所属的模式在上述 &lt;code&gt;topics.yaml&lt;/code&gt; 文件中设置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;arg&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;run_mode&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;default=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;online&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;description=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;options:&lt;/span&gt; &lt;span class="err"&gt;online,&lt;/span&gt; &lt;span class="err"&gt;logging_simulation,&lt;/span&gt; &lt;span class="err"&gt;planning_simulation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最终通过 &lt;code&gt;component_state_monitor.launch.py&lt;/code&gt; 生成了一系列针对目标话题的监控节点。这些节点发布诊断数据到 &lt;code&gt;/diagnostics&lt;/code&gt; 话题中。&lt;/p&gt;
&lt;h2 id="三topic_state_monitor模块运行效果"&gt;&lt;a href="#%e4%b8%89topic_state_monitor%e6%a8%a1%e5%9d%97%e8%bf%90%e8%a1%8c%e6%95%88%e6%9e%9c" class="header-anchor"&gt;&lt;/a&gt;三、topic_state_monitor模块运行效果
&lt;/h2&gt;&lt;p&gt;运行 Autoware 的规划demo样例后：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; autoware
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/autoware/install/setup.bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ros2 launch autoware_launch planning_simulator.launch.xml map_path:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/autoware_map/sample-map-planning vehicle_model:&lt;span class="o"&gt;=&lt;/span&gt;sample_vehicle sensor_model:&lt;span class="o"&gt;=&lt;/span&gt;sample_sensor_kit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后运行 &lt;code&gt;ros2 node list&lt;/code&gt; 可以看到 &lt;code&gt;topic_state_monitor&lt;/code&gt; 模块运行起来一些监控节点来对配置文件中的话题进行监控。监控节点名称为：“&lt;code&gt;topic_state_monitor&lt;/code&gt;” + &lt;code&gt;topic.yaml&lt;/code&gt; 中话题的 &lt;code&gt;node_name_suffix&lt;/code&gt; 名称。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/针对指定话题生成的监控节点.png"&gt;&lt;/p&gt;
&lt;p&gt;这些节点输出诊断信息到 &lt;strong&gt;ROS Diagnostics&lt;/strong&gt; 诊断系统中，可以在 &lt;code&gt;rqt_runtime_monitor&lt;/code&gt; 中看到诊断结果。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/rqt_runtime_monitor查看诊断结果.png"&gt;&lt;/p&gt;
&lt;p&gt;同时，&lt;code&gt;component_state_monitor::StateMonitor&lt;/code&gt; 节点的 &lt;code&gt;main.cpp&lt;/code&gt; 订阅 &lt;code&gt;/diagnostics&lt;/code&gt; 话题并通过定时器周期性地检查不同模块整体的状态是否正常。输出的话题格式是 &lt;code&gt;&lt;del&gt;/type/module&lt;/code&gt;，例如，对于 &lt;code&gt;type&lt;/code&gt; 为 &lt;code&gt;launch&lt;/code&gt; 中的 &lt;code&gt;map&lt;/code&gt; 模块，输出话题为 &lt;code&gt;&lt;/del&gt;/launch/map&lt;/code&gt;。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/检查各个模块整体是否正常生成的topic.png"&gt;&lt;/p&gt;
&lt;p&gt;话题输出的消息格式是自定义的 &lt;code&gt;ModeChangeAvailable.msg&lt;/code&gt; 格式，用于表示某个模块是否可用。消息包含以下内容:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;stamp&lt;/code&gt;&lt;/strong&gt;：时间戳，表示消息生成的时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;available&lt;/code&gt;&lt;/strong&gt;：布尔值，表示该模块当前是否有效。&lt;code&gt;true&lt;/code&gt; 表示模块正常，&lt;code&gt;false&lt;/code&gt; 表示模块不可用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/topic输出结果.png"&gt;&lt;/p&gt;
&lt;h2 id="四topic状态监控部分实现原理"&gt;&lt;a href="#%e5%9b%9btopic%e7%8a%b6%e6%80%81%e7%9b%91%e6%8e%a7%e9%83%a8%e5%88%86%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;四、topic状态监控部分实现原理
&lt;/h2&gt;&lt;p&gt;分析源码后总结下来，其核心是通过 &lt;code&gt;component_state_monitor.launch.py&lt;/code&gt; 对 &lt;code&gt;config.yaml&lt;/code&gt; 文件中要监控的 topic &lt;strong&gt;一对一创建&lt;/strong&gt;一个 node。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/创建topic监控节点.png"&gt;&lt;/p&gt;
&lt;p&gt;随后将 node 启动部分注册成一个插件，这样可以用同一个源码启动多个 node。在 node 源码中，根据监控 topic 是否为 &lt;strong&gt;tf 话题&lt;/strong&gt;创建 &lt;strong&gt;tf 类订阅者&lt;/strong&gt;和&lt;strong&gt;非 tf 类订阅者&lt;/strong&gt;。这里针对非 tf 类 topic，使用了 &lt;code&gt;rclcpp::SerializedMessage&lt;/code&gt; 一个通用的消息类型，表示经过序列化的消息。它不关心消息的具体内容，只是将消息传递为原始的字节流。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/创建subscription.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/subscription回调函数.png"&gt;&lt;/p&gt;
&lt;h2 id="五一些考量点"&gt;&lt;a href="#%e4%ba%94%e4%b8%80%e4%ba%9b%e8%80%83%e9%87%8f%e7%82%b9" class="header-anchor"&gt;&lt;/a&gt;五、一些考量点
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;topic_state_monitor&lt;/code&gt; 模块可针对任意类型的 topic 生成一个 node 去监控 topic 的状态，通用性强。但如果需要监控的 topic 过多可能&lt;strong&gt;进程开销大&lt;/strong&gt;，因此要对该模块对于性能的开销进行测试来判断是否可迁移到人形机器人上。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;topic_state_monitor&lt;/code&gt; 模块采用了&lt;strong&gt;组合节点&lt;/strong&gt;并将组合节点放入 &lt;strong&gt;container&lt;/strong&gt; 中来启动一堆 node 去监控各个 topic。这样做的好处是将多个节点加载到同一个进程中，每个节点仍然保持独立的逻辑和功能，但它们可以更高效地共享数据和资源。这种方法不仅减少了通信延迟，而且降低了系统的整体资源消耗（例如，CPU时间内存使用）。&lt;/p&gt;
&lt;p&gt;实际使用 Autoware 进行测试时发现，输入 &lt;code&gt;ros2 component list&lt;/code&gt; 查看容器节点信息可知组合节点 &lt;code&gt;/system/component_state_monitor/component&lt;/code&gt; 有被放入 &lt;code&gt;/system/component_state_monitor/container&lt;/code&gt; 容器中。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/ros2-component-list输出结果.png"&gt;&lt;/p&gt;
&lt;p&gt;但是查询系统进程资源占用情况时发现：启动的各个监控 node 并没有在同一个进程中进行，而是各自占用了一个进程，这样性能总开销过大。&lt;/p&gt;
&lt;p&gt;猜测是启动文件中 node 的启动方式存在问题。经过分析发现问题出在 &lt;code&gt;component_state_monitor.launch.py&lt;/code&gt; 启动文件对于 node 节点的启动是通过启动一个个 &lt;code&gt;launch.xml&lt;/code&gt; 文件来生成监控 node 节点，并没有将 node 节点放入 container 容器中，因此占用了多个进程。&lt;/p&gt;
&lt;p&gt;想要减少进程的占用，需要重构 &lt;code&gt;component_state_monitor.launch.py&lt;/code&gt; 对于 node 节点的启动部分。修改后的代码如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;launch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;launch.actions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DeclareLaunchArgument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OpaqueFunction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;launch.substitutions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LaunchConfiguration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;launch_ros.actions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ComposableNodeContainer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;launch_ros.descriptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ComposableNode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;yaml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_diagnostic_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;module&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_topic_status&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_topic_monitor_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;diag_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_diagnostic_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;node_name_suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;node_name_suffix&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 替换非法字符，如冒号和空格为下划线(防止报错Couldn&amp;#39;t parse remap rule: &amp;#39;-r __node......）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;node_name_suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node_name_suffix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;_&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;_&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;diag_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;diag_name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;_&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;_&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_state_monitor_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;node_name_suffix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;diag_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_topic_monitor_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;diag_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_diagnostic_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 基础参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;diag_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;diag_name&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 根据是否为 TF 类话题，添加不同的参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remappings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;topic_type&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 非 TF 类话题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# TF 类话题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frame_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frame_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;child_frame_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;child_frame_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 其他参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;frame_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;child_frame_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 如果需要进行主题重映射，可以在这里添加 remappings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 假设 YAML 文件中不包含 remaps 字段，因此 remappings 为空&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# if &amp;#34;remaps&amp;#34; in row[&amp;#34;args&amp;#34;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# for remap in row[&amp;#34;args&amp;#34;][&amp;#34;remaps&amp;#34;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# remappings.append(remap)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ComposableNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;system&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_state_monitor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_state_monitor::TopicStateMonitorNode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;create_topic_monitor_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remappings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;remappings&lt;/span&gt; &lt;span class="c1"&gt;# 目前为空&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;launch_setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 获取启动模式和配置文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LaunchConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;config_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LaunchConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safe_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 创建所有监控节点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;topic_monitor_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;create_topic_monitor_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;topic_monitor_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;create_topic_monitor_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 组织参数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;topic_monitor_param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;topic_monitor_param&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;create_topic_monitor_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;topic_monitor_param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;topic_monitor_param&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 创建主组件节点（StateMonitor）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComposableNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;component_state_monitor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;component_state_monitor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;component_state_monitor::StateMonitor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;component&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;topic_monitor_names&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;topic_monitor_names&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;topic_monitor_param&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 创建容器，并将所有ComposableNode添加到容器中&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ComposableNodeContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;component_state_monitor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rclcpp_components&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;component_container&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;composable_node_descriptions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;topic_monitor_nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 将监控节点加入容器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;screen&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_launch_description&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LaunchDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DeclareLaunchArgument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DeclareLaunchArgument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OpaqueFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;launch_setup&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码修改后运行可发现监控 node 成功被放入 container 容器中在同一个进程中运行。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/09/在同一个进程中运行.png"&gt;&lt;/p&gt;
&lt;p&gt;但是检查进程占用情况发现 &lt;code&gt;component_state_monitor&lt;/code&gt; 进程总占用在 &lt;strong&gt;70%&lt;/strong&gt; 左右，占用过高。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/03/总占用在70左右，占用过高-1024x110.png"&gt;
修改参数列表中的 &lt;code&gt;window_size&lt;/code&gt; 与 &lt;code&gt;update_rate&lt;/code&gt;，将其从默认的 &lt;strong&gt;10&lt;/strong&gt; 调小至 &lt;strong&gt;2&lt;/strong&gt; 后，占用可下降至 &lt;strong&gt;15%&lt;/strong&gt; 左右。
&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2025/03/占用可下降至15左右-1024x104.png"&gt;
经分析，&lt;code&gt;TopicStateMonitor&lt;/code&gt; 的逻辑本身相对简单，只是维护一个时间戳队列、计算话题接收速率，并根据阈值进行状态判断。单独看这段代码，性能开销并不大，主要是一些基本的内存操作（&lt;strong&gt;&lt;code&gt;push_back&lt;/code&gt;&lt;/strong&gt;、&lt;strong&gt;&lt;code&gt;pop_front&lt;/code&gt;&lt;/strong&gt;）、时间计算和简单的条件判断。这些操作本身不是CPU占用的主要来源。&lt;/p&gt;
&lt;p&gt;然而，当有 &lt;strong&gt;15个&lt;/strong&gt; 这样的监控节点，每个节点都在高频率地接收消息并调用 &lt;strong&gt;&lt;code&gt;update()&lt;/code&gt;&lt;/strong&gt; 函数时，整体系统的CPU使用率就可能显著增加。由于 Autoware 系统繁杂臃肿，消息的频率不太好手动控制。为了控制变量研究消息频率与数量对监控模块占用系统资源的情况，于是手动创建一些节点，观察不同 topic 数量、频率与 QoS 策略下的系统资源占用情况。&lt;/p&gt;
&lt;p&gt;测试编写脚本创建多个发布者发布 &lt;code&gt;std_msgs/msg/String&lt;/code&gt; 格式的话题，然后启动 &lt;code&gt;topic_state_monitor&lt;/code&gt;，其中 &lt;code&gt;window_size&lt;/code&gt; 设为 &lt;strong&gt;2&lt;/strong&gt;、&lt;code&gt;update_rate&lt;/code&gt; 设为 &lt;strong&gt;1&lt;/strong&gt;。之后对 &lt;code&gt;topic_state_monitor&lt;/code&gt; 进程的 CPU 占用率进行监控 &lt;strong&gt;120秒&lt;/strong&gt;，每秒测两次，将测试结果绘制成表格如下所示:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;影响因素&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Topic数量&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Topic频率&lt;/th&gt;
&lt;th style="text-align: left;"&gt;best_effort&lt;/th&gt;
&lt;th style="text-align: left;"&gt;transient_local&lt;/th&gt;
&lt;th style="text-align: left;"&gt;平均占用率&lt;/th&gt;
&lt;th style="text-align: left;"&gt;最小占用率&lt;/th&gt;
&lt;th style="text-align: left;"&gt;最大占用率&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Topic频率对占用率的影响&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;5&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.55%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;2.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;5.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;10&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4.53%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;5.63%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;3.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;7.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;20&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;8.44%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;12.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;35&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;10.23%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;14.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;40&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;11.36%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;8.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;45&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;13.87%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;10.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;18.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;14.30%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;10.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;18.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;QoS策略对占用率的影响&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;12.47%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;8.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;11.42%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;8.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;15&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;11.17%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Topic数量对占用率的影响&lt;/td&gt;
&lt;td style="text-align: left;"&gt;20&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.30%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;10.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;22.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;10&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;6.54%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;12.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;td style="text-align: left;"&gt;5&lt;/td&gt;
&lt;td style="text-align: left;"&gt;50&lt;/td&gt;
&lt;td style="text-align: left;"&gt;true&lt;/td&gt;
&lt;td style="text-align: left;"&gt;false&lt;/td&gt;
&lt;td style="text-align: left;"&gt;4.54%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;2.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;8.0%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
将表格绘制成折线图如下所示：
![](/uploads/2025/03/topic频率对cpu占用影响-1024x718.png)
![](/uploads/2025/09/topic数量对cpu占用影响.png)
&lt;p&gt;由表格数据可以得出结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Topic 数量与频率的增加会增加 &lt;code&gt;topic_state_monitor&lt;/code&gt; 模块对系统的占用&lt;/strong&gt;。如果以 &lt;strong&gt;15%&lt;/strong&gt; 的占用率为界限定义为对 CPU 占用较少、为可用状态的话，那么 &lt;strong&gt;15个50Hz的Topic以下&lt;/strong&gt; 或者 &lt;strong&gt;更多的更低Hz的Topic&lt;/strong&gt;、&lt;strong&gt;更少的更高Hz的Topic&lt;/strong&gt; 为此监控系统工作的最佳状态。&lt;/li&gt;
&lt;li&gt;同时，&lt;strong&gt;QoS 策略也会对系统占用产生影响&lt;/strong&gt;。设置 &lt;code&gt;best_effort&lt;/code&gt; 为 &lt;code&gt;true&lt;/code&gt;，即不使用 &lt;strong&gt;reliable 可靠性传输策略&lt;/strong&gt;；设置 &lt;code&gt;transient_local&lt;/code&gt; 为 &lt;code&gt;false&lt;/code&gt;，即不使用 &lt;strong&gt;Volatile 持久性 QoS 策略&lt;/strong&gt;。这样可以牺牲一点消息传输的可靠性来换取更低的资源占用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="小结"&gt;&lt;a href="#%e5%b0%8f%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;小结
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;topic_state_monitor&lt;/code&gt; 模块可针对任意类型的 topic 生成一个 node 去监控 topic 的状态，通用性强。但如果需要监控过多高频的 Topic 消息可能会导致&lt;strong&gt;进程开销大&lt;/strong&gt;。因此 Autoware 中对进行监控的 topic 进行了&lt;strong&gt;模块化分类处理&lt;/strong&gt;，根据不同的应用场景选择性地监控关键模块的关键话题。例如，定位模块着重关注 &lt;code&gt;map&lt;/code&gt; 到 &lt;code&gt;base_link&lt;/code&gt; 的 &lt;code&gt;tf&lt;/code&gt; 转换是否正常，控制模块着重关注发布的 &lt;code&gt;control_cmd&lt;/code&gt; 控制 topic 是否正常。&lt;/p&gt;</description></item><item><title>编译雷达驱动PCL库缺失问题</title><link>https://leo-wangbo.top/p/%E7%BC%96%E8%AF%91%E9%9B%B7%E8%BE%BE%E9%A9%B1%E5%8A%A8pcl%E5%BA%93%E7%BC%BA%E5%A4%B1%E9%97%AE%E9%A2%98/</link><pubDate>Fri, 08 Sep 2023 22:03:02 +0800</pubDate><guid>https://leo-wangbo.top/p/%E7%BC%96%E8%AF%91%E9%9B%B7%E8%BE%BE%E9%A9%B1%E5%8A%A8pcl%E5%BA%93%E7%BC%BA%E5%A4%B1%E9%97%AE%E9%A2%98/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 编译雷达驱动PCL库缺失问题" /&gt;&lt;p&gt;咸鱼淘了个一百多块的镭神雷达，看参数性能还挺不错，而且是TOF测距雷达，原价四五百呢。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/09/tb_image_share_1694178764160.jpg"&gt;&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/tb_image_share_1694178649277-4-736x1024.jpg" alt=""&gt;
 &lt;figcaption&gt;雷达参数&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;之后将驱动包拷贝到工作空间的src目录下后进行编译，可以看到代码包的名称与cmake里project的名称都是lslidar_driver，因此在工作空间目录下输入colcon build &amp;ndash;packages-select lslidar_driver编译驱动包。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/VBTRHNKSZQLIHEFOJQY-1024x521.png" alt=""&gt;
 &lt;figcaption&gt;雷达驱动文件包&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;但是编译的时候报了错，没有找到pcl_conversions的配置文件。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/PFWBH_@TIJWW_9IX@YX.png" alt=""&gt;
 &lt;figcaption&gt;编译报错&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;我求助了一下万能的Claude，他让我用apt安装libpcl-dev这个包。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/image-1024x485.png" alt=""&gt;
 &lt;figcaption&gt;万能的Claude&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;但是我执行命令后发现我已经安装过这个包了，那为什么还是找不到啊。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/09/image-1.png"&gt;&lt;/p&gt;
&lt;p&gt;接下来他又让我进行设置环境变量，甚至源码编译库文件等等操作，都没有解决这个问题。我后来发现缺失的是pcl_conversions 这个库，但是他却一直让我安装的是libpcl-dev。我又问了Claude这两个有什么区别，看起来libpcl-dev包含了pcl_conversions 。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/09/image-2.png"&gt;&lt;/p&gt;
&lt;p&gt;于是我决定找一下pcl_conversions 的安装目录。可以看到pcl_conversions 并没有被apt安装。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/image-3-1024x454.png" alt=""&gt;
 &lt;figcaption&gt;Claude提示寻找安装目录&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/image-4-1024x439.png" alt=""&gt;
 &lt;figcaption&gt;pcl_conversions 包确实未找到&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;于是执行apt安装libpcl-conversions-dev后，成功编译驱动包了。（虽然还是不知道为什么之前装了但是找不到）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install libpcl-conversions-dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后执行ros2 launch lslidar_driver lsn10_launch.py可启动雷达。打开rviz2，FixedFrame中输入雷达坐标系的名称，这个名称实在雷达驱动文件中的yaml文件中设置的&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/image-5.png" alt=""&gt;
 &lt;figcaption&gt;rviz2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/image-6-1024x525.png" alt=""&gt;
 &lt;figcaption&gt;驱动代码中的配置文件&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;之后点击Rviz 左下角的Add 按键，在弹出的窗口中点击By topic 选中/scan话题下的LaserScan 并点击OK。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/09/image-7.png" alt=""&gt;
 &lt;figcaption&gt;rviz中添加LaserScan&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;成功添加LaserScan 后我们便可以在Rviz 中看到这样的雷达点云图像。&lt;/p&gt;</description></item><item><title>给旭日X3派适配千兆网卡</title><link>https://leo-wangbo.top/p/%E7%BB%99%E6%97%AD%E6%97%A5x3%E6%B4%BE%E9%80%82%E9%85%8D%E5%8D%83%E5%85%86%E7%BD%91%E5%8D%A1/</link><pubDate>Wed, 09 Aug 2023 22:44:58 +0800</pubDate><guid>https://leo-wangbo.top/p/%E7%BB%99%E6%97%AD%E6%97%A5x3%E6%B4%BE%E9%80%82%E9%85%8D%E5%8D%83%E5%85%86%E7%BD%91%E5%8D%A1/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 给旭日X3派适配千兆网卡" /&gt;&lt;p&gt;由于旭日X3派自带的网卡实在是太拉胯，我家的WIFI都扫不出来，只好外加一USB网卡，购买的是如下款式。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/08/qq_pic_merged_1691575645249-1024x422.jpg"&gt;&lt;/p&gt;
&lt;p&gt;然后就是驱动的配置，如果想自己编译的话可以参考这个博客：&lt;a href="https://blog.csdn.net/Zhaoxi_Li/article/details/127975137?spm=1001.2014.3001.5502"&gt;体验极速——在旭日X3派上使用双频1300M USB无线网卡_1300m无线网卡实际速度_小玺玺的博客-CSDN博客&lt;/a&gt;，这里给出编译好的驱动下载连接：https://pan.baidu.com/s/1qhFyLxFiLhlTaKJfRXK4Ow 提取码：kuq1。&lt;/p&gt;
&lt;p&gt;先将驱动文件在Mobaxterm里ssh登录后拷贝至旭日派中，这里我拷贝至了home目录下，然后再执行命令拷贝到系统驱动目录下。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cp 88x2bu.ko /lib/modules/4.14.87/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后使用&lt;code&gt;cd /lib/modules/4.14.87/&lt;/code&gt;进入文件夹后输入以下指令对ko文件签名：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo hobot-sign-file 88x2bu.ko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后输入以下两条指令加载驱动，这个时候可以看到网卡驱动的灯开始闪烁。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /sbin/depmod -a 4.14.87
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo insmod 88x2bu.ko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输入ifconfig后产看网卡名称。可以看到图中的“wlx200db0c78392”为我们新增的网卡名称。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/08/屏幕截图-2023-08-09-174431-2.jpg"&gt;&lt;/p&gt;
&lt;p&gt;如果想&lt;strong&gt;永久启用&lt;/strong&gt;，输入&lt;code&gt;sudo vim /etc/modules&lt;/code&gt;，在里面添加&lt;code&gt;88x2bu&lt;/code&gt;即可。（一定要切忌在网卡驱动未正常启动的情况下永久启用）&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/08/5f817fd139df4fc3a11102522407b9b7-2.png"&gt;&lt;/p&gt;
&lt;p&gt;然后输入以下指令扫描出最新的WIFI名称。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sudo nmcli device wifi rescan # 扫描wifi网络
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nmcli device wifi list # 列出找到的wifi网络
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后输入 sudo nmcli dev wifi connect &amp;ldquo;wifi名称&amp;rdquo; password &amp;ldquo;密码&amp;rdquo; ifname 网卡名称 即可连接指定wifi，我的是。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nmcli dev wifi connect &amp;#34;RM2100_F7BB&amp;#34; password &amp;#34;18*********&amp;#34; ifname wlx200db0c78392
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>巡检防疫机器人</title><link>https://leo-wangbo.top/p/%E5%B7%A1%E6%A3%80%E9%98%B2%E7%96%AB%E6%9C%BA%E5%99%A8%E4%BA%BA/</link><pubDate>Mon, 18 Apr 2022 20:24:00 +0800</pubDate><guid>https://leo-wangbo.top/p/%E5%B7%A1%E6%A3%80%E9%98%B2%E7%96%AB%E6%9C%BA%E5%99%A8%E4%BA%BA/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 巡检防疫机器人" /&gt;&lt;p&gt;去年大半年的时间借着参加各种工科竞赛的功夫做了一辆巡检机器人，通过搭建这款巡检机器人，边学边做有了一定的Python和C语言的编程基础，可以绘制一些初级的PCB电路板，从前端到后端、Linux系统的使用、服务器的搭建都有了一定的了解。接下来就主要介绍这辆巡检机器人的主要功能及实现过程。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/IMG_20211008_214202_edit_166228711964212-1001x1024.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;巡检防疫机器人外观&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="功能"&gt;&lt;a href="#%e5%8a%9f%e8%83%bd" class="header-anchor"&gt;&lt;/a&gt;功能
&lt;/h2&gt;&lt;p&gt;做这款机器人的起始时间正值新冠疫情刚开始，因此将这辆巡检机器人的应用背景定为防疫相关。智能防疫机器人可通过摄像头识别人脸是否正确佩戴口罩。机器人还搭载有消毒模块，可开启消毒模式实现定点喷杀消毒，同时搭的温湿度传感器、可燃气体传感器、空气质量传感器等，可将传感器数据上传至云端并在Web界面实时显示分析，若检测到异常数值可在钉钉群里通过钉钉机器人推送告警信息。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/云端界面1.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;Web可视化界面1&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/云端界面2.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;Web可视化界面2&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="实现原理"&gt;&lt;a href="#%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;实现原理
&lt;/h2&gt;&lt;h3 id="系统硬件设计"&gt;&lt;a href="#%e7%b3%bb%e7%bb%9f%e7%a1%ac%e4%bb%b6%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;系统硬件设计
&lt;/h3&gt;&lt;p&gt;本文设计的智能防疫机器人的控制计算单元使用了‘’大脑‘’+‘’小脑‘’的设计方案，底层的STM32控制板为低算力、低时延、运行实时操作系统的‘’小脑‘’，用于控制底层电机，采集传感器数据等；上层的树莓派为高算力、高时延、运行Liunx操作系统的大脑，用于感知、思考和决策。其硬件设计框图如图所示。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/巡检机器人实现框图.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;系统硬件框图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id="系统软件设计"&gt;&lt;a href="#%e7%b3%bb%e7%bb%9f%e8%bd%af%e4%bb%b6%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;系统软件设计
&lt;/h3&gt;&lt;p&gt;软件设计分为四部分，一是树莓派端程序设计，二是底层STM32单片机程序设计，三是手机APP程序设计，四是云端服务器程序设计。&lt;/p&gt;
&lt;h4 id="树莓派端程序设计"&gt;&lt;a href="#%e6%a0%91%e8%8e%93%e6%b4%be%e7%ab%af%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;树莓派端程序设计
&lt;/h4&gt;&lt;p&gt;树莓派端程序主要包括巡检过程中的口罩识别代码、QT编写的UI界面部分、与服务器交互的部分。&lt;/p&gt;
&lt;p&gt;巡检过程中的口罩识别由于要兼顾巡检、人脸识别与语音播报，程序运行负载较大，因此为了提升整体程序运行的流畅度尽量用上所有CPU的资源，因此采用多进程来实现这一功能，在不降低精度的情况下大大提升了运行速度，达到了实时性的要求，部分实现代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#定义传递图像队列和传递图像处理结果队列
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;q_frame = Queue()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;q_respond = Queue()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;q_car= Queue()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#采集摄像头进程：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;get_camera_frame=Process(target=camera_frame_func, args=(&amp;#34;获取摄像头图像&amp;#34;, q_frame, mydict,q_car))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#处理图片进程：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;proc_frame=Process(target=proc_frame_func, args=(&amp;#34;处理图像&amp;#34;, q_frame, q_respond, mydict))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#播报语音信息：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;read_rst=Process(target=read_rst_func, args=(&amp;#34;播报语音信息&amp;#34;, q_respond,q_car))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;机器人巡检进程：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;carrun=Process(target=carrun_fun,args=(&amp;#34;小车巡检&amp;#34;, q_car))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 启动任务
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;get_camera_frame.start()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;proc_frame.start()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;read_rst.start()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;carrun.start()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个进程获取摄像头图像，并利用OpenCV中的训练好的人脸Haar特征分类级联器判断画面中是否存在人脸，若存在人脸则将人脸照片传至消息队列中。第二个进程通过消息队列取出人脸照片并上传至百度智能云平台，百度智能云平台可根据云端数据库中的信息匹配出人脸身份信息，并判断人脸是否正确佩戴口罩将判断结果返回，若没有正确佩戴口罩则进程三启动播出提示语音，并停止巡检进程，向底层运动控制系统发出停止指令。正确佩戴口罩后恢复巡检进程。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/巡检系统流程图.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;巡检系统流程图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;机器人上层有一五寸可触摸电容屏，界面如图所示。该多媒体屏幕可进行一定的人机交互与多媒体宣传功能。该界面采用QT编写（代码已申请软著），天气查询通过调用API接口实现，词条查询通过爬取百度百科实现。当按下开启消毒模式时，树莓派通过串口向底层单片机发送开启指令。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/qt.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;QT界面&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;控制模块总按钮位于上位机软件主界面的左下方的“手动控制”，点击后即可进入手动控制界面&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/控制界面.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;手动控制界面&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;当点击“播放音乐”按钮后，会弹出音乐播放器界面，可点击曲库中的音乐进行播放，左下角可切换“单曲循环”、“顺序播放”、“随机播放”模式。若想要播放曲库中没有的音乐，可对防疫机器人说出像要播放的曲名，机器人会联网下载歌曲后进行播放。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/音乐播放器.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;音乐播放器&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;树莓派通过串口接收到底层单片机采集到的各种数据通过MQTT协议将其传至阿里云服务器，也可接收服务器下发的指令来远程控制机器人。部分代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;Alink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AlinkJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AlinkJson&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;999999&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AlinkJson&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AlinkJson&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AlinkJson&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;method&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;thing.event.property.post&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AlinkJson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 消息回调（云端下发消息的回调函数）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SET&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;params&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;PowerLed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rpi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;powerLed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 开关值&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#连接回调（与阿里云建立链接后的回调函数）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 构建与云端模型一致的消息结构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;updateMsn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;natural_gas&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;natural_gas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;fired_gas&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;fired_gas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;&amp;#39;Harmful_gas&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;harmful_gas&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;JsonUpdataMsn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aliLink&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Alink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updateMsn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mqtt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;JsonUpdataMsn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 定时向阿里云IOT推送我们构建好的Alink协议数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="底层单片机程序设计"&gt;&lt;a href="#%e5%ba%95%e5%b1%82%e5%8d%95%e7%89%87%e6%9c%ba%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;底层单片机程序设计
&lt;/h4&gt;&lt;p&gt;底层STM32单片机程序分为主初始化程序、主程序、通讯中断子程序、功能模块子程序、PID电机控制子程序等。通讯中断子程序主要利用串口与树莓派进行通信，功能模块子程序为消毒喷洒装置控制函数、测温函数、LCD屏幕显示函数等。电机子程序内容为根据编码电机上的编码器返回的电机速度利用PID算法实时通过输出PWM波来控制电机的速度，从而保证机器人行进的稳定。&lt;/p&gt;
&lt;h4 id="手机app程序设计"&gt;&lt;a href="#%e6%89%8b%e6%9c%baapp%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;手机APP程序设计
&lt;/h4&gt;&lt;p&gt;手机APP程序采用Android studio软件开发和编译，分为主控界面、数据显示界面、模式选择界面等。进入控制界面后，可在此界面控制机器人的前进、后退、左转、右转、旋转以及摄像头云台的俯仰与旋转。还可控制防疫机器人进入巡检模式、消毒模式、以及选择人员进行精确测温等。同时可在此界面查看机器人传回的实时画面。数据显示界面可查看机器人检测到的各类传感器数据的数值、拍摄到的未正确佩戴口罩人脸的照片、体温检测异常的人的身份等。&lt;/p&gt;
&lt;p&gt;APP端对机器人的控制可选择不需要联网、时延低、控制距离有限的蓝牙控制，也可选择需要联网、时延相对较高、控制距离理论上无限的远程控制。当选择蓝牙控制模式时，手机蓝牙与防疫机器人身上的蓝牙相连来下发控制指令。当选择远程控制模式时，安卓APP通过MQTT协议与服务器建立连接，通过安卓APP将控制指令先发送给云端服务器，然后服务器再将数据发送给树莓派，从而达到对机器人远程控制的目的。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/image.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;&amp;nbsp;APP控制系统流程图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="实现效果"&gt;&lt;a href="#%e5%ae%9e%e7%8e%b0%e6%95%88%e6%9e%9c" class="header-anchor"&gt;&lt;/a&gt;实现效果
&lt;/h2&gt;&lt;div class="bilibili-wrap" style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5em 0;"&gt;
 &lt;iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;bvid=BV1sM4y1X7ac&amp;p=1&amp;autoplay=0&amp;high_quality=1&amp;danmaku=0"
 style="position:absolute;top:0;left:0;width:100%;height:100%;"
 frameborder="0" allowfullscreen scrolling="no"&gt;&lt;/iframe&gt;
&lt;/div&gt;</description></item><item><title>卧龙凤雏的电磁炮</title><link>https://leo-wangbo.top/p/%E5%8D%A7%E9%BE%99%E5%87%A4%E9%9B%8F%E7%9A%84%E7%94%B5%E7%A3%81%E7%82%AE/</link><pubDate>Thu, 17 Mar 2022 23:41:00 +0800</pubDate><guid>https://leo-wangbo.top/p/%E5%8D%A7%E9%BE%99%E5%87%A4%E9%9B%8F%E7%9A%84%E7%94%B5%E7%A3%81%E7%82%AE/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 卧龙凤雏的电磁炮" /&gt;&lt;h2 id="团队介绍"&gt;&lt;a href="#%e5%9b%a2%e9%98%9f%e4%bb%8b%e7%bb%8d" class="header-anchor"&gt;&lt;/a&gt;团队介绍
&lt;/h2&gt;&lt;p&gt;首先贴出卧龙凤雏团队与电磁炮的合影&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/01/mmexport1634987917663.jpg"&gt;&lt;/p&gt;
&lt;p&gt;最中间是总策划、酷爱军事、从小就造飞机的“曹工”，主要负责坦克车体外观及机械结构及PCB电路板的设计；左边的是我，负责机器人顶层控制逻辑中的视觉识别与追踪；右边是负责车体底层控制的“陈工”。&lt;/p&gt;
&lt;h2 id="制作过程"&gt;&lt;a href="#%e5%88%b6%e4%bd%9c%e8%bf%87%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;制作过程
&lt;/h2&gt;&lt;h3 id="外形设计"&gt;&lt;a href="#%e5%a4%96%e5%bd%a2%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;外形设计
&lt;/h3&gt;&lt;h4 id="底盘设计"&gt;&lt;a href="#%e5%ba%95%e7%9b%98%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;底盘设计
&lt;/h4&gt;&lt;p&gt;机器人底盘长788.45mm，宽308.00mm，高153.51mm，悬挂采用的是克里斯蒂悬挂系统，即一种拥有大直径负重轮，使用螺旋弹簧的独立式悬挂装置。这种悬挂均是由前后两个互相连接的圆柱形螺旋弹簧构成。位于前方的为可调式水平螺旋弹簧，后方的则是垂直螺旋弹簧，这种设计有更长的避震行程，可强化越野性能。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/侧面图.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;机器人底盘侧视图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;“曹工”组装车体&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/01/博客资料1634989140247.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;组装完成&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://leo-wangbo.top/uploads/2023/01/博客资料1634989150291-1.jpeg"&gt;&lt;/p&gt;
&lt;h4 id="磁加速系统设计"&gt;&lt;a href="#%e7%a3%81%e5%8a%a0%e9%80%9f%e7%b3%bb%e7%bb%9f%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;磁加速系统设计
&lt;/h4&gt;&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/磁加速系统实际模型.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;磁加速系统实际模型&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;炮台底座也使用木制材料，中间开有41mm*174mm的矩形孔为炮位提供移动的空间，整个炮塔通过螺栓固定在履带底盘上部的旋转滑台上。磁加速系统的加速段整体用木板封装起来以此来达到绝缘的效果；为了防止热量堆积在炮管支架的木板上每一级加速线圈周围都开有方形空用来散热；&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/磁加速系统炮管.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;磁加速系统炮管&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;电磁加速系统为磁阻式电磁加速系统，采用五级线圈加速，光电门进行击发，电解电容储能，发射电压为400V。第一级电容容量为2000μF，第二级电容容量为1880μF，第三级电容容量为1880μF，第四级电容容量为1440μF，第五级电容容量为1440μF，这样的电容容量设计是为了减少炮弹在加速的过程中所受到的反拉&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/磁加速PCB.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;磁加速系统PCB&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/磁加速实物.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;电容储能系统实物&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;该磁加速系统配备有自动装弹机，装弹机安装在炮管的尾部并随炮管运动可以实现任意角度装填，装填机构通过丝杆推动炮弹并将其送入炮膛，丝杆由四线两相步进电机提供动力，在装弹机滑台的两侧安装有两个限位开关来限制推弹杆的移动空间。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/装弹机.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;自动装弹机示意图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;经过建立数学模型进行计算并通过测试，该磁加速系统可以将我们所设计的炮弹加速至45m/s左右。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/炮弹实物-2-rotated.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;炮弹实物&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/模拟.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;对炮弹的空气动力模拟计算图示&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id="电路设计"&gt;&lt;a href="#%e7%94%b5%e8%b7%af%e8%ae%be%e8%ae%a1" class="header-anchor"&gt;&lt;/a&gt;电路设计
&lt;/h4&gt;&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/遥控器原理图.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;遥控器原理图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/遥控器pcb.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;遥控器PCB&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/底层控制板板原理图.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;底层控制板原理图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/底层控制板PCB.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;底层控制板PCB&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id="上路测试"&gt;&lt;a href="#%e4%b8%8a%e8%b7%af%e6%b5%8b%e8%af%95" class="header-anchor"&gt;&lt;/a&gt;上路测试
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;开着出去，抬着回来&lt;/strong&gt;&lt;/p&gt;
&lt;div style="text-align:center;margin:1.5em 0;"&gt;
 &lt;video controls preload="metadata" src="https://leo-wangbo.top/uploads/2023/01/开着出去.mp4" style="max-width:100%;border-radius:8px;"&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;div style="text-align:center;margin:1.5em 0;"&gt;
 &lt;video controls preload="metadata" src="https://leo-wangbo.top/uploads/2023/01/抬着回来.mp4" style="max-width:100%;border-radius:8px;"&gt;&lt;/video&gt;
&lt;/div&gt;
&lt;h3 id="软件部分"&gt;&lt;a href="#%e8%bd%af%e4%bb%b6%e9%83%a8%e5%88%86" class="header-anchor"&gt;&lt;/a&gt;软件部分
&lt;/h3&gt;&lt;p&gt;由于后来想要拿此机器人参加一些比赛，所以要为电磁炮想出应用一些民用价值。考虑到现在楼层建筑越来越高，若发生火灾消防部队扑救的难度很大，如果电磁炮可以对火源发出灭火弹则可迅速阻止火势扩大，因此就以“基于磁加速系统的高层建筑灭火机器人”为背景继续完善机器人。&lt;/p&gt;
&lt;p&gt;初步方案是用树莓派进行火焰识别，并用舵机云台进行火焰追踪，将角度数据回传给底层STM32控制端后进行炮塔对火焰的追踪，最后再根据利用炮口的激光测距仪测出的炮口与火焰的距离进行炮弹射速的调整。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/原理.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;实现原理图&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h4 id="初步实现效果演示"&gt;&lt;a href="#%e5%88%9d%e6%ad%a5%e5%ae%9e%e7%8e%b0%e6%95%88%e6%9e%9c%e6%bc%94%e7%a4%ba" class="header-anchor"&gt;&lt;/a&gt;初步实现效果演示
&lt;/h4&gt;&lt;div class="bilibili-wrap" style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5em 0;"&gt;
 &lt;iframe src="https://player.bilibili.com/player.html?isOutside=true&amp;bvid=BV1z34y1Z7vE&amp;p=1&amp;autoplay=0&amp;high_quality=1&amp;danmaku=0"
 style="position:absolute;top:0;left:0;width:100%;height:100%;"
 frameborder="0" allowfullscreen scrolling="no"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3 id="优化改进"&gt;&lt;a href="#%e4%bc%98%e5%8c%96%e6%94%b9%e8%bf%9b" class="header-anchor"&gt;&lt;/a&gt;优化改进
&lt;/h3&gt;&lt;p&gt;由于树莓派识别火焰的速率实在不敢恭维，于是家中有矿的”曹工“斥一顿早饭钱买了一块英伟达Jetson Nano边缘计算模块，Jetson nano与树莓派相比，NVIDIA Jetson Nano包含性能更高，功能更强大的GPU——NVIDIA Jetson Nano中具有128个CUDA核心的NVIDIA Maxwell GPU。NVIDIA Jetson Nano中更强大的GPU可以为图形处理，甚至人工智能（AI）和机器学习（ML）提供更强大的功能。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/IMG_20211023_201311_edit_109758631565543-scaled.jpg" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;Jetson Nano&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;火焰识别算法采用的是NanoDet目标检测模型，NanoDet 是一个速度超快和轻量级的移动端目标检测模型，非常适合嵌入式部署。将在PC端训练好的模型移植到Jetson Nano边缘计算平台上即可进行火焰识别。识别到火焰后，根据火焰在视角中的位置，摄像头云台利用PID算法进行追踪。Jetson Nano通过PCA9655 舵机驱动板驱动摄像头云台舵机。&lt;/p&gt;
&lt;p&gt;PID算法代码如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# *****************************************************************#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# 增量式PID系统 #
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# *****************************************************************#
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;class IncrementalPID:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; def __init__(self, P, I, D):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Kp = P
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Ki = I
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Kd = D
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.PIDOutput = 0.0 # PID控制器输出
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.SystemOutput = 0.0 # 系统输出值
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.LastSystemOutput = 0.0 # 上次系统输出值
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Error = 0.0 # 输出值与输入值的偏差
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.LastError = 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.LastLastError = 0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # 设置PID控制器参数
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; def SetStepSignal(self, StepSignal):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Error = StepSignal - self.SystemOutput
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; IncrementValue = self.Kp * (self.Error - self.LastError) + \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Ki * self.Error + \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.Kd * (self.Error - 2 * self.LastError + self.LastLastError)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.PIDOutput += IncrementValue
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.LastLastError = self.LastError
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.LastError = self.Error
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # 设置一阶惯性环节系统 其中InertiaTime为惯性时间常数
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; def SetInertiaTime(self, InertiaTime, SampleTime):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.SystemOutput = (InertiaTime * self.LastSystemOutput + \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SampleTime * self.PIDOutput) / (SampleTime + InertiaTime)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; self.LastSystemOutput = self.SystemOutput
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;火焰追踪主函数代码如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pwm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PCA9685&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pwm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPWMFreq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pwm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setServoPulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pwm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setServoPulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backends&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cudnn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backends&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cudnn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;benchmark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;load_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_tensorboard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;predictor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Predictor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cuda:0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Press &amp;#34;Esc&amp;#34; to exit.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;camera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;USBCamera&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capture_fps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ret_val, frame = cap.read()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# if ret_val == False:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# continue #skip if capture fail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;predictor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;predictor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visualize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x,y&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 输入X轴方向参数PID控制输入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;xservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;xservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetStepSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;xservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetInertiaTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;target_valuex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ne"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;xservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemOutput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 输入Y轴方向参数PID控制输入&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;yservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;yservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetStepSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;yservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetInertiaTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yservo_pid.SystemOutput&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemOutput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ne"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;yservo_pid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemOutput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;820&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;820&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;target_valuex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target_valuex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;target_valuex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pwm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setServoPulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_valuex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pwm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setServoPulse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;valuex,valuey&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_valuex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_valuey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;火焰追踪效果如下&lt;/p&gt;
&lt;div style="text-align:center;margin:1.5em 0;"&gt;
 &lt;video controls preload="metadata" src="https://leo-wangbo.top/uploads/2023/01/火焰追踪.mp4" style="max-width:100%;border-radius:8px;"&gt;&lt;/video&gt;
 &lt;p style="text-align:center;color:#888;font-size:0.9em;"&gt;&lt;strong&gt;Jetson Nano火焰追踪效果&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;</description></item></channel></rss>