自行编译micropython固件刷入ESP32 cam,并测试拍照及图传

一、环境准备

1.Ubuntu20.04LTS

2.ESP-IDF

3.micropython

操作步骤

1.安装基于Windows的linux子系统

适用于 Linux 的 Windows 子系统安装指南 (Windows 10)

注意:如果安装Ubuntu20.04LTS,需使用wsl,不要安装wsl2

2.编译环境准备(基于Ubuntu20.04LTS,别的系统需要的环境不同)

$ sudo apt-get install git wget libncurses-dev flex bison gperf python3 python3-pip python3-setuptools python3-serial python3-click python3-cryptography python3-future python3-pyparsing python3-pyelftools cmake ninja-build ccache libffi-dev libssl-dev python-is-python3

3.安装ESP-IDF

我是用的v4.3的分支,v4.3以前的wifi会出现自动休眠的情况,具体情况为工作一段时间后出现:

E (234871) wifi:ieee80211_ioctl.c 1443

下载并安装编译工具:

$ mkdir ~/esp/ #创建安装目录
$ cd ~/esp/
$ git clone https://github.com/espressif/esp-idf.git #克隆idf
$ cd esp-idf
$ git checkout v4.3 #切换分支,或者使用md5 git checkout c9646ff0beffc86d2c6d1bfbad34da16e328e0e3
$ git submodule update --init --recursive #更新子模块


# 克隆并检出 IDF 到正确版本后,运行 install.sh脚本:
$ ./install.sh #安装工具
#此处python会报错,不用管它,那是python的问题,与此次项目无关,有兴趣的朋友可以自己解决
$ source export.sh #配置环境变量

更新工具时github下载慢的解决方案:

$ vi ~/esp/esp-idf/tools/tools.json

#将https://github.com全部替换成https://hub.fastgit.org

 下载esp-idf工具的相机驱动

$ cd ~/esp/esp-idf/components
$ git clone https://github.com/espressif/esp32-camera #下载相机驱动

4.配置micropython

克隆micropython

$ cd ~/esp
$ git clone --recursive https://github.com/micropython/micropython.git #下载并更新子目录

由于官方的固件不带camera库,所以我们要手动配置,以便支持摄像头

下载micropython的camera

$ cd micropython/ports/esp32
$ git clone https://github.com/lemariva/micropython-camera-driver

将micropython-camera-driver文件夹中的文件复制到ports/esp32文件夹内

