【電賽學習筆記】MaxiCAM 項目實踐——二維云臺追蹤指定目標

前言

本文是對視覺模塊MaixCam實現二維云臺人臉跟蹤_嗶哩嗶哩_bilibili大佬的項目實踐整理與拓展,侵權即刪。

單路舵機基本控制

#導入必要模塊
from maix import pwm, time , pinmap#定義全局變量,設初值
SERVO_FREQ = 50         #主頻
SERVO_MIN_DUTY = 2.5    #最小角度占空比
SERVO_MAX_DUTY = 12.5   #最大角度占空比
#選擇pwm通道
pwm_id = 7
#引腳功能映射
pinmap.set_pin_function("A19", "PWM7")#定義角度設置函數
def angle_to_duty(angle):return (SERVO_MAX_DUTY - SERVO_MIN_DUTY) / 180 * angle + SERVO_MIN_DUTY     #固定公式無需記憶#創建PWM對象
out = pwm.PWM(pwm_id, freq = SERVO_FREQ, duty = angle_to_duty(0), enable = True)for i in range(180):out.duty(angle_to_duty(i))time.sleep_ms(10)

上述代碼實現了舵機從0°到180°的運動

舵機類的定義

class Servo:#設置屬性SERVO_FREQ = 50         #主頻SERVO_MIN_DUTY = 2.5    #最小角度占空比SERVO_MAX_DUTY = 12.5   #最大角度占空比SERVO_MAX_ANGLE = 180   #最大旋轉角#初始化函數def __init__(self, pwm_id:int, angle:int) -> None:angle = Servo.SERVO_MAX_ANGLE if angle > Servo.SERVO_MAX_ANGLE else angleangle = 0 if angle < 0 else angleif pwm_id == 7:pinmap.set_pin_function("A19", "PWM7")self.pwm = pwm.PWM(pwm_id, freq = Servo.SERVO_FREQ, duty = self._angle_to_duty_(angle), enable = True)elif pwm_id == 6:pinmap.set_pin_function("A18", "PWM6")self.pwm = pwm.PWM(pwm_id, freq = Servo.SERVO_FREQ, duty = self._angle_to_duty_(angle), enable = True)elif pwm_id == 5:pinmap.set_pin_function("A17", "PWM5")self.pwm = pwm.PWM(pwm_id, freq = Servo.SERVO_FREQ, duty = self._angle_to_duty_(angle), enable = True)elif pwm_id == 4:pinmap.set_pin_function("A16", "PWM4")self.pwm = pwm.PWM(pwm_id, freq = Servo.SERVO_FREQ, duty = self._angle_to_duty_(angle), enable = True)def __del__(self) -> None :self.pwm.disable()def _angle_to_duty_(self,angle:int) -> float :return (Servo.SERVO_MAX_DUTY - Servo.SERVO_MIN_DUTY) / 180 * angle + Servo.SERVO_MIN_DUTY def angle(self, angle:int) -> None:angle = Servo.SERVO_MAX_ANGLE if angle > Servo.SERVO_MAX_ANGLE else angleangle = 0 if angle < 0 else angleself.pwm.duty(self._angle_to_duty_(angle))

關于Python中“類”的簡介

下面以這一段 Servo 舵機控制類 為例子,把 Python 中“類的定義規則、各參數/變量的作用域與訪問規則” 逐條拆開講清。只要記住 3 句話就能不迷路:

  1. 類里定義的變量分 類變量實例變量

  2. 函數參數和返回值可以寫“類型注解”,但運行時不強制檢查。

  3. self. 的是實例自己的;不帶的是類或局部臨時的。


一、類的“殼子”怎么寫

class Servo:...
  • class 關鍵字 + 類名(首字母大寫,PEP8 規范)。

  • 冒號后縮進 4 空格,內部放 類變量、方法


二、類變量(Class Variables)

SERVO_FREQ      = 50
SERVO_MIN_DUTY  = 2.5
SERVO_MAX_DUTY  = 12.5
SERVO_MAX_ANGLE = 180
  • 寫在類體里、任何方法外

  • 所有實例共享同一份;通過 類名.變量實例.變量 都能讀

    Servo.SERVO_MAX_ANGLE   # 推薦
    my_servo.SERVO_MAX_ANGLE
  • 如果某個實例想“私自”改值,會變成該實例自己的同名屬性,不會動到類變量。


