IDE仿真可以,存到SD卡后运行一直不正常

Viewed 40

问题描述


切换摄像头,读取第一张图片,TCP服务器模式发送给PC客户端,IDE仿真可以正常发送切换后的新摄像头号第一张,存到SD卡后运行一直不正常。
板子庐山派,IDE4.09。4.08,烧录了几种固件都不行,试了多读几次摄像头也不行,只能断网再连接才行。不知道那个缓存在哪清除。如有必要可发代码给检查。

复现步骤


接三个摄像头,切换摄像头,读取第一张图片,TCP服务器模式发送给PC客户端,IDE仿真可以正常发送切换后的新摄像头第一张图片,程序存到SD卡后运行第一张图片一直不正常,第二张才正常。怎么刷新摄像头第一张就是旧的摄像头的。
板子庐山派,IDE4.09。4.08,烧录了几种固件都不行,试了多读几次摄像头也不行,只能断网再连接才行。不知道那个缓存在哪清除。如有必要可发代码给检查。

硬件板卡


庐山派 IDE 4.08,.09

软件版本


固件显示版本L0.40,其他IMG测试了几个都一样

4 Answers

你好,请发一下固件名称,代码。

附件怎么上传到这里。直接粘贴不了

import network
import socket
import time
import os
import select
# K230官方摄像头模块
from media.sensor import *
from media.display import *
from media.media import *

# 服务器配置
TCP_PORT_IMAGE = 2001  # 图像发送端口
TCP_PORT_CTRL = 2002   # 控制端口
STATIC_IP_CONFIG = ('192.168.1.201', '255.255.255.0', '192.168.1.1', '8.8.8.8')

# 摄像头配置(严格遵循官方规范)
BASE_WIDTH = 1920      # 基础分辨率(官方要求)
BASE_HEIGHT = 1080
OUT_WIDTH = 1024      # 输出分辨率(你需要的640×480)
OUT_HEIGHT = 768
JPG_QUALITY = 80
FPS = 30

# 全局Sensor实例(三路同时初始化)
sensor0 = None  # CSI0 (id=0)
sensor1 = None  # CSI1 (id=1)
sensor2 = None  # CSI2 (id=2)

# 全局控制标记
CSI2_ALLOW_SEND = False
CSI2_SEND_ONE_FRAME = False
CSI0_ALLOW_SEND = False
CSI0_SEND_ONE_FRAME = False
CSI1_ALLOW_SEND = False
CSI1_SEND_ONE_FRAME = False

# 全局套接字集合
server_socks = {}
client_socks = {}
# 帧计数(按通道统计)
frame_count = {
    "CSI0": 0,
    "CSI1": 0,
    "CSI2": 0
}

