<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>嵌入式 on 阿波的博客</title><link>https://leo-wangbo.top/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F/</link><description>Recent content in 嵌入式 on 阿波的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 28 Nov 2023 22:14:33 +0800</lastBuildDate><atom:link href="https://leo-wangbo.top/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F/index.xml" rel="self" type="application/rss+xml"/><item><title>旭日X3派连接不了手机热点解决方法</title><link>https://leo-wangbo.top/p/%E6%97%AD%E6%97%A5x3%E6%B4%BE%E8%BF%9E%E6%8E%A5%E4%B8%8D%E4%BA%86%E6%89%8B%E6%9C%BA%E7%83%AD%E7%82%B9%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/</link><pubDate>Thu, 20 Apr 2023 20:33:57 +0800</pubDate><guid>https://leo-wangbo.top/p/%E6%97%AD%E6%97%A5x3%E6%B4%BE%E8%BF%9E%E6%8E%A5%E4%B8%8D%E4%BA%86%E6%89%8B%E6%9C%BA%E7%83%AD%E7%82%B9%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 旭日X3派连接不了手机热点解决方法" /&gt;&lt;p&gt;解决方法其实很简单，旭日派的WIFI模组检测不到5G频段的WIFI，现在的手机开启热点默认都是5G频段，因此将手机热点的频段改为2.4G即可，注意热点名称也不能带有中文。&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 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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 list 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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 wifi_connect &amp;#34;你要连接的wifi名&amp;#34; &amp;#34;wifi密码&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&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/04/image-20220902152042941-1024x263.png"&gt;&lt;/p&gt;
&lt;p&gt;等到终端返回信息“successfully activated&amp;quot;,就说明WIFI连接成功。我们可以Ping一个网站，来检查一下连接。如果能够Ping通，就说明网络已经连接成功，现在就可以成功连接到互联网了。&lt;/p&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;nmcli connnection modify 你的wifi名 connection.autoconnect yes
&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><item><title>回顾21年电赛</title><link>https://leo-wangbo.top/p/%E5%9B%9E%E9%A1%BE21%E5%B9%B4%E7%94%B5%E8%B5%9B/</link><pubDate>Sun, 28 Nov 2021 18:51:00 +0800</pubDate><guid>https://leo-wangbo.top/p/%E5%9B%9E%E9%A1%BE21%E5%B9%B4%E7%94%B5%E8%B5%9B/</guid><description>&lt;img src="https://leo-wangbo.top/" alt="Featured image of post 回顾21年电赛" /&gt;&lt;p&gt;说实话挺不想回顾这场电赛的，因为这次比赛的结果与付出严重不成正比，但生活的真相就是这样，努力有时不一定会有回报，罗曼罗兰曾经说过：“世上只有一种英雄主义，就是认清生活的真相之后依然热爱生活”。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/IMG_20211107_195708_edit_87234411352834-scaled.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="#%e9%a2%98%e7%9b%ae%e4%bb%8b%e7%bb%8d" class="header-anchor"&gt;&lt;/a&gt;题目介绍
&lt;/h2&gt;&lt;p&gt;其他组的题目都是关于信号采集，AC/DC的这方面没怎么接触过，只有F组是关于送药小车的，正好手头有一个车架，于是就选了F组的题目。题目要求是先搭建下图带有几个路口的赛道，一共有八个药房，小车从起点出发前要先识别一个1到8的数字，然后根据识别到的结果小车需要沿着红线找到对应的药房。&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/1636353667239_edit_82264883879634.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%ae%9e%e7%8e%b0%e8%bf%87%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;实现过程
&lt;/h2&gt;&lt;p&gt;电赛每个小组有三个人，小组另外两个人，一个人只会写文档，一个人资历尚浅（现已是大牛），所以基本除了写文档的所有工作都落我头上了😭。首先要解决的就是识别数字，最好的方案就是拿K210，因为K210训练部署视觉识别模型迅速，并且有专门的NPU（(神经网络处理单元）加速单元，识别也较为迅速。但是由于学校对于这类比赛很是轻视，没有任何资金补助（连电赛要用的纸箱子都不提供），赛前并未准备这类视觉识别模块。手头只有一个树莓派，网上利用树莓派识别数字的教程还挺多的的，多用python+opencv+tensorflow实现，我也尝试了一下发现识别的帧率只有十帧不到，这根本满足不了比赛的需求。此时已经到第二天上午了，电赛一共只有三天四夜的准备时间，万愁莫展之际我想到了一个下策，调用数字识别API，这可能有点耍阴招，但我看规则也没禁止这一行为（可能电赛加入视觉识别还没几年）。于是最终选择了调用百度api实现了数字。&lt;/p&gt;
&lt;p&gt;接下来就是识别红线了，幸好学过一点点OpenCV，先对图像进行预处理，包括灰度化、平滑滤波、二值化，然后就能轻松框出红线了。效果如下&lt;/p&gt;
&lt;figure&gt;
 &lt;img src="https://leo-wangbo.top/uploads/2023/01/N0WIJ2XD_FYH2NQW.png" alt=""&gt;
 &lt;figcaption&gt;&lt;strong&gt;识别红线&lt;/strong&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;接下来要实现让送药小车沿着红线前进，根据识别红线框出的框在视野中的坐标对车轮转速进行PID控制，但还是由于客观设备的限制，手头只有普通的直流电机，没有编码器与编码电机，这样就无法对转速进行闭环控制，所以最后沿着红线行驶时，超调量较大，导致有时就会沿着红线左右摇摆。效果如下：&lt;/p&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=BV1t34y1Z7Jd&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;p&gt;时间能力有限，到最后一天只能调成这样了，这个效果拿个省二等奖应该问题不大。但是到了最后开箱正式向评委展示的时候，发现电池没电了。。。。(调试时间太紧张，封箱前忘了给锂电池充电了）。最后小车动都没动起来，果然最终还是小细节决定成败啊😭。结果已经无法改变，总的来说这次电赛我还是学到很多的，三天四夜就没睡几个小时（提前体验996生活？😇），一直在调试软件硬件，查资料编代码的能力还是得到了一些锻炼的。&lt;/p&gt;</description></item></channel></rss>