基于Sipeed M1s Dock的网络相机
基于Sipeed M1s Dock开发板,本项目实现了一个简单的网络实时相机
标签
嵌入式系统
2023寒假在家练
Parteiadler
更新2023-03-28
534

一、项目描述

1.项目需求

完成一个基于Sipeed M1s Dock的网络相机。具体要求为:完成相机驱动,定时拍摄图片,并将图片通过网络传到电脑或服务器,实现长时间拍摄;通过电脑端编程将图片合成为一个视频。

2.设计思路

使用Sipeed提供的示例代码中的camera_streaming_through_wifi例程,实现相机驱动、图片定时拍摄与图片上传功能;在PC端编写python代码,搭建服务端以接收并实时显示图片内容,达到实时网络相机的效果。

设备端依次执行摄像头初始化、WiFi初始化、WiFi连接,成功后便执行图片(已压缩为jpg格式)上传操作。

上传获取的一帧图片时,设备端首先会发送四个字节长度的数据,告知服务端将要发送的图片的大小,并等待服务端回复;接收到服务端回复的一字节任意内容后,设备端就会发送图片数据;图片数据发送结束后,便重复上述操作发送下一帧图片。

服务端运行python代码,搭建TCP服务端并监听指定ip地址及端口发来的连接请求;与设备端连接成功后开始接收数据,依次执行接收四字节的图片大小数据、回复一个字节的任意内容(本项目设置为一个空格,即“ ”,对应ASCII码为0x20)、接收图片数据、保存图片、显示图片,之后便重复此循环。

3.软件流程图

Fq6HOi5PlSCeruOA-RMxEhsNkdjd

二、项目硬件介绍

Sipeed M1s Dock是基于Sipeed M1s模组来设计的一款核心板,引出了MIPI CSI、SPI LCD等FPC接口,免去接线难的烦恼。使用最精简的设计,用于客户对模组进行模组评估,或者爱好者直接上手游玩等用途。

FqaedFo8ZSlgd_hYfM6cfDl_mYCS

板卡主芯片为BL808 RISC-V 480MHz + NPU BLAI-100;板载USB转UART调试器,可实现一键点击烧录,无需按实体按键;接有1.69寸240x280电容触摸屏和200W像素摄像头;支持2.4G WIFI / BT / BLE;板载1个模拟麦克风、1个LED和1个TF卡座;引出一路USB-OTG到USB Type-C接口。

开发板完备支持FreeRTOS,提供有C语言SDK,可以通过串口或虚拟磁盘拖拽两种方式实现固件下载,此外还支持AI推理框架和AI模型的使用,可以实现如语音关键词识别、人脸识别等AI应用功能。

本项目主要使用到了开发板的摄像头、WiFi等模块。

三、项目实现

1.模块介绍

设备端:设备端开发需要搭建环境。首先,在Linux系统下,访问以下两个链接:

SDK:https://gitee.com/Sipeed/M1s_BL808_SDK.git

Example:https://gitee.com/Sipeed/M1s_BL808_example.git

按照第二个链接的readme文件中的setup步骤搭建环境,能够正常编译示例代码即环境搭建成功。

现在根目录(bl808)下有两个文件夹:M1s_BL808_SDK中包含了Sipeed提供的SDK文件,主程序的代码依赖其中的库文件运行;M1s_BL808_example文件夹下则是实现功能的示例工程文件。

对于前者我们要关注的是如下路径:

~\M1s_BL808_SDK\components\sipeed\e907\m1s_e907_xram\src

在该路径中的m1s_e907_xram_wifi.c文件

对于后者我们要关注的是:

~\M1s_BL808_example\c906_app\camera_streaming_through_wifi

在该路径中的main.c文件,以及:

~\M1s_BL808_example\e907_app

这个路径。

两者与设备端WiFi连接有关。c906和e907为处理器的两个核,在连接WiFi时,WiFi SSID和服务端ip地址等参数参数传入c906中,但实际的WiFi连接与数据推流是由e907完成的。