$ cp -r ~/esp/micropython/ports/esp32/micropython-camera-driver/* ~/esp/micropython/ports/esp32/

修改配置文件

#打开第一个文件

$ vi mpconfigport.h

# 在// extra built in modules to add to the list of known ones下加入

   extern const struct _mp_obj_module_t mp_module_camera;

# 在#define MICROPY_PORT_BUILTIN_MODULES \下加入

    { MP_OBJ_NEW_QSTR(MP_QSTR_camera), (mp_obj_t)&mp_module_camera }, \


#打开第二个文件

$ vi main.c

修改 #if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_SPIRAM_SUPPORT
至 #elif CONFIG_ESP32S2_SPIRAM_SUPPORT || CONFIG_ESP32S3_SPIRAM_SUPPORT 
之间的代码替换如下:
    size_t mp_task_heap_size;
    mp_task_heap_size = 2 * 1024 * 1024;
    void *mp_task_heap = malloc(mp_task_heap_size);
    ESP_LOGI("main", "Allocated %dK for micropython heap at %p", mp_task_heap_size/1024, mp_task_heap);

#打开第三个文件

$ vi main/CMakeLists.txt

在set(IDF_COMPONENTS下添加:esp32-camera
在set(MICROPY_SOURCE_PORT下添加:${PROJECT_DIR}/modcamera.c

 将一些内置脚本预编译为字节码

$ cd ~/esp/micropython
$ make -C mpy-cross

编译microPython固件

$ cd ~/esp/micropython/ports/esp32
$ make -j4 BOARD=GENERIC_CAM 

#查看固件
$ cd ~/esp/micropython/ports/esp32/build-GENERIC_CAM
$ ls
固件名为firmware.bin,由bootloader.bin、partitions.bin 和 micropython.bin 组成

二、烧录micropython

# 安装esptool.py

$ pip install esptool

# 擦除设备flash

$ esptool.py --chip esp32 --port (你的串口一般为COM3) erase_flash

#烧录

$ cd ~/esp/micropython/ports/esp32/build-GENERIC_CAM

$ esptool.py --chip esp32 --port (你的串口一般为COM3) --baud 460800 write_flash -z 0x1000 firmware.bin

三、测试

使用串口工具连接板子(自行百度下载)

烧录后的板子内有个boot.py文件,可以将连接wifi和其它需要开机启动的脚本放在此处

创建一个main.py的文件,这个文件可以用来写设备工作的内容,比如下方的拍照及图传

系统的执行顺序为boot.py->main.py

连接wifi

# 连接wifi
import network
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
# 扫描wifi
sta_if.scan()
# 连接wifi
sta_if.connect("WIFI名", "密码") 
# 查看连接状态
sta_if.isconnected() 

拍照

import camera

#ESP32-CAM(默认配置)
camera.init(0, format=camera.JPEG)


#其他设置:
#上翻下翻
camera.flip(0)
#左/右
camera.mirror(1)

# 分辨率
camera.framesize(camera.FRAME_SVGA)
# 选项如下:
# FRAME_96X96 FRAME_QQVGA FRAME_QCIF FRAME_HQVGA FRAME_240X240
# FRAME_QVGA FRAME_CIF FRAME_HVGA FRAME_VGA FRAME_SVGA
# FRAME_XGA FRAME_HD FRAME_SXGA FRAME_UXGA FRAME_FHD
# FRAME_P_HD FRAME_P_3MP FRAME_QXGA FRAME_QHD FRAME_WQXGA
# FRAME_P_FHD FRAME_QSXGA
# 有关详细信息,请查看此链接:https://bit.ly/2YOzizz

#特效
camera.speffect(camera.EFFECT_NONE)
#选项如下:
# 效果\无(默认)效果\负效果\ BW效果\红色效果\绿色效果\蓝色效果\复古效果
# EFFECT_NONE (default) EFFECT_NEG \EFFECT_BW\ EFFECT_RED\ EFFECT_GREEN\ EFFECT_BLUE\ EFFECT_RETRO

#白平衡
camera.whitebalance(camera.WB_HOME)
#选项如下:
# WB_NONE (default) WB_SUNNY WB_CLOUDY WB_OFFICE WB_HOME

#饱和
camera.saturation(0)
#-2,2(默认为0). -2灰度
# -2,2 (default 0). -2 grayscale 

#亮度
camera.brightness(0)
#-2,2(默认为0). 2亮度
# -2,2 (default 0). 2 brightness

#对比度
camera.contrast(0)
#-2,2(默认为0).2高对比度
#-2,2 (default 0). 2 highcontrast

#质量
camera.quality(10)
#10-63数字越小质量越高

#拍照,buf为jpg二进制数据,可以直接存储为jpg
buf = camera.capture()

传输,使用socket UDP方式

# 客户端(esp32 cam)
import socket

#服务端地址和端口,127.0.0.1改成你的服务端地址
ADDR = ('127.0.0.1',10086)

print ("发送UDP包...")
#socket连接
sendSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
#拍照发送
while True:
    buf = camera.capture()
    #发送数据
    sendSock.sendto(buf,ADDR)
    print ("发送完毕...")
#关闭socket连接
sendSock.close()


#服务端
import socket,time

# 客户端ip及端口,为空则接收任意客户端发来的数据
ADDR = ('',10086)
recvSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0)
recvSock.bind(ADDR)

# 这里时间戳用来命名图片文件    
time_e = int(time.time())
# 当前时间戳的第N帧
zz = 0
#总帧数,此次为测试,可具体参考帧数来设置(我测试的效果大概为每秒6帧,录制20s,所以达到120张照片停止循环)
num = 0
print ("等待数据...")

while True:
    #接收的数据大小,建议比图片本身大,不然无法传输
    data = recvSock.recv(100000)
    #每次检查时间戳
    time_b = int(time.time())
    #每次循环帧数加1
    zz = zz + 1
    #如果时间戳+1秒,则帧数序号归零
    if time_b != time_e:
        time_e = time_b
        zz = 0
    #存储图片
    filename = str(time_e) + str(zz) + '.jpg'
    with open (filename,'wb') as f :
        f.write(data)
        f.close()
    print(filename)
    #总帧数
    num =  num + 1
    if num == 120:
        break

#将图片合成视频
import os,cv2

pic_path = '.'
pics_list = [i for i in os.listdir(pic_path) if i.endswith('.jpg')]
fps = 7  # 帧率,自行参考文件命名,我的大概是7
size = (800, 600)  # 视频尺寸,请根据图片实际尺寸设置,不然无法合成,SVGA为800*600
out_file_name = '{0}.mp4'.format('示例视频')  # 输出视频名称
out_path =  '.'  # 输出视频路径
out_file = os.path.join(out_path, out_file_name)
fourcc = cv2.VideoWriter_fourcc('D', 'I', 'V', 'X')
 
video = cv2.VideoWriter(out_file, fourcc, fps, size)
for item in pics_list:
    item = out_path + '/' + item
    img = cv2.imread(item)
    video.write(img)
video.release()

接下来可以播放视频测试效果了,项目还在开发中,上述只为测试效果,请勿用于生产环境,关于UDP发送乱序的问题,可以将包编序,以字典的方式发送

 另,官版固件不自带urequests,需要自行安装

# 使用upip安装
import upip
upip.install("urequests")

测试urequests

import urequests
urequests.get('https://www.baidu.com').text

欢迎指正

end.

你可能感兴趣的:(esp32cam,python,单片机,物联网,ubuntu,github)