# ===================== 初始化三路摄像头(严格遵循官方规范) =====================
def init_all_cameras():
    """
    按官方范例初始化三路摄像头
    - 基础分辨率:1920×1080
    - 输出分辨率:640×480
    - 三路Sensor同时初始化,绑定不同显示层
    """
    global sensor0, sensor1, sensor2  # 声明使用全局变量
    print("\n" + "="*50)
    print("初始化三路摄像头(遵循官方规范)")
    print("="*50)

    try:
        # ------------------- CSI0 (id=0) -------------------
        sensor0 = Sensor(id=0, width=BASE_WIDTH, height=BASE_HEIGHT, fps=FPS)
        sensor0.reset()
        # 设置输出分辨率(640×480)
        sensor0.set_framesize(width=OUT_WIDTH, height=OUT_HEIGHT, chn=0)
        sensor0.set_pixformat(Sensor.YUV420SP, chn=0)
        sensor0.set_hmirror(True)
        sensor0.set_vflip(True)
        # 绑定到VIDEO1层
        bind_info0 = sensor0.bind_info(x=0, y=0)
        Display.bind_layer(**bind_info0, layer=Display.LAYER_VIDEO1)

        # ------------------- CSI1 (id=1) -------------------
        sensor1 = Sensor(id=1, width=BASE_WIDTH, height=BASE_HEIGHT, fps=FPS)
        sensor1.reset()
        sensor1.set_framesize(width=OUT_WIDTH, height=OUT_HEIGHT, chn=0)
        sensor1.set_pixformat(Sensor.YUV420SP, chn=0)
        sensor1.set_hmirror(True)
        sensor1.set_vflip(True)
        # 绑定到VIDEO2层
        bind_info1 = sensor1.bind_info(x=OUT_WIDTH, y=0)
        Display.bind_layer(**bind_info1, layer=Display.LAYER_VIDEO2)

        # ------------------- CSI2 (id=2) -------------------
        sensor2 = Sensor(id=2, width=BASE_WIDTH, height=BASE_HEIGHT, fps=FPS)
        sensor2.reset()
        sensor2.set_framesize(width=OUT_WIDTH, height=OUT_HEIGHT, chn=0)
        sensor2.set_pixformat(Sensor.YUV420SP, chn=0)
        sensor2.set_hmirror(True)
        sensor2.set_vflip(True)

        # 初始化显示(仅调用一次)
        Display.init(Display.LT9611, to_ide=True)
        # 初始化媒体管理器(仅调用一次)
        MediaManager.init()

        # 多路Sensor仅需调用一次run()
        sensor0.run()

        time.sleep_ms(500)
        print(f"✅ 三路摄像头初始化成功!")
        print(f"   基础分辨率: {BASE_WIDTH}x{BASE_HEIGHT} | 输出分辨率: {OUT_WIDTH}x{OUT_HEIGHT}")
        print(f"   CSI0(id=0)→VIDEO1 | CSI1(id=1)→VIDEO2 | CSI2(id=2)→自定义显示")
        return True
    except BaseException as e:
        print(f"❌ 摄像头初始化失败: {e}")
        return False

# ===================== 创建非阻塞服务器套接字 =====================
def create_tcp_server(ip, port, sock_type):
    print(f"\n" + "="*50)
    print(f"创建{ sock_type } TCP服务器(端口{port})")
    print("="*50)

    server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_sock.bind(('0.0.0.0', port))
    server_sock.listen(10)
    server_sock.setblocking(False)
    server_socks[server_sock] = (port, sock_type)

    print(f"✅ {sock_type}服务器启动成功!")
    print(f"   监听端口: {port}")
    print(f"   访问地址: {ip}:{port}")
    print(f"   运行模式: 非阻塞(select多路复用)")
    return server_sock