三、實例變量(Instance Variables)

實例變量在 __init__ 里用 self.名字 = ... 綁定:

self.pwm = pwm.PWM(...)
  • 每個對象各有一份,生命周期隨對象。

  • 訪問必須通過實例:my_servo.pwm


四、構造函數?__init__

def __init__(self, pwm_id: int, angle: int) -> None:
位置含義
self固定第 1 參數,指向當前正在創建的對象本身
pwm_id: int形參 +?類型注解(告訴人/IDE 該傳 int)。
angle: int同上。
-> None返回值注解:構造函數固定返回?None

五、形參、局部變量、類變量的區分示例

angle = Servo.SERVO_MAX_ANGLE if angle > Servo.SERVO_MAX_ANGLE else angle
  • 左邊 angle局部變量(形參名被重新綁定)。

  • Servo.SERVO_MAX_ANGLE類變量

  • 沒有 self. 前綴,所以不會存成實例屬性。


六、私有“工具函數”的命名慣例

def _angle_to_duty_(self, angle: int) -> float:
  • 單下劃線開頭 _name 表示“內部使用”,Python 不會強制隱藏,僅提示程序員。

  • self → 實例方法,能訪問實例變量 self.pwm

  • angle: int -> float 再次使用類型注解。


七、析構函數?__del__

def __del__(self) -> None:self.pwm.disable()
  • 對象被垃圾回收前自動調用;常用于釋放硬件資源。

  • 同樣帶 self,但不建議依賴它做關鍵清理,CPython 不保證時機。


八、實例方法?angle

def angle(self, angle: int) -> None:
  • 調用方式:servo.angle(90)

  • 內部通過 self.pwm.duty(...) 修改實例自己的 PWM。


九、變量/屬性的完整訪問路徑總結

寫法指向
Servo.SERVO_FREQ類變量(所有實例共享)
self.pwm實例變量(當前對象私有)
angle(無前綴)局部變量(函數內臨時)

十、快速記憶表

概念定義位置訪問方式生命周期
類變量類體,方法外類.變量 / 實例.變量隨類
實例變量__init__?里用?self.實例.變量隨實例
形參/局部變量函數參數或內部直接變量名函數調用期間

照以上規則,你就能看懂并寫出任何類似的 Python 類。

項目實戰——二位云臺色塊追蹤

from maix import camera, display, image, app
import servo### 初始化 ###
# 舵機初始角度
INIT_POS_X = 90
INIT_POS_Y = 100
# 濾波系數(越小越平滑,響應越慢)
FILTER_FACTOR = 0.15
# PID 系數(已調好,可微調)
KP = 0.018
KD = 0.20# 攝像頭與顯示
cam = camera.Camera(320, 240)        # 分辨率可改,但需與后續一致
dis = display.Display()# 舵機(PWM6→水平,PWM7→垂直)
servo_x = servo.Servo(6, INIT_POS_X)
servo_y = servo.Servo(7, INIT_POS_Y)# 目標角度初值
target_x_pos = INIT_POS_X
target_y_pos = INIT_POS_Y
last_err_x_pos = 0
last_err_y_pos = 0# 圖像中心
IMAGE_WIDTH  = 320
IMAGE_HEIGHT = 240# 紅色色塊的 LAB 閾值(需根據實際環境調整)
# 格式:(L_min, L_max, A_min, A_max, B_min, B_max)
color_threshold = [(0, 80, 30, 70, 10, 60)]while not app.need_exit():img = cam.read()# 查找色塊:merge=True 合并相鄰塊,pixels_threshold 過濾小面積blobs = img.find_blobs(color_threshold, merge=True, pixels_threshold=300)if not blobs:          # 沒檢測到dis.show(img)continue# 取最大色塊作為目標blob = max(blobs, key=lambda b: b.pixels())# 畫框和中心十字img.draw_rect(blob.x(), blob.y(), blob.w(), blob.h(), color=image.COLOR_GREEN)img.draw_cross(blob.cx(), blob.cy(), color=image.COLOR_RED, size=5)# ---------- 橫向 PID ----------err_x_pos = IMAGE_WIDTH / 2 - blob.cx()err_x_pos = FILTER_FACTOR * err_x_pos + (1 - FILTER_FACTOR) * last_err_x_posdelta_x_pos = KD * (err_x_pos - last_err_x_pos) + KP * err_x_poslast_err_x_pos = err_x_postarget_x_pos += delta_x_pos# ---------- 縱向 PID ----------err_y_pos = IMAGE_HEIGHT / 2 - blob.cy()err_y_pos = FILTER_FACTOR * err_y_pos + (1 - FILTER_FACTOR) * last_err_y_posdelta_y_pos = KD * (err_y_pos - last_err_y_pos) + KP * err_y_poslast_err_y_pos = err_y_postarget_y_pos += delta_y_pos# 舵機角度限幅(0°~180°)target_x_pos = max(0, min(180, target_x_pos))target_y_pos = max(0, min(180, target_y_pos))# 驅動舵機servo_x.angle(int(target_x_pos))servo_y.angle(int(target_y_pos))dis.show(img)

