光影追踪·智能控制”——基于CanMV-K230的视觉引导激光舵机系统全栈开发实战
·
目录
一、引言:当激光笔遇上视觉识别
在2023年全国大学生电子设计竞赛中,视觉识别+执行机构类题目频繁出现:从“电磁炮打靶”到“智能搬运车”,无一不要求“看得准、打得稳、控得精”。传统方案往往采用“PC+OpenCV+下位机”的分布式架构,成本高、延迟大、部署难。
本文提出一种“All-in-One”解决方案:
以立创·庐山派K230-CanMV开发板为核心,在端侧完成图像采集→视觉识别→激光指示→舵机闭环控制的全链路闭环
立创·庐山派K230-CanMV开发板原理图如下:




更多原理图信息三连评论区回复“原理图”即可,私信发
仅用一块板子、一根USB线、一颗舵机、一支激光笔,即可实现“看到目标→激光瞄准→舵机跟随”的完整演示。
二、系统总体设计
| 模块 | 功能 | 资源占用 |
| Camera | 640×640@30fps RGB 采集 | K230 ISP + DVP |
| Vision | 色块/矩形/线段识别 | K230 NPU + OpenCV |
| Laser | 3.3V 激光笔开关 | GPIO33 |
| Servo | 9g舵机 0°–180° | PWM2(GPIO46) |
| UI | 实时画面+FPS叠加 | LT9611 800×480 |
| Power | 5V 2A Type-C 供电 | 板载MT9700 |
三、硬件连接一览
| 外设 | 引脚 | 原理图索引 |
| 激光笔正极 | 3V3 | P1-01 |
| 激光笔负极 | GPIO33 | P1-33 |
| 舵机信号线 | GPIO46(PWM2) | P1-46 |
| 舵机VCC | 5V | P1-02 |
| 舵机GND | GND | P1-06 |
注:舵机务必使用板载5V供电,GPIO仅提供信号,防止电流倒灌。
四、软件架构
4.1 技术栈
-
操作系统:RT-Smart(K230大核)
-
视觉库:CanMV Media Framework(Python3)
-
控制库:machine.PWM + machine.Pin
-
调试界面:IDE实时回传
4.2 任务流

五、核心代码解析
5.1 初始化:让硬件“醒”过来
from media.sensor import *
from media.display import *
from media.media import *
from machine import FPIOA, Pin, PWM
import time, os
# 1. 重映射引脚
fpioa = FPIOA()
fpioa.set_function(33, FPIOA.GPIO33) # 激光
fpioa.set_function(46, FPIOA.PWM2) # 舵机
# 2. 激光笔初始化
laser = Pin(33, Pin.OUT, value=0)
# 3. 舵机PWM初始化:50Hz,周期20ms
servo = PWM(2, freq=50, duty=0)
servo.enable(True)
# 4. 摄像头
sensor = Sensor(width=640, height=640)
sensor.reset()
sensor.set_pixformat(Sensor.RGB565)
sensor.set_framesize(width=640, height=640)
# 5. 显示
Display.init(Display.LT9611, to_ide=True)
MediaManager.init()
sensor. Run()
5.2 目标识别:色块+矩形双保险
def find_max_blob(img):
blobs = img.find_blobs([(41, 57, 31, 83, 13, 71)], # 红色阈值
pixels_threshold=5000,
area_threshold=5000,
margin=True)
if not blobs:
return None
max_blob = max(blobs, key=lambda b: b.pixels())
return max_blob
5.3 坐标映射:把像素“翻译”成角度
def map_coord_to_angle(x, img_w=640):
"""
将x坐标线性映射到0-180°
"""
return int((x / img_w) * 180)
5.4 主循环:20行代码完成闭环
clock = time.clock()
while True:
clock.tick()
os.exitpoint()
img = sensor.snapshot()
blob = find_max_blob(img)
if blob:
cx = blob.cx()
angle = map_coord_to_angle(cx)
duty = 0.5 + angle / 180 * 2 # 0.5ms~2.5ms
servo.duty(duty / 20 * 100)
laser.value(1) # 点亮激光
img.draw_rectangle(blob.rect(), color=(0, 255, 0), thickness=4)
img.draw_cross(cx, blob.cy(), color=(255, 0, 0), size=10)
else:
laser.value(0)
img.draw_string(10, 10, f"FPS:{clock.fps():.1f}", scale=2)
Display.show_image(img)
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)