# ===================== 处理2002控制端口指令 =====================
def handle_ctrl_data(client_sock, client_addr):
    """处理2002端口指令,三路摄像头独立控制"""
    # 声明所有使用的全局变量(关键修复点)
    global CSI2_ALLOW_SEND, CSI2_SEND_ONE_FRAME
    global CSI0_ALLOW_SEND, CSI0_SEND_ONE_FRAME
    global CSI1_ALLOW_SEND, CSI1_SEND_ONE_FRAME

    try:
        recv_data = client_sock.recv(1024)
        if not recv_data:
            print(f"\n🔌 2002控制客户端{client_addr}主动断开")
            del client_socks[client_sock]
            client_sock.close()
            return

        # 打印接收的原始数据
        hex_data = [hex(b) for b in recv_data]
        print(f"\n📥 从2002客户端{client_addr}收到数据:")
        print(f"   原始字节: {recv_data} | 16进制: {hex_data}")

        reply = b""
        # ------------------- CSI2指令(0XA0/0XA1/0XB0) -------------------
        if 0xA0 in recv_data:
            # 关闭其他两路,仅开启CSI2
            CSI0_ALLOW_SEND = False
            CSI0_SEND_ONE_FRAME = False
            CSI1_ALLOW_SEND = False
            CSI1_SEND_ONE_FRAME = False
            # 开启CSI2持续发送
            CSI2_ALLOW_SEND = True
            CSI2_SEND_ONE_FRAME = False
            print(f"✅ 检测到0XA0(仅CSI2持续发送)")
            reply = b"OK: 0XA0 received, ONLY CSI2 continuous stream STARTED\r\n"

        elif 0xA1 in recv_data:
            # 关闭其他两路,仅开启CSI2单帧
            CSI0_ALLOW_SEND = False
            CSI0_SEND_ONE_FRAME = False
            CSI1_ALLOW_SEND = False
            CSI1_SEND_ONE_FRAME = False
            # 开启CSI2单帧发送
            CSI2_SEND_ONE_FRAME = True
            CSI2_ALLOW_SEND = False
            print(f"✅ 检测到0XA1(仅CSI2单帧发送)")
            reply = b"OK: 0XA1 received, ONLY CSI2 send ONE frame then stop\r\n"

        elif 0xB0 in recv_data:
            # 停止CSI2
            CSI2_ALLOW_SEND = False
            CSI2_SEND_ONE_FRAME = False
            print(f"✅ 检测到0XB0(CSI2停止发送)")
            reply = b"OK: 0XB0 received, CSI2 stream STOPPED\r\n"

        # ------------------- CSI0指令(0X60/0X61/0X70) -------------------
        elif 0x60 in recv_data:
            # 关闭其他两路,仅开启CSI0
            CSI1_ALLOW_SEND = False
            CSI1_SEND_ONE_FRAME = False
            CSI2_ALLOW_SEND = False
            CSI2_SEND_ONE_FRAME = False
            # 开启CSI0持续发送
            CSI0_ALLOW_SEND = True
            CSI0_SEND_ONE_FRAME = False
            print(f"✅ 检测到0X60(仅CSI0持续发送)")
            reply = b"OK: 0X60 received, ONLY CSI0 continuous stream STARTED\r\n"

        elif 0x61 in recv_data:
            # 关闭其他两路,仅开启CSI0单帧
            CSI1_ALLOW_SEND = False
            CSI1_SEND_ONE_FRAME = False
            CSI2_ALLOW_SEND = False
            CSI2_SEND_ONE_FRAME = False
            # 开启CSI0单帧发送
            CSI0_SEND_ONE_FRAME = True
            CSI0_ALLOW_SEND = False
            print(f"✅ 检测到0X61(仅CSI0单帧发送)")
            reply = b"OK: 0X61 received, ONLY CSI0 send ONE frame then stop\r\n"

        elif 0x70 in recv_data:
            # 停止CSI0
            CSI0_ALLOW_SEND = False
            CSI0_SEND_ONE_FRAME = False
            print(f"✅ 检测到0X70(CSI0停止发送)")
            reply = b"OK: 0X70 received, CSI0 stream STOPPED\r\n"

        # ------------------- CSI1指令(0X80/0X81/0X90) -------------------
        elif 0x80 in recv_data:
            # 关闭其他两路,仅开启CSI1
            CSI0_ALLOW_SEND = False
            CSI0_SEND_ONE_FRAME = False
            CSI2_ALLOW_SEND = False
            CSI2_SEND_ONE_FRAME = False
            # 开启CSI1持续发送
            CSI1_ALLOW_SEND = True
            CSI1_SEND_ONE_FRAME = False
            print(f"✅ 检测到0X80(仅CSI1持续发送)")
            reply = b"OK: 0X80 received, ONLY CSI1 continuous stream STARTED\r\n"

        elif 0x81 in recv_data:
            # 关闭其他两路,仅开启CSI1单帧
            CSI0_ALLOW_SEND = False
            CSI0_SEND_ONE_FRAME = False
            CSI2_ALLOW_SEND = False
            CSI2_SEND_ONE_FRAME = False
            # 开启CSI1单帧发送
            CSI1_SEND_ONE_FRAME = True
            CSI1_ALLOW_SEND = False
            print(f"✅ 检测到0X81(仅CSI1单帧发送)")
            reply = b"OK: 0X81 received, ONLY CSI1 send ONE frame then stop\r\n"

        elif 0x90 in recv_data:
            # 停止CSI1
            CSI1_ALLOW_SEND = False
            CSI1_SEND_ONE_FRAME = False
            print(f"✅ 检测到0X90(CSI1停止发送)")
            reply = b"OK: 0X90 received, CSI1 stream STOPPED\r\n"

        # 未知指令
        else:
            print(f"⚠️  未检测到有效指令!支持的指令:")
            print(f"   CSI2: 0XA0(持续) 0XA1(单帧) 0XB0(停止)")
            print(f"   CSI0: 0X60(持续) 0X61(单帧) 0X70(停止)")
            print(f"   CSI1: 0X80(持续) 0X81(单帧) 0X90(停止)")
            reply = b"ERROR: Invalid command! Check supported commands\r\n"

        client_sock.sendall(reply)
        print(f"📤 向2002客户端{client_addr}回复: {reply.decode().strip()}")

    except Exception as e:
        print(f"\n❌ 2002客户端{client_addr}通讯异常: {type(e).__name__}: {e}")
        del client_socks[client_sock]
        client_sock.close()