PID部分解釋

零基礎也能聽懂的 PID 小車比喻
(把“色塊追蹤”想成“讓小汽車自動開到路中間”)

────────────────────

  1. 先認識三個字母
    P —— Proportional 比例
    I —— Integral 積分
    D —— Derivative 微分

(先不用背英文,記住它們各自干的事就行)

────────────────────
2. 把問題換成生活例子

? 你坐在一輛玩具小汽車里,車要停在一條長路的正中間。
? 你每隔 1 秒鐘往窗外看一眼,測一下“車身離中線的距離”(這個距離就是誤差 err)。
? 每一次看完,你就給方向盤一個“修正量”(delta),讓車往中線靠。

PID 就是決定“修正量”的三兄弟。
────────────────────
3. 三兄弟分別做什么?

① 大哥 P(比例):
“離得越遠,打得越猛!”
公式:P 部分 = KP × err
? KP 是“比例系數”,像方向盤靈敏度。
? 如果 KP 太小,車慢吞吞;KP 太大,車猛沖過頭。

② 二哥 D(微分):
“快撞線了,趕緊松手!”
公式:D 部分 = KD × (err ? last_err)
? 只看“誤差變化的速度”。
? 當車快速接近中線時,D 會反向拉一把,避免沖過頭。
? 相當于“阻尼”,讓車不晃。

③ 小弟 I(積分):
“怎么老差一點?慢慢加把勁!”
? 把歷史上的誤差都加起來,再乘一個系數 KI。
? 對小誤差做長期“補償”。
? 本例為了簡單,把 I 關掉(KI=0),所以代碼里只有 P 和 D。

────────────────────
4. 代碼逐句翻譯

以橫向為例:

err_x_pos = IMAGE_WIDTH/2 - blob.cx()

→ 看一眼:色塊中心離畫面中心有多少像素。

err_x_pos = FILTER_FACTOR*err_x_pos + (1-FILTER_FACTOR)*last_err_x_pos

→ 先做個“小濾波”,讓測量值別太跳(和 PID 無關,只是讓數據平滑)。

delta_x_pos = KD*(err_x_pos - last_err_x_pos) + KP*err_x_pos

→ 把 P 和 D 兩個修正量合在一起:
? KPerr_x_pos → 大哥 P:離得多就轉得多。
? KD
(err-last) → 二哥 D:如果誤差變化很快,就減速。

last_err_x_pos = err_x_pos

→ 把這次誤差存起來,下次算 D 時用。

target_x_pos += delta_x_pos

→ 方向盤最終轉角 = 上次轉角 + 本次修正量。

縱向同理,只是換了一個方向。

────────────────────
5. 調參口訣(小白速成)

  1. 先把 KD 設為 0,只調 KP:

    • 車慢 → 增大 KP

    • 車抖動 → 減小 KP

  2. 再加 KD:

    • 車沖到中線停不下來 → 增大 KD

    • 車變得遲鈍 → 減小 KD

  3. 如果靜止時總有固定誤差,再加一點 KI(本例不需要)。

一句話總結
P 管“現在有多偏”,D 管“偏得有多快”,I 管“長期小偏差”,三兄弟一起用力,就能把色塊牢牢地鎖在畫面正中央!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90387.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90387.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90387.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深入解析 ArkUI 觸摸事件機制:從點擊到滑動的開發全流程

