问题描述
使用相机id=0和id=2启动相机启动不了,提示RuntimeError: sensor(0) run error, vicap init failed(-1),但使用id=2的可以,程序运行时若相机正常可看到如下情况,非正常情况为以下这样
,相机id修改的核心代码为
固件用的是链接里的固件[烧录固件]
from machine import UART, Pin, FPIOA, ADC, WDT, RTC, Timer, TOUCH, PWM
from libs.YOLO import YOLO11,YOLOv5
from libs.Utils import *
#from sdcard.Utils import *
import ulab.numpy as np
import time, os, urandom, sys,gc, utime,uos
from media.sensor import *
from media.display import *
from media.media import *
import image
import io
import json # 如果数据是JSON格式
import math
import random
#from mpp import pm
#pm.cpu.set_profile(3)
class Servent:
def __init__(self):
# 初始化系统设置
self._init_system()
# 初始化硬件引脚
self._init_pins()
# 初始化显示相关设置
self._init_display()
# 相机初始化
self._init_camera()
# 初始化参数设置
self._init_parameters()
def _init_system(self):
"""初始化系统设置"""
os.exitpoint(os.EXITPOINT_ENABLE) # 启用退出点
def _init_pins(self):
"""初始化FPIOA和GPIO引脚"""
# 创建FPIOA对象并为引脚功能分配
fpioa = FPIOA()
# 引脚配置
fpioa.set_function(62, FPIOA.GPIO62) # 红灯
fpioa.set_function(20, FPIOA.GPIO20) # 绿灯
fpioa.set_function(63, FPIOA.GPIO63) # 蓝灯
fpioa.set_function(19, FPIOA.GPIO19) # 拍照按键
fpioa.set_function(18, FPIOA.GPIO18) # 灯
fpioa.set_function(43, FPIOA.PWM1) # 配置蜂鸣器IO口功能
# 串口和485通信接口
fpioa.set_function(40, FPIOA.UART1_TXD)
fpioa.set_function(41, FPIOA.UART1_RXD)
fpioa.set_function(47, FPIOA.GPIO47) # DE 发送模式 高电平有效 RE 接收模式 低电平有效
# 单片机串口
fpioa.set_function(48, FPIOA.UART4_TXD)
fpioa.set_function(49, FPIOA.UART4_RXD)
# GH1.25串口2
fpioa.set_function(11, FPIOA.UART2_TXD)
fpioa.set_function(12, FPIOA.UART2_RXD)
# 初始化LED (共阳:高电平熄灭,低电平亮)
self.LED_R = Pin(62, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 红灯
self.LED_G = Pin(20, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 绿灯
self.LED_B = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 蓝灯
self.button_photo = Pin(19, Pin.IN, pull=Pin.PULL_DOWN, drive=7) # 拍照按键
self.button = Pin(53, Pin.IN, Pin.PULL_DOWN)
self.LED = Pin(18, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 灯
self.DHRL = Pin(47, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
# 默认熄灭所有LED
self.LED_R.high()
self.LED_G.high()
self.LED_B.high()
def _init_display(self):
"""初始化显示相关设置"""
# 3.1寸屏幕模式
self.DISPLAY_WIDTH = 800
self.DISPLAY_HEIGHT = 480
# 创建用于绘图的图像对象
self.img_show = image.Image(self.DISPLAY_WIDTH, self.DISPLAY_HEIGHT, image.RGB565)
# 定义画布中的按钮区域
# ====================== 新 ================================
self.test_button_area = (250, 150, 250, 130) # 拍照按钮区域
# 初始化显示
Display.init(Display.ST7701, width=self.DISPLAY_WIDTH, height=self.DISPLAY_HEIGHT, to_ide=False)
self.deinit_flag = 1
def _create_directories(self):
"""创建必要的目录"""
status_folder = "/sdcard/status"
arg_folder = "/sdcard/arg"
self.image_folder = "/data/images"
for folder in [status_folder, arg_folder, self.image_folder]:
try:
os.stat(folder)
except OSError:
os.mkdir(folder)
def _init_parameters(self):
"""初始化参数设置"""
self.last_displayed_percent = -1
self.power_value = None
# 模型加载
self.kmodel_path="/sdcard/best.kmodel"
self.labels = ["甲虫","粉螟"]
self.model_input_size=[1280,736]
self.confidence_threshold = 0.4
self.nms_threshold=0.45
self.colors=get_colors(len(self.labels))
# 待机状态参数
self.is_stand = 0
# 虫情数量初始化
self.insect_jia = 0
self.insect_fenming = 0
# 自动拍照相关参数
self.start_photo_auto = 0
self.auto_time_flag = 1
# 加载自动定时时间
try:
with open("/sdcard/arg/auto_time.txt", 'r') as f:
self.auto_time = int(f.read())
except:
# self.auto_time = 86400000 # 默认一天
self.auto_time = 10 * 1000
# 设置自动拍照启动标志
self.start_photo_auto = 1 if self.auto_time else 0
with open("/sdcard/arg/start_photo_auto.txt", 'w') as f:
f.write(str(self.start_photo_auto))
def _init_camera(self):
"""初始化相机"""
self.fps = time.clock()
sensor_id = 1
self.sensor = Sensor(id=sensor_id, fps=60)
self.sensor.reset()
# 拍照用通道
self.sensor.set_framesize(framesize=self.sensor.FHD, chn=1)
self.sensor.set_pixformat(Sensor.RGB565, chn=1)
# LCD屏幕显示画面
self.sensor.set_framesize(width=800, height=480, chn=CAM_CHN_ID_0)
self.sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)
# self.sensor.set_framesize(width=800, height=480, chn=2)
# 初始化媒体管理器
MediaManager.init()
self.sensor.run()
# =================================================================
def lckfb_save_jpg(self, img, filename, quality=95):
"""
将图像压缩成JPEG后写入文件 (不依赖第一段 save_jpg/MediaManager.convert_to_jpeg 的写法)
:param img: 传入的图像对象 (Sensor.snapshot() 得到)
:param filename: 保存的目标文件名 (含路径)
:param quality: 压缩质量 (1-100)
"""
# 将图像压缩为 JPEG 格式数据
# quality=95 表示压缩质量越高,图片越清晰,文件体积越大,这个也会导致明明都是800*480分辨率的图片,有的图片大,有的图片小。
compressed_data = img.compress(quality=quality)
with open(filename, "wb") as f:
f.write(compressed_data)
def auto_photo(self):
self.all_image_count_and_reset("/data/images/")
self.auto_old_ms = utime.ticks_ms()
self.LED.high()
self.yolo_auto=YOLO11(task_type="detect",mode="image",kmodel_path=self.kmodel_path,labels=self.labels,rgb888p_size=[1920,1080],model_input_size=self.model_input_size,conf_thresh=self.confidence_threshold,nms_thresh=self.nms_threshold,max_boxes_num=50,debug_mode=0)
self.yolo_auto.config_preprocess()
s_date = "日期: " + str(2025) + "年 " + str(8) + "月 " + str(18) + "日 " + str(16) + ":" + str(0)
# self.tim.init(period=self.auto_time, mode=Timer.PERIODIC, callback=self.auto_photo)
with open("/sdcard/arg/real_auto_time.txt",'w') as f:
f.write(str(self.auto_time))
self.auto_time_flag = "0"
with open("/sdcard/arg/auto_time_flag.txt",'w') as f:
f.write(self.auto_time_flag)
try:
with open("/sdcard/arg/image_count_auto.txt",'r') as f:
image_count_auto = f.read()
self.image_count_auto = int(image_count_auto)
except:
pass
print("相机启动")
# 启动传感器
self.sensor.run()
# global image_count_all
# 丢掉前面100帧数据,防止摄像头还不稳定
for i in range(100):
self.sensor.snapshot()
#抓取通道0的图像
# img_show = self.sensor.snapshot(chn=2)
# self.insect_jia = self.reconize_jia(img_show)
# self.insect_fenming = self.reconize_fenming(img_show)
img_photo_auto = self.sensor.snapshot(chn=1)
img_rgb888=img_photo_auto.to_rgb888()
img_hwc=img_rgb888.to_numpy_ref()
shape=img_hwc.shape
img_tmp = img_hwc.reshape((shape[0] * shape[1], shape[2]))
img_tmp_trans = img_tmp.transpose()
img_res=img_tmp_trans.copy()
img = img_res.reshape((shape[2],shape[0],shape[1]))
res=self.yolo_auto.run(img)
self.insect_jia = res[1].count(0)
self.insect_fenming = res[1].count(1)
img_photo_auto.draw_string_advanced(2, 1080-35, 32, s_date, color=(0, 255, 0))
img_photo_auto.draw_string_advanced(2, 0, 32, "甲虫:"+str(self.insect_jia), color=(0, 255, 0))
img_photo_auto.draw_string_advanced(2, 35, 32, "粉螟:"+str(self.insect_fenming), color=(0, 255, 0))
# 拍照并保存
self.image_count_auto += 1
# filename = f"{self.image_folder}/auto_{self.image_count_auto:05d}_{img_photo_auto.width()}x{img_photo_auto.height()}.jpg"
# print(filename)
# print("当前文件总数: "+str(image_count_all))
# 直接调用自定义的 lckfb_save_jpg() 函数
# self.lckfb_save_jpg(img_photo_auto, filename, quality=95)
with open("/sdcard/arg/insect_jia.txt",'w') as f:
f.write(str(self.insect_jia))
with open("/sdcard/arg/insect_fenming.txt",'w') as f:
f.write(str(self.insect_fenming))
with open("/sdcard/arg/image_count_auto.txt",'w') as f:
f.write(str(self.image_count_auto))
self.LED.low()
# self.yolo.deinit()
def all_image_count_and_reset(self,directory):
image_count_all = 0
# image_count_all = int(self.image_count_unauto) + int(self.image_count_auto)
for f in os.listdir(directory):
full_path = directory + f
if os.stat(full_path)[0] == 33206: # 检查是否是文件
image_count_all += 1
if image_count_all >= 100:
self.image_count_unauto = "0"
self.image_count_auto = "0"
with open("/sdcard/arg/image_count_unauto.txt",'w') as f:
f.write(self.image_count_unauto)
with open("/sdcard/arg/image_count_auto.txt",'w') as f:
f.write(self.image_count_auto)
# print("总照片数: " + str(image_count_all))
# ======================================================================================
def run(self):
try:
i = 0
p_flag = 1
if self.start_photo_auto:
self.auto_old_ms = utime.ticks_ms()
while(True):
if self.start_photo_auto:
self.auto_new_ms = utime.ticks_ms()
with open("/sdcard/arg/auto_new_ms.txt",'w') as f:
f.write(str(self.auto_new_ms))
if p_flag:
if self.start_photo_auto:
self.auto_photo()
p_flag = 0
time.sleep(1) # 暂停1秒
# os.exitpoint() # 可用的退出点
except KeyboardInterrupt as e:
print("用户终止:", e) # 捕获键盘中断异常
except BaseException as e:
print(f"异常:{e}") # 捕获其他异常
finally:
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP) # 启用睡眠模式的退出点
time.sleep_ms(100) # 延迟100毫秒
MediaManager.deinit()
gc.collect()
servent = Servent()
servent.run()
## 复现步骤
----------
将相机接在CSI_1的位置,启动程序即可
## 硬件板卡
----------
庐山派
## 软件版本
----------
CanMV v1.3-48-g1e83acc(based on Micropython e00a144) on 2025-07-15; k230_canmv_lckfb with K230
## 其他信息
----------
[烧录固件](https://kvftsfijpo.feishu.cn/file/PCo8botGaoAw5txlSancgLLOnRc?from=from_copylink)