接下来将介绍在烧写运行程序前需要执行的修改步骤。

(1)修改e907 firmware

修改后的firmware已在附件中提供(firmware.bin),可直接在后续步骤中使用,下文则是对修改过程的说明。

2023.2.27,官方发布了新的firmware修复了这个问题,经实验本项目代码与新firmware完全兼容(只要ip地址和端口等配置正确)。

(demo说明:https://wiki.sipeed.com/hardware/zh/maix/m1s/other/start.html,与本项目内容基本一致,但demo里的服务端python似乎更流畅,不过我也懒得改了,反正能用╮(╯_╰)╭)

上述工作过程中,两核之间的参数传递由m1s_e907_xram_wifi.c完成。可能是开发者疏忽,代码219~220行处服务端的ip地址和端口号是固定的,没有用到c906传来的参数,需要修改。(后续更新中该问题可能会被修复,读者请自行判断是否需要修改。官方还真的修复了,随便挑一个用吧······

client_addr.sin_port = htons(8888);
client_addr.sin_addr.s_addr = inet_addr("10.42.0.1");

将htons后的参数改为private.port,将inet_addr后的参数改为private.ip,该代码才可正常工作。

client_addr.sin_port = htons(private.port);
client_addr.sin_addr.s_addr = inet_addr(private.ip);

此时因为我们修改了e907核的SDK文件,其固件需要重新编译。在终端中打开e907_app目录,执行以下指令:

export BL_SDK_PATH=$(pwd)/../M1s_BL808_SDK

./build.sh firmware

第一条指令导入了SDK路径,第二条指令则编译firmware工程。编译完成后会生成build_out文件夹,该文件夹下的firmare.bin就是我们刚刚修改好的e907固件。保存好该文件,准备后续烧录。

(2)修改主程序文件

打开camera_streaming_through_wifi文件夹下的main.c文件,将第20行后的参数改为你的设备端将要连接的WiFi的SSID和密码,将第21行后的参数改为你的设备端将要连接的服务端的ip地址和端口号。

m1s_xram_wifi_connect("liuxo_desktop", "12345678");
m1s_xram_wifi_upload_stream("10.42.0.1", 8888);

最后在终端中打开c906_app文件夹(注意不是工程文件夹!),执行以下指令:

export BL_SDK_PATH=$(pwd)/../M1s_BL808_SDK

./build.sh camera_streaming_through_wifi

编译刚刚修改的工程,第一条执行过则不需要。编译完成后会生成build_out文件夹,该文件夹下的d0fw.bin就是我们刚刚修改好的工程程序,保存好该文件,准备后续烧录。

(3)程序固件等烧录

在以下网址中下载名为Bouffalo Lab Dev Cube的程序:

https://dev.bouffalolab.com/download

该程序为博流官方的图形化烧录程序。接下来按照以下网址中“3.1.1. 图形化界面烧录”的步骤进行烧录:

https://wiki.sipeed.com/hardware/zh/maix/m1s/other/start.html

其中firmware和d0fw使用之前编译好的.bin文件。

设备端开发完成。

服务端:服务端代码只需修改设定的ip地址和端口号即可直接运行。下面将介绍代码中每一部分所执行的操作。

参数定义:本部分定义了服务端的ip地址与端口号,以及存储图像文件的临时文件名。前两个参数根据你在主程序文件中设定的值修改。

# 参数定义
bind_ip = "192.168.0.104" # 服务端ip地址
bind_port = 9999 # 服务端端口号
filename = 'frame.jpg' # 保存的一帧图像的文件名

搭建TCP服务端并监听连接:此处使用了python的socket库,使用定义好的ip地址与端口号搭建TCP服务器,并监听设备端连接。一旦接收到设备端的连接请求,程序就会向下运行。

# 运行TCP服务端
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip,bind_port))
server.listen(1)
print("[*] Listening on %s:%d" % (bind_ip,bind_port))
client,addr = server.accept()
print("[*] Accepted connection from: %s:%d" % (addr[0], addr[1]))