摘要 隨著 HarmonyOS NEXT 的不斷發展&#xff0c;ArkUI 逐漸成為主流的 UI 構建方式。而用戶交互在任何應用中都是基礎而又關鍵的一環&#xff0c;如何利用 ArkUI 提供的觸摸事件機制&#xff0c;如 onTouch、onClick、onSwipe 等&#xff0c;來實現自然、順滑、用戶友好的交互…

Tailwind CSS 自定義工具類與主題配置指南

一、自定義工具類配置在 src/tailwind.css 文件中&#xff0c;我們可以通過 layer utilities 指令添加自定義工具類&#xff1a;tailwind base; tailwind components; tailwind utilities;layer utilities {/* 自定義工具 上下浮動效果 */.animate-floatY {animation: floatY 3…

【代碼隨想錄二刷|704.二分查找、27.移除元素、977.有序數組的平方】

704.二分查找 題目鏈接&#xff1a;704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int search(vector<int>& nums, int target) {//不用二分查找&#xff0c;直接求// for(int i0;i<nums.size();i){// if(nums[i]target)…

基于Vue的工業設備大屏可視化模板(含設備地圖分布+宣傳模塊+報表展示+三維模型加載預覽)

場景 為實現工業設備可視化大屏需求&#xff0c;可實現基于地圖的設備數據管理&#xff0c;點擊具體設備可進行詳細介紹和三維模型展示。 可播放宣傳視頻&#xff0c;可展示PM數據報表等數據&#xff0c;可接受報警數據提醒、統計等數據。 基于現有開源平臺框架進行二次改造…

堆(Heap)優先級隊列(Priority Queue)

一、堆的概念堆&#xff08;Heap&#xff09;是一種特殊的基于樹的數據結構&#xff0c;通常分為最大堆和最小堆兩種類型。它滿足堆屬性&#xff1a;對于最大堆&#xff0c;父節點的值總是大于或等于其子節點的值&#xff1b;而對于最小堆&#xff0c;父節點的值總是小于或等于…

踩坑記錄:因版本不匹配導致 Boost 1.85 編譯失敗的完整解決過程

踩坑記錄&#xff1a;因版本不匹配導致 Boost 1.85 編譯失敗的完整解決過程 轉載請注明出處&#xff0c;歡迎評論區交流。 背景 最近在 Windows 11 VS2022 環境下嘗試用 b2 編譯 Boost 1.85.0&#xff0c;結果一路踩坑&#xff0c;最后發現罪魁禍首是 Boost.Build 自帶的 msv…

InfluxDB Line Protocol 協議深度剖析(二)

四、Line Protocol 寫入操作與實踐&#xff08;一&#xff09;HTTP API 寫入使用 HTTP API 是通過 Line Protocol 寫入數據到 InfluxDB 的常用方式。InfluxDB 1.x&#xff1a;請求方式為 POST&#xff0c;URL 格式為 “http://host:port/write?dbdatabase_name”。其中&#x…

負載均衡:提升業務性能的關鍵技術

一.負載均衡&#xff08;3.6 &#xff09;1.1.什么是負載均衡&#xff1a;負載均衡&#xff1a;Load Balance&#xff0c;簡稱LB&#xff0c;是一種服務或基于硬件設備等實現的高可用反向代理技術&#xff0c;負載均 衡將特定的業務(web服務、網絡流量等)分擔給指定的一個或多個…

【STM32項目】智能家居(版本1)

????大家好&#xff0c;這里是5132單片機畢設設計項目分享&#xff0c;今天給大家分享的是基于《基于STM32的智能家居設計》。 目錄 1、系統功能 2.1、硬件清單 2.2、功能介紹 2.3、控制模式 2、演示視頻和實物 3、系統設計框圖 4、軟件設計流程圖 5、原理圖 6、主…

OpenSCA開源社區每日安全漏洞及投毒情報資訊—2025年7月24日

2025年7月24日安全風險情報資訊在野漏洞風險&#xff08;CVE未收錄&#xff09;&#xff1a;1公開漏洞精選&#xff1a;2組件投毒情報&#xff1a;2在野漏洞風險&#xff08;CVE未收錄&#xff09;1.1 gemini-cli項目潛在命令注入漏洞項目詳情項目描述&#xff1a;gemini-cli是…

