OpenMV Pure Thermal#
OpenMV Pure Thermal คือบอร์ดถ่ายภาพความร้อนแบบระบบสมบูรณ์ที่สร้างบน STMicroelectronics STM32H743 (Cortex‑M7 @ 480 MHz) พร้อม SDRAM ภายนอก 64 MB, แฟลช QSPI 32 MB, ตัวแปลงสัญญาณ JPEG แบบฮาร์ดแวร์, จอสัมผัสแบบ capacitive IPS 4.3" ขนาด 800×480, ช่องออก HDMI, ซ็อกเก็ต FLIR® Lepton® สำหรับกล้องความร้อน และกล้องแสงปกติ OV5640 ขนาด 5MP นอกจากนี้ยังมี Wi‑Fi, ช่องเสียบ microSD, เครื่องวัดระยะด้วยเลเซอร์, บัซเซอร์ และหลอด LED สีขาวกำลังสูง
สำหรับข้อมูลแผ่นข้อมูล รูปถ่าย และขนาด โปรดดูที่ หน้าผลิตภัณฑ์ OpenMV Pure Thermal
คุณสมบัติเด่น#
STMicroelectronics STM32H743XI Cortex‑M7 ที่ 480 MHz
ตัวแปลงสัญญาณ JPEG encoder/decoder แบบฮาร์ดแวร์
SDRAM ภายนอก 64 MB (~400 MB/s) บวก SRAM ภายใน 1 MB
แฟลชภายใน 2 MB + แฟลช QSPI ภายนอก 32 MB (~50 MB/s อ่าน)
เซนเซอร์แสงปกติแบบ rolling‑shutter OV5640 ขนาด 5MP
ซ็อกเก็ต FLIR® Lepton® — รองรับ Lepton รุ่น 1/2/2.5/3/3.5 ทั้งแบบ radiometric และ non‑radiometric พร้อมอุณหภูมิต่อพิกเซลเป็นองศาเซลเซียส
จอสัมผัสแบบ capacitive IPS 4.3" ขนาด 800×480 (สี 24 บิต @ 60 Hz) รองรับท่าทางสัมผัสได้สูงสุด 5 จุด
ช่องออก HDMI ผ่าน TFP410 DVI serializer — สูงสุด 1280×720 @ 60 Hz
Wi‑Fi ผ่าน WINC1500; รองรับ MJPEG over RTSP แบบพร้อมใช้งานทันที
USB‑C ความเร็วเต็ม (12 Mb/s, จำกัดกระแส 900 mA) — ปรากฏเป็น VCP + USB mass storage ต่อโฮสต์ รวมถึงรองรับการชาร์จด้วย
ช่องเสียบ microSD — SD สูงสุด 2 GB, SDHC สูงสุด 32 GB, SDXC สูงสุด 2 TB
เครื่องวัดระยะเลเซอร์ VL53L1CX (สูงสุด ~4 ม.)
บัซเซอร์ ที่ควบคุมระดับเสียง/ความถี่ด้วยซอฟต์แวร์
หลอด LED สีขาวกำลังสูง นอกเหนือจาก LED แสดงสถานะ RGB ของผู้ใช้
ขั้วต่อแบตเตอรี่ LiPo พร้อมการชาร์จผ่าน USB ที่ 500 mA
พิน I/O จำนวน 10 พิน, รองรับ 5 V ทนได้ มีแรงดันเอาต์พุต 3.3 V, 25 mA ต่อพิน (รวม 120 mA), รองรับอินเทอร์รัปต์ P6 ไม่ รองรับ 5 V เมื่อใช้ในโหมด ADC หรือ DAC
ARM 10‑pin SWD สำหรับการดีบัก ST‑LINK / J‑Link
ขั้วต่อ Qwiic สำหรับอุปกรณ์ต่อพ่วง I²C
Note
บอร์ดมีช่องที่ขอบล่างซ้ายสำหรับใส่ น็อตขาตั้งกล้อง ¼"–20 แบบเสริม ไม่ได้ติดมาจากโรงงาน — บัดกรีเข้าในช่องถ้าต้องการติดบอร์ดบนขาตั้งกล้องมาตรฐาน
การกำหนดพิน#
ข้อมูลอ้างอิงพิน#
ชื่อพิน | ฟังก์ชัน |
|---|---|
P0 | UART1 RX / SPI2 MOSI |
P1 | UART1 TX / SPI2 MISO |
P2 | SPI2 SCK / FDCAN2 TX |
P3 | SPI2 NSS (CS) / FDCAN2 RX |
P4 | I2C2 SCL / UART3 TX / TIM2 CH3 |
P5 | I2C2 SDA / UART3 RX / TIM2 CH4 |
P6 | ADC / DAC / TIM2 CH1 |
P7 | I2C4 SCL / TIM4 CH1 |
P8 | I2C4 SDA / TIM4 CH2 |
P9 | digital I/O |
RESET | ดึงไปที่ GND เพื่อรีเซ็ตบอร์ด |
SYN | แพด frame‑sync — ไม่ได้ต่อเชื่อม |
VIN | แพด shield VIN — ไม่ได้ต่อเชื่อม |
BOOT0 | ดึงไปที่ 3.3 V ขณะเปิดเครื่องเพื่อเข้า DFU / ROM bootloader |
BUZZER | บัซเซอร์ piezo บนบอร์ด (ขับด้วย TIM2/PWM) |
LED_RED | ช่องแดงของ LED แสดงสถานะ RGB (active low) |
LED_GREEN | ช่องเขียวของ LED แสดงสถานะ RGB (active low) |
LED_BLUE | ช่องน้ำเงินของ LED แสดงสถานะ RGB (active low) |
LED_WHITE | หลอด LED สีขาวกำลังสูง |
Note
แพด SYN และ VIN บน shield/header ไม่มีการเชื่อมต่อทางไฟฟ้า บน Pure Thermal — มีไว้เพื่อความเข้ากันได้ของ header เท่านั้น จ่ายไฟให้บอร์ดผ่าน USB‑C หรือขั้วต่อแบตเตอรี่ LiPo บนบอร์ดแทน (ดู พินจ่ายไฟ ด้านล่าง) นอกจากนี้ แพด VIN มีการพิมพ์บนบอร์ดว่า VBAT (เป็นข้อผิดพลาดในการระบุชื่อ) — ตำแหน่งเป็นพิน VIN ของ header OpenMV มาตรฐานและไม่ได้ต่อเชื่อมไม่ว่าทิศทางใด
พินจ่ายไฟ#
3.3V — ราง 3.3 V ที่ผ่านการปรับแรงดัน มีให้สูงสุด 250 mA สำหรับ shield
GND — กราวด์ร่วม
Pure Thermal รับไฟผ่าน USB‑C หรือ ขั้วต่อแบตเตอรี่ LiPo บนบอร์ด พอร์ต USB‑C จำกัดกระแสรวมไว้ที่ 900 mA และรองรับการชาร์จ LiPo ที่ 500 mA ดังนั้นสามารถต่อแบตเตอรี่พร้อมกับ USB ได้
ปุ่มเปิด/ปิด บนบอร์ดสลับเปิด/ปิดรางไฟฟ้าของระบบ และทำงานได้ไม่ว่าจะจ่ายไฟจาก USB หรือ LiPo กดปุ่มค้างไว้สักสองสามวินาที เพื่อสลับสถานะ — การกดเบาจะถูกละเว้นเพื่อป้องกันการปิดเครื่องโดยไม่ตั้งใจ
การเลือกแหล่งจ่ายไฟทำตามกฎง่าย ๆ สองข้อ:
แบตเตอรี่จะจ่ายไฟให้บอร์ดก็ต่อเมื่อแรงดันสูงกว่า 3 V ต่ำกว่าค่าขีดแบ่งนั้น PMIC บนบอร์ดจะตัดแบตเตอรี่ออกเพื่อป้องกันการคายประจุมากเกินไป
เมื่อมี USB ต่ออยู่ USB จะจ่ายไฟให้บอร์ด และ LiPo ที่ต่ออยู่จะชาร์จในเบื้องหลัง
ขั้วต่อ LiPo ยังมี การป้องกันแรงดันย้อนกลับ ดังนั้นการเสียบแบตเตอรี่กลับด้านจะไม่ทำให้บอร์ดเสียหาย
Note
บอร์ดยังส่ง แรงดันแบตเตอรี่ และ สัญญาณวัดกระแสแบตเตอรี่ กลับไปยังช่อง ADC ของ MCU แต่ยังไม่มีการเพิ่มการรองรับเฟิร์มแวร์สำหรับทั้งสองอย่าง
พินสำหรับการกู้คืนและดีบัก#
RESET — ดึงไปที่ GND เพื่อรีเซ็ตบอร์ด Pure Thermal ยังมี ปุ่ม RESET บนบอร์ดที่ทำงานเหมือนกัน
BOOT0 — ดึงไปที่ 3.3 V ขณะเปิดเครื่องเพื่อเข้าสู่ ROM bootloader ของ STM32 (โหมด DFU) OpenMV IDE ใช้โหมดนี้ในการเขียน bootloader บนบอร์ดใหม่ ปุ่ม BOOT0 บนบอร์ดทำงานเหมือนกัน — กดค้างขณะเปิดเครื่อง
บอร์ดมีหัวต่อดีบัก SWD (RST / SWCLK / SWDIO / SWO) อยู่ถัดจากหัวต่อ GPIO เข้ากันได้กับอะแดปเตอร์ ST‑LINK และ SEGGER J‑Link นอกจากนี้ยังมีขั้วต่อ ARM 10‑pin SWD แบบแยกติดตั้งอยู่ด้วย — มีสัญญาณ SWD เหมือนกัน (ไม่มี JTAG เต็มรูปแบบ) แต่ในรูปแบบ 0.05" 10‑pin มาตรฐาน
Note
พิน trace SWO ใช้ร่วมกับสัญญาณนาฬิกา SPI ของ FLIR® Lepton® บนบอร์ด ไม่สามารถใช้ SWO พร้อมกับ Lepton — ต้องเลือกอย่างใดอย่างหนึ่ง
ขั้วต่อ PURE Modules Debug ตัวที่สามติดตั้งอยู่บนบอร์ด โดยแยกสัญญาณที่เน้นการดีบักออกมาหลายสัญญาณ (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3.3 V, GND และพิน GPIO สองพิน) สำหรับเชื่อมต่อโมดูลเสริม พิน GPIO สองพินบนขั้วต่อนี้ขับเคลื่อนโดย I²C bus แบบ bit‑banged แทนที่จะเป็นอุปกรณ์ต่อพ่วงฮาร์ดแวร์
ขั้วต่อดีบักทั้งสาม (หัวต่อ SWD แบบแนว, ขั้วต่อ ARM 10‑pin SWD และขั้วต่อ PURE Modules Debug) อ้างอิง 3.3 V — ตรวจสอบให้แน่ใจว่าอะแดปเตอร์ดีบักของคุณถูกตั้งค่าสำหรับลอจิก 3.3 V ก่อนเชื่อมต่อ
อุปกรณ์ต่อพ่วงบนบอร์ด#
LED#
Pure Thermal มี LED สามดวงบนบอร์ด:
LED RGB สำหรับผู้ใช้ — ควบคุมด้วยซอฟต์แวร์ เข้าถึงได้ผ่าน
LED_RED,LED_GREENและLED_BLUEfrom machine import LED LED("LED_RED").on() LED("LED_GREEN").on() LED("LED_BLUE").on()
หลอด LED สีขาว — ขับเคลื่อนผ่าน
LED_WHITELED_WHITEต่อสายแบบ active high ในฮาร์ดแวร์ ในขณะที่เฟิร์มแวร์ถือว่า LED บนบอร์ดอื่น ๆ ทุกดวงเป็น active low ดังนั้นใช้low()/high()แทนon()/off()(ซึ่งจะกลับทิศตรรกะ):from machine import LED light = LED("LED_WHITE") light.low() # turn the white LED ON light.high() # turn the white LED OFF
LED ชาร์จ — ขับเคลื่อนโดยตรงจากฮาร์ดแวร์จัดการพลังงานบนบอร์ด ไม่มีการควบคุมด้วยซอฟต์แวร์ ทำงานได้ไม่ว่ารางระบบจะเปิดหรือปิด (คือไม่ว่าปุ่มเปิด/ปิดจะอยู่ตำแหน่งใด)
สี
ความหมาย
น้ำเงิน
กำลังชาร์จ — ดูข้อผิดพลาด: อาจไม่ดับเมื่อชาร์จเสร็จ
เขียว
ชาร์จเสร็จแล้ว — ดูข้อผิดพลาด: อาจไม่ทำงานได้อย่างน่าเชื่อถือ
แดง
แบตเตอรี่เหลือน้อย (≤ 3.2 V, เฉพาะเมื่อไม่ได้ชาร์จอยู่)
บัซเซอร์#
บัซเซอร์ piezo บนบอร์ดต่อสายไปยังช่องตัวจับเวลา — ขับด้วย machine.PWM เพื่อสร้างเสียงที่มีการควบคุมความถี่ (ระดับเสียง) และรอบดิวตี้ (ระดับเสียง) ด้วยซอฟต์แวร์:
import time
from machine import Pin, PWM
beep = PWM(Pin("BUZZER"), freq=2_000, duty_u16=32768) # ~50% duty
time.sleep_ms(500) # sound for 0.5 s
beep.deinit()
เซนเซอร์กล้อง#
OV5640 เป็น CSI หลักบน Pure Thermal — ส่ง cid=csi.OV5640 เพื่อระบุตำแหน่งอย่างชัดเจน:
import csi
cam = csi.CSI(cid=csi.OV5640)
cam.reset(hard=True)
cam.pixformat(csi.RGB565)
cam.framesize(csi.WVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
OV5640 มีตัวบีบอัด JPEG บนบอร์ด ตั้งค่า csi.CSI.pixformat เป็น csi.JPEG แล้วเซนเซอร์จะส่งเฟรมที่บีบอัดแล้วไปยังกล้องโดยตรงผ่านบัสกล้อง ซึ่งทำให้การถ่ายภาพความละเอียดสูงเป็นเรื่องปฏิบัติได้จริง: csi.HD (1280×720), csi.FHD (1920×1080) และ 5MP เต็ม csi.WQXGA2 (2592×1944) สตรีมได้ในรูปแบบ JPEG ปรับการบีบอัดด้วย csi.CSI.quality (0-100 ค่าสูงกว่า = เฟรมใหญ่กว่า รายละเอียดมากกว่า):
cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)
OV5640 มีเลนส์โฟกัสอัตโนมัติแบบ voice‑coil‑actuator เรียกโฟกัสอัตโนมัติแบบครั้งเดียวผ่าน csi.CSI.ioctl พร้อม csi.IOCTL_TRIGGER_AUTO_FOCUS — เซนเซอร์จะกวาดมอเตอร์โฟกัสครั้งเดียวและล็อคที่สิ่งที่อยู่ตรงหน้า:
cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)
เรียก ioctl ซ้ำทุกครั้งที่ฉากเปลี่ยน — โฟกัสอัตโนมัติเป็นแบบครั้งเดียว ไม่ใช่ต่อเนื่อง
Note
เอาต์พุต STROBE ของ OV5640 (ใช้สำหรับแฟลช/ไฟ IR แบบซิงโครไนซ์) ต่อสายไปยัง MCU บน Pure Thermal แต่ยังไม่มีการเพิ่มการรองรับเฟิร์มแวร์สำหรับมัน
เซนเซอร์กล้องความร้อน#
ซ็อกเก็ต FLIR® Lepton® ปรากฏเป็น CSI ตัวที่สองบน API เดียวกัน csi --- เซ็นเซอร์กล้อง ส่ง cid=csi.LEPTON เพื่อระบุตำแหน่ง และข้ามการรีเซ็ตฮาร์ดแวร์:
import csi
lepton = csi.CSI(cid=csi.LEPTON)
lepton.reset(hard=False)
lepton.pixformat(csi.GRAYSCALE)
lepton.framesize(csi.QVGA)
while True:
img = lepton.snapshot()
Note
เอาต์พุต VSYNC ของ Lepton (หนึ่งพัลส์ต่อเฟรมความร้อน) ต่อสายไปยัง MCU บน Pure Thermal แต่ยังไม่มีการเพิ่มการรองรับเฟิร์มแวร์สำหรับมัน
CSI ทั้งสองสามารถทำงานพร้อมกันได้ ตัวอย่างด้านล่างดึงเฟรมสีจาก OV5640 และเฟรมความร้อนจาก Lepton จากนั้นซ้อนทับ Lepton ไว้บนเฟรมสีโดยใช้พาเลต Ironbow และมาสก์อัลฟ่าที่จางลงเป็นโปร่งใสที่ความเข้มต่ำ:
import csi
import image
import math
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
csi0 = csi.CSI()
csi0.reset(hard=True)
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.WVGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False)
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QVGA)
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(
img1, 0, 0,
color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR,
)
การเรียนรู้ของเครื่อง#
ml --- Machine Learning รันโมเดล TFLite แบบ quantised บน Cortex‑M7 ด้วยเคอร์เนล CMSIS‑NN — เร็วพอสำหรับตัวตรวจจับขนาดกะทัดรัดที่สักสองสามเฟรมต่อวินาที โมเดลในระบบไฟล์แบบอ่านอย่างเดียว /rom โหลดโดยตรงจากแฟลชโดยไม่ต้องคัดลอกไปยัง RAM นี่คือตัวตรวจจับใบหน้า BlazeFace ขนาด 128×128 ที่ซ้อนทับใบหน้าที่ตรวจพบและจุดสำคัญ 6 จุดบนทุกเฟรมจากกล้องแสงปกติ:
import csi
import time
import ml
from ml.postprocessing.mediapipe import BlazeFace
# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))
# Load built-in face detection model
model = ml.Model("/rom/blazeface_front_128.tflite", postprocess=BlazeFace(threshold=0.4))
print(model)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# faces is a list of ((x, y, w, h), score, keypoints) tuples
for r, score, keypoints in model.predict([img]):
ml.utils.draw_predictions(img, [r], ("face",), ((0, 0, 255),), format=None)
# keypoints is a ndarray of shape (6, 2)
# 0 - right eye (x, y)
# 1 - left eye (x, y)
# 2 - nose (x, y)
# 3 - mouth (x, y)
# 4 - right ear (x, y)
# 5 - left ear (x, y)
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
print(clock.fps(), "fps")
เครื่องวัดระยะเลเซอร์#
ST VL53L1CX time‑of‑flight ranger บนบอร์ดต่อสายไปยัง I²C bus 2 ใช้ไดรเวอร์แช่แข็ง vl53l1x --- ไดรเวอร์เซนเซอร์วัดระยะ VL53L1X ToF เพื่อรับค่าระยะทางสูงสุด ~4 ม.:
import time
from machine import I2C
import vl53l1x
bus = I2C(2)
tof = vl53l1x.VL53L1X(bus)
while True:
print("Distance:", tof.read(), "mm")
time.sleep_ms(100)
เอาต์พุต LCD#
LCD บนบอร์ดขนาด 4.3" มีความละเอียด 800 × 480 (WVGA) และขับเคลื่อนผ่านอินเทอร์เฟซจอแสดงผล RGB ของโมดูล display --- ไดรเวอร์ดิสเพลย์ — ส่ง framesize=display.FWVGA เพื่อให้ตรงกับความละเอียดดั้งเดิม:
import display
lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True) # turn the LCD backlight on
lcd.write(img)
แบ็คไลท์ต่อสายไปยัง GPIO ดังนั้น backlight() รับ True / False (หรือค่าใด ๆ ระหว่าง 0–100 โดย 0 คือปิด และค่าที่ไม่ใช่ศูนย์คือเปิด):
lcd.backlight(False) # turn the backlight off
lcd.backlight(True) # back on
จอสัมผัส#
ตัวควบคุมการสัมผัสแบบ capacitive คือ FT5X06; ตำแหน่งการสัมผัสหลายจุดและเหตุการณ์ท่าทางมือถูกเปิดเผยผ่าน ft5x06 --- ไดรเวอร์หน้าจอสัมผัส ลงทะเบียนคอลแบ็กเพื่อตอบสนองต่อการสัมผัสและอ่านจุดที่ใช้งานอยู่ภายใน:
import ft5x06
touch = ft5x06.FT5X06()
def on_touch(n):
for i in range(n):
x = touch.get_point_x(i)
y = touch.get_point_y(i)
print("touch", i, "at", x, y)
gesture = touch.get_gesture()
if gesture != ft5x06.GESTURE_NONE:
print("gesture:", gesture)
touch.touch_callback(on_touch)
เอาต์พุต HDMI#
เฟิร์มแวร์ยังแจกจ่าย framebuffer ของ LCD ไปยัง tfp410 --- ตัวควบคุม DVI/HDMI HDMI serializer บนบอร์ดด้วย ทำให้จอภาพภายนอกสะท้อนสิ่งที่อยู่บน LCD สร้าง tfp410.TFP410 เพื่อเปิดใช้งานเอาต์พุต HDMI:
import tfp410
hdmi = tfp410.TFP410()
หากต้องการเฉพาะเอาต์พุต HDMI และไม่สนใจ LCD บนบอร์ด ให้ปิดแบ็คไลท์และเพิ่มความละเอียด framebuffer ให้เกิน WVGA TFP410 รองรับสูงสุด 1280×720 @ 60 Hz ตัวอย่างเช่น:
lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False) # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()
แผงบนบอร์ดมีความละเอียดคงที่ที่ 800×480 ดังนั้นอะไรก็ตามที่เกิน WVGA จะมีความหมายเฉพาะบนจอภาพ HDMI ภายนอกเท่านั้น
เพื่อทราบเมื่อจอภาพ HDMI ถูกเสียบหรือถอดออก ให้ลงทะเบียนคอลแบ็ก hot‑plug บน TFP410 คอลแบ็กจะทำงานด้วย True เมื่อเชื่อมต่อ และ False เมื่อตัดการเชื่อมต่อ:
def on_hotplug(connected):
print("HDMI", "connected" if connected else "disconnected")
hdmi.hotplug_callback(on_hotplug)
คุณยังสามารถโพลสถานะการเชื่อมต่อได้ทุกเมื่อด้วย isconnected() (เฉพาะเมื่อไม่มีการลงทะเบียนคอลแบ็ก)
พอร์ต HDMI ยังรองรับช่อง DDC (ข้อมูลการแสดงผล) และ CEC (การควบคุมอิเล็กทรอนิกส์สำหรับผู้บริโภค) เปิดเผยผ่านคลาส คลาส DisplayData -- ข้อมูลดิสเพลย์ ใช้มันเพื่ออ่านบล็อก EDID ของจอภาพที่เชื่อมต่ออยู่ (เพื่อให้ปรับตัวตามความละเอียด/อัตราการรีเฟรชดั้งเดิม) หรือเพื่อส่ง/รับเฟรม CEC สำหรับควบคุมอุปกรณ์ HDMI อื่น ๆ บนสายเดียวกัน:
from display import DisplayData
dd = DisplayData(cec=True, ddc=True)
edid = dd.display_id() # EDID bytes from the monitor
print(len(edid), "byte EDID")
# Send a CEC "image view on" command (opcode 0x04) from address 1 to address 0
dd.send_frame(0, 1, b"\x04")
# ...or wait for an incoming CEC frame addressed to us (logical address 1)
src, data = dd.receive_frame(1, timeout=5_000)
print("CEC from", src, ":", data)
Wi‑Fi#
Wi‑Fi ทำงานผ่านโมดูล Microchip WINC1500 เปิดเผยผ่านอินเทอร์เฟซ class WINC -- ไดรเวอร์ WiFi shield
import network, time
wlan = network.WINC()
wlan.connect("ssid", "password")
while not wlan.isconnected():
time.sleep(1)
print("Wi‑Fi IP:", wlan.ipconfig("addr4")[0])
Note
เนื่องจากปัญหาการขาดแคลนชิ้นส่วน บาง Pure Thermal ถูกจัดส่งโดยไม่มีโมดูล WINC1500 ติดตั้ง หาก network.WINC ทำให้เกิดข้อผิดพลาดหรือเชื่อมต่อไม่ได้ ให้ตรวจสอบบอร์ดว่าขาดโมดูล Wi‑Fi — ส่วนที่เหลือของกล้องทำงานได้เหมือนกันทุกอย่างโดยไม่มีมัน
การ์ด microSD#
เมื่อใส่การ์ดจะถูก mount อัตโนมัติที่ /sdcard และสามารถใช้งานผ่านระบบไฟล์ปกติ:
import os
for entry in os.listdir("/sdcard"):
print(entry)
ข้อมูลอ้างอิงบัส#
GPIO#
ใช้ machine.Pin เพื่ออ่านหรือขับพินที่มีชื่อบนบอร์ด เอาต์พุตเป็น 3.3 V CMOS รองรับ 5 V ในด้านอินพุต และสามารถ sink/source ได้สูงสุด 25 mA ต่อพิน (รวม 120 mA ทั่วทั้ง header)
from machine import Pin
out = Pin("P0", Pin.OUT)
out.on()
out.off()
out.value(1)
inp = Pin("P1", Pin.IN, Pin.PULL_UP)
print(inp.value())
พินอินพุตใด ๆ ยังสามารถเรียกอินเทอร์รัปต์บนการเปลี่ยนขอบสัญญาณได้:
def handler(pin):
print("triggered:", pin)
Pin("P1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART#
บัส | TX | RX |
|---|---|---|
UART1 | P1 | P0 |
UART3 | P4 | P5 |
from machine import UART
uart = UART(3, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C#
บัส | SCL | SDA |
|---|---|---|
I2C2 | P4 | P5 |
I2C4 | P7 | P8 |
from machine import I2C
i2c = I2C(2, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
ฮาร์ดแวร์เดียวกันยังสามารถใช้ในโหมด target (slave) ผ่าน machine.I2CTarget เพื่อเปิดเผยพื้นที่หน่วยความจำให้กับตัวควบคุม I²C อื่น:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)
ขั้วต่อ Qwiic บนบอร์ดแยกบัส I²C ตัวหนึ่งเหล่านี้ออกมาสำหรับโมดูลแบบ plug‑and‑play สายอนุกรม Qwiic ถูก level-shifted เป็น 5 V ผ่านทรานซิสเตอร์แบบ open‑drain ดังนั้นบัสจำกัดเฉพาะ โหมดมาตรฐาน (100 kHz) และ โหมดเร็ว (400 kHz) เท่านั้น — อย่าพยายามรันโหมดเร็วพิเศษหรืออัตราสูงกว่าผ่าน Qwiic header
ขั้วต่อ Qwiic จ่าย 5 V เพื่อขับโมดูลที่ต่ออยู่; ไม่สามารถใช้จ่ายไฟให้ Pure Thermal เอง — จ่ายไฟให้บอร์ดผ่าน USB‑C หรือขั้วต่อแบตเตอรี่ LiPo แทน
SPI#
บัส | MOSI | MISO | SCK | CS |
|---|---|---|---|---|
SPI2 | P0 | P1 | P2 | P3 |
from machine import SPI
from machine import Pin
spi = SPI(2, baudrate=10_000_000)
cs = Pin("P3", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
CAN (FDCAN)#
บัส | TX | RX |
|---|---|---|
FDCAN2 | P2 | P3 |
from machine import CAN
can = CAN(2, 500_000)
can.set_filters(None)
can.send(0x123, b"\xDE\xAD\xBE\xEF")
print(can.recv())
ADC และ DAC#
P6 เป็นพินอนาล็อกสำหรับผู้ใช้เพียงพินเดียว สามารถใช้เป็นอินพุต ADC 12 บิตหรือเอาต์พุต DAC ได้
ADC — สเกลเต็มที่ 3.3 V ที่พิน:
from machine import ADC import time adc = ADC("P6") while True: voltage = adc.read_u16() * 3.3 / 65535 print(voltage) time.sleep_ms(100)
DAC — ผ่าน
pyb.DACค่า 8 บิตครอบคลุม 0–3.3 V:from pyb import DAC dac = DAC("P6") voltage = 1.65 dac.write(int(voltage / 3.3 * 255))
ในโหมด ADC หรือ DAC P6 รองรับเฉพาะ 3.3 V เท่านั้น — ห้ามป้อน 5 V
PWM#
พิน | ตัวจับเวลา / ช่อง |
|---|---|
P4 | TIM2 CH3 |
P5 | TIM2 CH4 |
P6 | TIM2 CH1 |
P7 | TIM4 CH1 |
P8 | TIM4 CH2 |
Note
TIM1 ถูกสงวนไว้ โดยเฟิร์มแวร์เพื่อสร้างสัญญาณนาฬิกาพิกเซลของเซนเซอร์กล้อง ดังนั้นช่อง TIM1 ที่อยู่บน P0/P1/P2 ทางกายภาพจึงไม่สามารถใช้สำหรับ PWM ของผู้ใช้โดยไม่ทำให้กล้องเสียหาย
TIM4 ใช้ร่วมกับ pyb.Servo — การสร้าง servo จะตั้งค่าตัวจับเวลาทั้งหมดใหม่เป็นโหมด 50 Hz ดังนั้นอย่าผสม machine.PWM บน P7/P8 กับ pyb.Servo ในสคริปต์เดียวกัน
ขับใด ๆ ของพวกมันผ่าน machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("P7"), freq=1_000, duty_u16=32768)
บัสแบบ Software bit‑banged#
machine.SoftI2C และ machine.SoftSPI ทำงานบน GPIO ใด ๆ หากต้องการบัสเพิ่มเติม
เซนเซอร์ความร้อน (ภายนอกบอร์ด)#
นอกเหนือจาก FLIR Lepton บนบอร์ด เฟิร์มแวร์ยังรวมไดรเวอร์ fir --- ไดรเวอร์เซนเซอร์ความร้อน (fir == far infrared) สำหรับเครื่องถ่ายภาพความร้อน I²C แบบต่อสายภายนอก:
MLX90621 — IR array 16 × 4
MLX90640 — IR array 32 × 24
MLX90641 — IR array 16 × 12
AMG8833 — IR array 8 × 8
ต่อสายโมดูลเข้ากับบัส I²C ของบอร์ดและอ่านเฟรมด้วย fir.init() + fir.snapshot()
import time
import image
import fir
fir.init() # auto‑detects the sensor
clock = time.clock()
while True:
clock.tick()
try:
img = fir.snapshot(x_scale=5, y_scale=5,
color_palette=image.PALETTE_IRONBOW,
hint=image.BICUBIC,
copy_to_fb=True)
except OSError:
continue
print(clock.fps())
ไดรเวอร์ fir สื่อสารกับเซนเซอร์ผ่าน I²C 2 เท่านั้น — ต่อสายโมดูลเข้ากับ P4 (SCL) และ P5 (SDA)
เวลา#
time#
import time
time.sleep(1)
time.sleep_ms(500)
time.sleep_us(10)
start = time.ticks_ms()
elapsed = time.ticks_diff(time.ticks_ms(), start)
ตัวจับเวลาเสมือน#
from machine import Timer
one_shot = Timer(-1)
one_shot.init(period=5_000, mode=Timer.ONE_SHOT,
callback=lambda t: print("once"))
periodic = Timer(-1)
periodic.init(period=2_000, mode=Timer.PERIODIC,
callback=lambda t: print("tick"))
ค่า Period เป็นมิลลิวินาที เรียก deinit() เพื่อหยุดและคืนสล็อต
นาฬิกาแบบเรียลไทม์#
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())
หากต่อแบตเตอรี่ LiPo ไว้ RTC จะเก็บเวลาไว้แม้ขณะที่รางระบบปิดอยู่ (ปิดผ่านปุ่มเปิด/ปิดบนบอร์ด) หากเสียบเฉพาะ USB การกดปุ่มเปิด/ปิดจะตัดไฟไปยัง RTC เช่นกัน — ดังนั้นเวลาจากนาฬิกาจะไม่คงอยู่หลังวงจรไฟฟ้าโดยไม่มีแบตเตอรี่ต่ออยู่
Watchdog#
from machine import WDT
wdt = WDT(timeout=5_000)
while True:
# ...do work...
wdt.feed()
ข้อมูลการบูตและรันไทม์#
หน้าต่าง USB bootloader#
ในทุกการเปิดเครื่อง กล้องจะรัน bootloader สั้น ๆ (สักสองสามวินาที) ที่ให้ OpenMV IDE อัปเดตเฟิร์มแวร์โดยไม่ต้องให้ผู้ใช้เข้าโหมด DFU หลังจากหน้าต่างหมดเวลา bootloader จะส่งต่อไปยัง boot.py แล้วจึง main.py
สคริปต์ที่กำลังทำงานสามารถกลับเข้าสู่ bootloader ได้ตามต้องการโดยเรียก machine.bootloader()
ระบบไฟล์และลำดับการบูต#
เฟิร์มแวร์ Pure Thermal mount ระบบไฟล์สูงสุดสามระบบเมื่อบูต:
แฟลชภายใน — mount ที่
/flashเสมอ เก็บmain.pyและREADME.txtตามค่าเริ่มต้น; สร้างในการบูตครั้งแรกการ์ด microSD — หากใส่การ์ดแล้วจะถูก mount ที่
/sdcardROMFS — ระบบไฟล์แบบ memory‑mapped อ่านอย่างเดียวที่
/romใช้สำหรับส่งมอบข้อมูลขนาดใหญ่ (เช่น โมเดล AI) ที่ได้ประโยชน์จากการเข้าถึงแบบ zero‑copy Mount อัตโนมัติโดย MicroPython เมื่อเริ่มต้น ก่อนที่ Python ของผู้ใช้จะทำงาน
หลังจาก mount แล้ว working directory จะถูกตั้งเป็น /sdcard เมื่อมีการ์ดอยู่ มิฉะนั้น /flash จากนั้น interpreter จะรันสคริปต์จากไดเรกทอรีนั้น:
boot.pyถูกรันบน ทุก การ soft resetmain.pyถูกรันเฉพาะ เมื่อบูตเย็น เท่านั้น ทันทีหลังจากboot.py
การวาง boot.py หรือ main.py ลงบนการ์ด SD จะแทนที่ไฟล์ที่อยู่ใน flash โดยไม่แตะต้องมัน
เมื่อเชื่อมต่อผ่าน USB ระบบไฟล์บูต (/sdcard หากมีการ์ดอยู่ มิฉะนั้น /flash) จะแสดงเป็น USB mass‑storage drive บนโฮสต์ด้วย Eject drive ก่อนรีเซ็ตกล้อง เพื่อให้โฮสต์ flush การเขียนที่แคชไว้
Note
ไฟล์ที่สร้างหรือแก้ไขโดยโค้ดที่รันบน OpenMV Cam จะไม่แสดงบนโฮสต์จนกว่า drive จะถูก mount ใหม่ ใช้การ์ด SD สำหรับข้อมูลใด ๆ ที่สคริปต์เขียนกลับ และ mount ใหม่ก่อนอ่านไฟล์เหล่านั้นจากโฮสต์
ขนาดพื้นที่เก็บข้อมูล#
Pure Thermal จัดส่งพร้อม:
/flash— ระบบไฟล์ FAT 24 MB อ่าน/เขียน/rom— ROMFS แบบ memory‑mapped อ่านอย่างเดียว 8 MB ใช้สำหรับส่งมอบสคริปต์และโมเดล ML ที่ได้ประโยชน์จากการเข้าถึง mmap แบบ zero‑copy/sdcard— ขนาดเต็มของการ์ด microSD ที่ใส่อยู่ (เมื่อมีอยู่) อ่าน/เขียน
ตัวบ่งชี้ hard‑fault#
หาก LED RGB ของผู้ใช้วนรอบสีต่าง ๆ อย่างรวดเร็ว — เร็วพอที่จะดูเหมือน LED ขาวระยิบระยับ มากกว่าสีที่แตกต่างกัน — เฟิร์มแวร์ได้เกิด hard fault ที่กู้คืนไม่ได้ ให้ reflash เฟิร์มแวร์เพื่อกู้คืน
ข้อผิดพลาดของฮาร์ดแวร์#
ข้อบกพร่องระดับบอร์ดบางประการมีการบันทึกไว้ใน ข้อผิดพลาดฮาร์ดแวร์ Pure Thermal รายการสำคัญที่ควรทราบ:
การรบกวนจากขั้วต่อแบตเตอรี่ — ชิ้นส่วนบน PCB อยู่ใต้ขั้วต่อแบตเตอรี่ LiPo โดยตรง และลิ่มที่ยื่นออกมาบนปลั๊กสายแบตเตอรี่อาจเกี่ยวชิ้นส่วนเหล่านั้นเมื่อถอดสายออก บางครั้งดึงชิ้นส่วนออกจากบอร์ด ตัดลิ่มออกจากปลั๊กสายด้วยคีมตัดแบน flush cutters ก่อนใช้งานครั้งแรก
RTC หยุดทำงานขณะบอร์ดปิด — ค่า load capacitance บน crystal 32 kHz (Y2) สูงเกินไป การถอด C96 และ C97 (คู่ที่อยู่ข้าง crystal ถัดจาก STM32) ช่วยให้ RTC ทำงานต่อด้วยไฟสำรอง บอร์ดส่วนใหญ่จัดส่งโดยถอด cap เหล่านี้ออกแล้ว หาก RTC ของคุณสูญเสียเวลาเมื่อถอดปลั๊ก ให้ตรวจสอบตำแหน่งเหล่านั้น ดู GitHub issues #1536 และ #1600 สำหรับเธรดเต็ม
LED ตัวบ่งชี้การชาร์จค้างสีน้ำเงิน — ตัวชาร์จอาจสิ้นสุดรอบการชาร์จที่แรงดันระหว่าง 4.15 V ถึง 4.19 V โดยไม่สลับตัวบ่งชี้จากสีน้ำเงิน (กำลังชาร์จ) เป็นสีเขียว (ชาร์จเสร็จ) แบตเตอรี่ยังคงชาร์จเต็มในกรณีนี้ เชื่อการวัดแรงดัน ไม่ใช่ LED
Silkscreen ระบุ VIN ผิดเป็น VBAT — แพดในตำแหน่ง VIN ของ header OpenMV มาตรฐานถูกพิมพ์บนบอร์ดว่า
VBATบน Pure Thermal ป้ายกำกับผิด แต่ไม่มีผลในทางปฏิบัติเพราะแพดนี้ ไม่มีการเชื่อมต่อทางไฟฟ้า ไม่ว่าทิศทางใด
ไลบรารีซอฟต์แวร์#
ดู ดัชนีไลบรารี สำหรับรายการโมดูลทั้งหมด รวมถึงโมดูลที่มีเฉพาะใน Pure Thermal build