数据处理循环:设备端与服务端连接后,首先会发送长度为4字节的图像大小数据,并等待服务端回复后才会发送图像数据。

以此数据传输过程为基础,服务端首先使用socket.recv()方法接收4字节数据,将其转换为int型变量(data_size),该变量值即为将接收的图像数据的大小。回复设备端1个字节的内容后,再次使用recv方法接收图像数据,保存到recv_image变量中。

需要指出的是,设备端发送数据时,同一图像的数据或其大小数据可能被分在两个TCP数据包中发送,使用单独的一次recv方法可能会存在接收不完全、传输未同步(即服务端没有正确捕捉到数据开始与结束的标志位处)的问题,代码中通过两次连续的recv方法解决。

# 读取下一帧图像大小
recv_size = client.recv(4)
if len(recv_size) < 4: # 未完全接收
    print('Data size is not completely received!')
    recv_append = client.recv(4-len(recv_size))
    recv_size = recv_size + recv_append
print('recv_size :',end = ' ')
print(recv_size)
data_size = int.from_bytes(recv_size, "little")
print('data_size =',end = ' ')
print(data_size)

# 回复客户端,令其发送当前帧图像
client.sendall(bytes(' ','UTF-8')) 

# 读取图像数据
recv_image = client.recv(data_size)
if len(recv_image) < data_size: # 未完全接收
    print('Image data is not completely received!')
    recv_append = client.recv(data_size-len(recv_image))
    recv_image = recv_image + recv_append
print('recv_image :',end = ' ')
print(recv_image)

接下来将获取的图像保存。

# 保存图像
with open(filename,'wb') as f:
    f.write(recv_image)

最后使用cv2库实现图像的读取与显示。

# 显示图像
jpg_image = cv.imread(filename)
cv.imshow('Streaming',jpg_image)
cv.waitKey(1)

所以,本服务端程序能够实时显示摄像机画面是通过连续存储、读取与显示静态图像实现的,因为处理每一帧图像所需的时间极短,所以视觉效果上便是连续的视频流播放。

2.整体实现及效果

烧录固件,运行设备端与服务端程序,效果如下(以下图片从演示视频中截取):

Ft7wIvYtEV6oFDWwMBC8TQlV1JskFhDvRFiq0dsYSUQ2Zcorhk2FiFrZ

四、遇到的问题

使用官方示例代码时,发现设备可以正常连接WiFi,但始终无法与服务端连接。经交流群友指点,理解了双核工作方式后发现是参数传递上出现了问题。此外,修改后重新编译firmware时,使用的Linux虚拟机经常会闪退,可能是工程过大的原因。限制build.sh中的线程数后,问题得以解决,设备也可与服务端正常连接。

测试服务端的数据处理功能时,最开始往往会在运行一段时间后出错。经串口调试后发现是通信未同步导致的。jpg格式的图片有固定的开始与结束标志,若接收端未实现同步,保存的图像数据就不可能被解码器正确解码。最后通过条件判断与两次连续的recv方法解决。

五、后期计划

本项目显示视频的方式可能并不常用也并不合适,后期会考虑改进显示视频的方式。官方的好像也差不多······

目前本项目只能实时显示摄像头捕捉的画面,没有实现录像功能,将来会考虑在服务端或设备端加入手动录制功能,让用户像使用手机的录像功能一样使用本项目的应用,保存需要的片段。

开发板附带的显示屏没有用到,考虑增加显示驱动将摄像头画面实时显示在显示屏上的功能。

服务端程序没有考虑到设备端主动断开连接的情形,若在服务端进行数据处理时强行断开设备端连接会出错,代码还有不完善的地方(这里官方做得比较完善,可以参考下)。

附件下载
Codes.zip
包括e907固件和服务端python代码
团队介绍
个人
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号