飛算 JavaAI 深度實戰:從老項目重構到全棧開發的降本增效密碼

飛算 JavaAI 深度實戰&#xff1a;從老項目重構到全棧開發的降本增效密碼引言正文一、智能引導模塊&#xff1a;老項目重構的 “手術刀” 級解決方案1.1 本地化智能分析&#xff1a;IDEA 插件實操演示1.1.1 &#x1f4cc; IDEA 插件安裝步驟1.1.1.1 首先打開idea工具&#xff0…

分布式推客系統開發全解:微服務拆分、傭金結算與風控設計

一、推客系統概述與市場背景推客系統&#xff08;也稱為分銷系統或社交電商系統&#xff09;已成為現代電商平臺和內容平臺的重要增長引擎。根據最新統計數據&#xff0c;2023年社交電商市場規模已突破3萬億元&#xff0c;占整體電商市場份額的25%以上。推客系統的核心價值在于…

Linux tcpdump 抓取udp 報文

一、tcpdump 支持命令選項tcpdump -i # 指定監聽網絡接口tcpdump -w # 將捕獲到的信息保存到文件中&#xff0c;且不分析和打印在屏幕tcpdump -r # 從文件中讀取數據tcpdump -n # 不把 ip 轉化成域名tcpdump -t # 在每行的輸出中不顯示時間tcpdump -v # 產生詳細的輸出tc…

Oracle數據塊8KB、OS默認認塊管理4KB,是否需調整大小為一致?

上班路上&#xff0c;腦中忽然閃現一個問題&#xff1a;Oracle數據庫塊大小&#xff08;8KB&#xff09;、操作系統文件系統塊大小&#xff08;4KB&#xff09;&#xff0c;為了減少IOPS&#xff0c;需不需要調整為一致&#xff1f;在數據塊保持一致的情況下&#xff0c;針對頻…

卡爾曼濾波器噪聲方差設置對性能影響的仿真研究

卡爾曼濾波器噪聲方差設置對性能影響的仿真研究 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家,覺得好請收藏。點擊跳轉到網站。 1. 引言 卡爾曼濾波器是一種廣泛應用于信號處理、控制系統、導航系統等領域的遞歸估計算法。它通過對系…

“多線程修路:當count++變成災難現場”

1.現象 當我們操作一個線程池的時候&#xff0c;可能需要去計數&#xff0c;也就是統計count&#xff0c;那我們這里有一個疑問&#xff0c;會不會產生線程安全問題&#xff1f; 毫無疑問絕對會有線程安全問題。在線程池環境中&#xff0c;多個線程并發訪問和修改一個共享的 co…

GaussDB null的用法

1 null的定義null 空值代表丟失的未知數據。 默認情況下&#xff0c;表列可以保存 null 值。 本章解釋 is null 和 is not null 操作符。2 null值的贅述如果表中的列是可選的&#xff0c;那么我們可以插入一個新記錄或更新一個現有記錄&#xff0c;而無 需向列添加一個值。這意…

智慧農業新圖景:物聯網如何精準守護作物生長?

在傳統農業生產模式下&#xff0c;農民往往憑借經驗判斷作物生長需求&#xff0c;灌溉、施肥缺乏精準性&#xff0c;導致水資源浪費、土壤板結、作物產量與品質難以提升等問題。加之氣候變化無常&#xff0c;極端天氣頻發&#xff0c;給農業生產帶來諸多不確定性&#xff0c;傳…

[ComfyUI] -入門2- 小白零基礎搭建ComfyUI圖像生成環境教程

AI圖像生成已經成為AIGC(人工智能生成內容)領域的重要組成部分,而ComfyUI作為一款可視化的Stable Diffusion工作流工具,以其模塊化、高度自由化的特點吸引了越來越多創作者的關注。本文將手把手教你如何在Windows系統下,從零搭建屬于自己的ComfyUI圖像生成環境。 一、Comf…

java設計模式 -【單例模式】

單例模式的定義 單例模式&#xff08;Singleton Pattern&#xff09;是一種創建型設計模式&#xff0c;確保一個類只有一個實例&#xff0c;并提供一個全局訪問點。常用于需要控制資源或共享狀態的場景&#xff0c;例如數據庫連接、日志記錄器等 單例模式的實現方式 餓漢式&…