# ===================== 处理2001图像端口数据 =====================
def handle_image_data(client_sock, client_addr):
    try:
        recv_data = client_sock.recv(1024)
        if not recv_data:
            print(f"\n🔌 2001图像客户端{client_addr}主动断开")
            del client_socks[client_sock]
            client_sock.close()
            return

        data_str = recv_data.decode('utf-8', 'ignore').strip()
        print(f"\n📥 从2001客户端{client_addr}收到数据: {data_str}")
        client_sock.sendall(recv_data)
        print(f"📤 向2001客户端{client_addr}回显数据: {data_str}")

        if "exit" in data_str:
            print(f"🔌 2001客户端{client_addr}发送exit,断开连接")
            del client_socks[client_sock]
            client_sock.close()

    except Exception as e:
        print(f"\n❌ 2001客户端{client_addr}通讯异常: {type(e).__name__}: {e}")
        del client_socks[client_sock]
        client_sock.close()

# ===================== 发送指定CSI端口的图像 =====================
def send_csi_frame(client_sock, client_addr, csi_id, sensor_inst, csi_name):
    """发送指定CSI端口的图像(640×480)"""
    # 声明所有使用的全局变量(关键修复点)
    global frame_count
    global CSI2_ALLOW_SEND, CSI2_SEND_ONE_FRAME
    global CSI0_ALLOW_SEND, CSI0_SEND_ONE_FRAME
    global CSI1_ALLOW_SEND, CSI1_SEND_ONE_FRAME

    allow_send = False
    send_one_frame = False

    # 获取对应端口的控制标记
    if csi_id == 0:
        allow_send = CSI0_ALLOW_SEND
        send_one_frame = CSI0_SEND_ONE_FRAME
    elif csi_id == 1:
        allow_send = CSI1_ALLOW_SEND
        send_one_frame = CSI1_SEND_ONE_FRAME
    elif csi_id == 2:
        allow_send = CSI2_ALLOW_SEND
        send_one_frame = CSI2_SEND_ONE_FRAME

    # 无发送指令时返回
    if not allow_send and not send_one_frame:
        return

    try:
        # 采集当前Sensor的图像(chn=0)
        #sensor_inst.flush(chn=0)  # 刷新缓存,读取最新帧
        #sensor_inst.snapshot(chn=0)  # 丢弃缓存帧
        img = sensor_inst.snapshot(chn=0)  # 读取最新帧
        #time.sleep(0.5)
        img = sensor_inst.snapshot(chn=0)
        if not img:
            print(f"❌ {csi_name}图像采集失败")
            return

        # 编码为640×480 JPG
        jpg_data = img.to_jpeg(quality=JPG_QUALITY)
        data_len = len(jpg_data)

        # 构造发送数据(通道标识 + 长度 + 图像数据)
        channel_flag = bytes([csi_id])
        len_bytes = data_len.to_bytes(4, 'big')
        send_data = channel_flag + len_bytes + jpg_data

        # 发送数据
        client_sock.sendall(send_data)

        # 更新帧计数
        frame_count[csi_name] += 1
        print(f"\n📸 向2001客户端{client_addr}发送{csi_name}图像:")
        print(f"   帧数: {frame_count[csi_name]} | 大小: {data_len} 字节")
        print(f"   通道标识: 0x{channel_flag.hex()} | 分辨率: {OUT_WIDTH}x{OUT_HEIGHT}")

        # 单帧模式:发送后重置标记
        if send_one_frame:
            if csi_id == 0:
                CSI0_SEND_ONE_FRAME = False
            elif csi_id == 1:
                CSI1_SEND_ONE_FRAME = False
            elif csi_id == 2:
                CSI2_SEND_ONE_FRAME = False
            print(f"✅ {csi_name}单帧发送完成!已自动停止")

    except Exception as e:
        if "BrokenPipeError" not in str(type(e).__name__):
            print(f"\n❌ {csi_name}图像发送失败: {type(e).__name__}: {e}")

# ===================== 发送激活通道的图像 =====================
def send_active_frames(client_sock, client_addr):
    """发送当前激活的摄像头图像"""
    # 声明使用全局变量(关键修复点)
    global sensor0, sensor1, sensor2

    # CSI0 (id=0)
    if sensor0 is not None:
        send_csi_frame(client_sock, client_addr, 0, sensor0, "CSI0")
    # CSI1 (id=1)
    if sensor1 is not None:
        send_csi_frame(client_sock, client_addr, 1, sensor1, "CSI1")
    # CSI2 (id=2)
    if sensor2 is not None:
        send_csi_frame(client_sock, client_addr, 2, sensor2, "CSI2")

# ===================== LAN网络初始化 =====================
def init_lan_network():
    print("="*50)
    print("初始化LAN网络(基于官方范例)")
    print("="*50)

    a = network.LAN()
    print(f"1. LAN接口激活状态: {a.active()}")
    init_ifconfig = a.ifconfig()
    print(f"2. 初始IP配置: {init_ifconfig}")

    try:
        a.ifconfig(STATIC_IP_CONFIG)
        print(f"3. 设置静态IP: {STATIC_IP_CONFIG}")
    except Exception as e:
        print(f"3. 静态IP配置失败(固件特性): {e}")

    static_ifconfig = a.ifconfig()
    print(f"4. 静态IP配置后: {static_ifconfig}")

    try:
        a.ifconfig("dhcp")
        print(f"5. 切换为DHCP模式")
    except Exception as e:
        print(f"5. DHCP配置失败: {e}")

    dhcp_ifconfig = a.ifconfig()
    print(f"6. DHCP配置后IP: {dhcp_ifconfig}")

    mac_addr = a.config("mac")
    print(f"7. LAN接口MAC地址: {mac_addr}")

    a.ifconfig("dhcp")
    final_ifconfig = a.ifconfig()
    print(f"8. 最终DHCP IP配置: {final_ifconfig}")

    if final_ifconfig[0] != '0.0.0.0':
        ip = final_ifconfig[0]
    else:
        ip = STATIC_IP_CONFIG[0]

    print(f"\n✅ 最终使用IP: {ip}")
    return a, ip

# ===================== 主函数 =====================
def main():
    # 声明使用全局变量(关键修复点)
    global server_socks, client_socks, frame_count

    try:
        # 1. 初始化三路摄像头(官方规范)
        cam_ok = init_all_cameras()
        if not cam_ok:
            print("❌ 摄像头初始化失败,程序退出")
            return

        # 2. 初始化网络
        lan_dev, lan_ip = init_lan_network()

        # 3. 创建双端口服务器
        create_tcp_server(lan_ip, TCP_PORT_CTRL, "控制(2002)")
        create_tcp_server(lan_ip, TCP_PORT_IMAGE, "图像(2001)")

        # 4. 启动提示
        print("\n" + "="*60)
        print("🚀 庐山派K230三路摄像头控制服务器(官方规范版)")
        print(f"🎮 控制端口: {lan_ip}:{TCP_PORT_CTRL} | 2001端口统一发送图像")
        print(f"📸 核心逻辑:三路Sensor同时初始化,独立控制发送")
        print(f"📸 分辨率: 基础1920×1080 → 输出640×480")
        print(f"📸 摄像头指令对照表:")
        print(f"   CSI2: 0XA0(持续) 0XA1(单帧) 0XB0(停止)")
        print(f"   CSI0: 0X60(持续) 0X61(单帧) 0X70(停止)")
        print(f"   CSI1: 0X80(持续) 0X81(单帧) 0X90(停止)")
        print("="*60)

        # 5. 主循环:select多路复用监听
        while True:
            os.exitpoint()
            # 构建待监听的套接字集合
            read_socks = list(server_socks.keys()) + list(client_socks.keys())
            if not read_socks:
                time.sleep(0.001)
                continue

            # select监听
            readable, _, _ = select.select(read_socks, [], [], 0.001)
            for sock in readable:
                # 服务器套接字:新客户端连接
                if sock in server_socks:
                    port, sock_type = server_socks[sock]
                    try:
                        client_sock, client_addr = sock.accept()
                        client_sock.setblocking(False)
                        client_socks[client_sock] = (client_addr, sock_type)

                        # 连接成功提示
                        if sock_type == '控制(2002)':
                            print(f"\n" + "="*30)
                            print(f"🎮 2002控制客户端已连接: {client_addr}")
                            print("="*30)
                            # 发送指令说明
                            tip = b"K230 3-Camera Control Server | Official Standard\r\n"
                            tip += b"  CSI2: 0XA0(continuous) 0XA1(one frame) 0XB0(stop)\r\n"
                            tip += b"  CSI0: 0X60(continuous) 0X61(one frame) 0X70(stop)\r\n"
                            tip += b"  CSI1: 0X80(continuous) 0X81(one frame) 0X90(stop)\r\n"
                            client_sock.sendall(tip)
                        else:
                            print(f"\n" + "="*30)
                            print(f"📸 2001图像客户端已连接: {client_addr}")
                            print(f"🔑 数据格式: 通道标识(1B) + 长度(4B) + JPG数据")
                            print("="*30)
                            tip = f"K230 3-Camera Image Server | Resolution: {OUT_WIDTH}x{OUT_HEIGHT}\r\n"
                            client_sock.sendall(tip.encode())

                    except Exception as e:
                        print(f"\n⚠️  新客户端连接失败: {type(e).__name__}: {e}")

                # 客户端套接字:处理数据
                else:
                    client_addr, sock_type = client_socks[sock]
                    if sock_type == '控制(2002)':
                        handle_ctrl_data(sock, client_addr)
                    else:
                        handle_image_data(sock, client_addr)

            # 向所有图像客户端发送激活通道的图像
            for sock in list(client_socks.keys()):
                info = client_socks.get(sock)
                if info and info[1] == '图像(2001)':
                    send_active_frames(sock, info[0])

            time.sleep(0.001)

    except Exception as e:
        print(f"\n❌ 服务器主循环异常: {type(e).__name__}: {e}")
    finally:
        # 释放所有资源(严格遵循官方范例)
        print("\n" + "="*30)
        print("🔴 服务器开始释放资源...")
        print("="*30)
        # 关闭客户端套接字
        for sock in client_socks:
            try:
                sock.close()
            except:
                pass
        # 关闭服务器套接字
        for sock in server_socks:
            try:
                sock.close()
            except:
                pass
        # 停止所有Sensor(官方要求)
        global sensor0, sensor1, sensor2  # 声明使用全局变量
        if sensor0 is not None:
            sensor0.stop()
        if sensor1 is not None:
            sensor1.stop()
        if sensor2 is not None:
            sensor2.stop()
        # 释放显示和媒体资源
        Display.deinit()
        MediaManager.deinit()
        os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
        time.sleep_ms(100)
        print("✅ 所有资源释放完成:TCP套接字 + 三路摄像头 + 显示设备")

# ===================== 程序入口 =====================
if __name__ == "__main__":
    main()
    while True:
        os.exitpoint()
        time.sleep(0.01)

客户端,发送61,81,A1,来回切换看图片