
#第九届立创电赛#ESP32S3摄像遥控小车
简介
ESP32S3摄像遥控小车具有地面移动摄像的功能,能用于开展农业作物观察、动植物观察、危险区域或无人区域探险、狭窄区域搜索、科学研究等活动。
简介:ESP32S3摄像遥控小车具有地面移动摄像的功能,能用于开展农业作物观察、动植物观察、危险区域或无人区域探险、狭窄区域搜索、科学研究等活动。开源协议
:GPL 3.0
描述
注:* 为必填项
请在报名阶段填写 ↓
* 1、项目功能介绍
最近在网上看到一款《废旧安卓手机暴改遥控坦克,支持画面传输,成品470元》的创意,这款遥控坦克是基于ESP32设计的,通过废旧安卓手机显示坦克拍摄的画面。如下图:

于是我们想着基于去年的ESP32-C3蓝牙小车,做一个蓝牙遥控的摄像小车,遥控和拍摄画面都通过微信小程序来实现,降低制作的难度和成本。
本项目基于立创·ESP32S3R8N8开发板、DRV8833直流电机驱动板、OV2640摄像头、OLED显示屏、锂电池、电机、橡胶轮等元件,成本不到100元(详见BOM表)。小车采用两路电源供电,具有低成本、静音、稳定、长续航等特点,适合中小学生学习、二次开发。
ESP32S3摄像遥控小车具有地面移动摄像的功能,能用于开展农业作物观察、动植物观察、危险区域或无人区域探险、狭窄区域搜索、科学研究等活动。比如我们就尝试开展了农田作物生长情况观察(详见视频)、寻找躲在床底下的猫猫(详见下图)、乐高城探险等应用测试(详见视频)。

*2、项目属性
本项目首次公开,为原创项目。
* 3、开源协议
使用GPL3.0开源协议。100%开源,便于中小学生学习和二次开发。
请在竞赛阶段填写 ↓
*4、硬件部分
1)主控芯片
采用立创·ESP32S3R8N8开发板,高性能随身WiFi与蓝牙开发板,所有资料全开源,丰富教程案例,轻松上手,项目式学习。支持以下功能:

详见官方文档:https://lckfb.com/project/detail/lckfb-esp32s3r8n8
2)电机驱动
采用一块国产小体积DRV8833电机驱动模块。

本项目采用橡胶轮,橡胶轮不能像麦克纳姆轮一样左右水平移动,左边的两个轮子和右边的两个轮子都是同向转动的,所以可以将左边两个电机并联组成一组,右边两个电机并联组成一组,只采用一块国产小体积DRV8833电机驱动模块驱动4个直流减速电机。
3)电源方案
采用两路电源方案,一路为ESP32S3开发板供电,一路为电机供电,避免互相干扰。特别是摄像头,需要更稳定的电压,当电压低时,图像会有水波纹。

ESP32S3开发板的供电参考《常用开发板的供电设计方案(3.3V、5V供电方案)》,直接将3.7V锂电池接入ESP32S3开发板的5V引脚,开发板会将3.7V降压到3.3V供MCU使用。
电机供电采用一个3.7V锂电池通过DRV8833直接供电,不需要降压。如果要让小车的速度更快,可以考虑采用2个3.7V锂电池供电,7.4V的电压能让小车速度更快。

因摄像头还需要用到2.8V和1.2V,所以增加了两路降压电路,分别采用XC6206P282MR、XC6206P122MR的LDO将3.3V降到2.8V和1.2V,供摄像头使用。
4)小车主板
因需要使用到OV2640摄像头,PCB板增加了不省贴片电容、电阻,以及LDO、SD卡等,增加了焊接难度。ESP32S3、DRV8833、OV2640摄像头等模块采用2.54排针固定,电池、电机采用XH2.54插件连接,方便焊接、组装,以及元件重复利用。
PCB板原理图如下:

PCB图:

焊接图:

PCB板焊接的难度在于那一排的贴片LDO、电容、电阻,其他都简单。
5)OV2640摄像头模块
包含三个模块:OV2640模块、转接板、M12镜头和镜头座。

这是我们做的一个开源工程,详见:https://oshwhub.com/cnas2023/camera-zhuan
摄像头转接板比较简单,只有一个24脚转接口和一个FPC接口。我们又在网上买了个镜头和镜头座,让摄像头拍摄的照片更清晰些。这块转接板是24脚的,没有去掉不用的引脚,适用于OV2640和OV5640,需要更高分辨率也可以用OV5640。
6)电机、橡胶轮、固定支架
某宝上买的,电机、车轮、固定支架各4个,不超过15元。

麦克纳姆轮具有随意改变行驶方向的特性,但稳定性较差,容易打滑,而且噪声较大。使用橡胶轮代替后,行驶稳定,且轮胎几乎没有噪声(噪声来自减速电机)。
7)电池

3.7V锂电池两颗,带XH2.54接线端子。我们用的是从坏的小米电动牙刷上拆下来的。
8)成果图
组装好的成品:





注:请前往嘉立创EDA 生成/上传设计文件,文件完成后,相关文稿将自动生成至项目详情;这里可以详细说明您的项目实现原理和机制、注意事项、调试方法、测试方法等。推荐图文并茂的形式向别人介绍您的想法。
*5、软件部分
1)遥控器(微信小程序)
我们开发的一个微信小程序,用来控制蓝牙小车行动并实时显示摄像头拍摄的画面。小程序二维码:

——小程序主界面


——小程序使用的UUID与Bluefruit Connect一致,默认是:
service_uuid = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
reader_uuid = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
sender_uuid = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'

——小程序的6个按键,分别为上、下、左、右、A、B,按下按键分别向连接的蓝牙小车发送"upup"、"down"、"left"、"right"、"act1"、"bac2"。
——小程序的浏览窗口用于实时显示摄像头拍摄的画面,浏览窗口地址为"http://"+文本框输入的地址+":5000/video_feed"
小程序的操作详见视频。
2)小车程序(基于Micropython)
小车程序一共包含电机控制、摄像头、SD卡、OLED等模块,当接收到微信小程序发送的"upup"、"down"、"left"、"right"指令时,做出前进、后退、左转、右转的动作,当接收到"act1"指令时,拍摄一张照片并存储在SD卡上。
因小车需要使用蓝牙遥控,并使用WIFI进行图像传输,所以我们使用了双线程,分别控制,避免干扰。参考代码如下:
from machine import Pin,freq,SDCard,Timer,SoftI2C
from time import sleep_ms,sleep
import bluetooth,network,camera,_thread,ssd1306,ufont
from microdot import Microdot
# 设置CPU的工作频率为 240 MHz
freq(240000000)
# 初始化OLED
i2c = SoftI2C(scl=Pin(4), sda=Pin(5))
display = ssd1306.SSD1306_I2C(128, 64, i2c) # 定义oled
font = ufont.BMFont("unifont-14-12917-16.v3.bmf") # 定义字体库
# 初始化SD卡
sd = SDCard(
slot=1 , width=1, cd=None, wp=None,
sck=1,miso=3,mosi=2,
cs=None ,freq=20000000
) #定义SD卡
os.mount(sd, '/sd') #挂载SD卡
# 初始化
BLE_MSG = ""
i=0
''' 定义小车电机引脚和动作函数 '''
Left0 = Pin(6,Pin.OUT) # O6引脚,左前轮电机向前
Left1 = Pin(7,Pin.OUT) # O7引脚,左前轮电机向后
Right0 = Pin(41,Pin.OUT) # 41引脚,右前轮电机向前
Right1 = Pin(42,Pin.OUT) # 42引脚,右前轮电机向后
# 车向前进
def cargo():
Left1.value(1)
Left0.value(0)
Right1.value(1)
Right0.value(0)
# 车向后退
def carback():
Left1.value(0)
Left0.value(1)
Right1.value(0)
Right0.value(1)
# 车停止
def carstop():
Left1.value(0)
Left0.value(0)
Right1.value(0)
Right0.value(0)
# 车向左转
def carleft():
Left1.value(0)
Left0.value(1)
Right1.value(1)
Right0.value(0)
# 车向右转
def carright():
Left1.value(1)
Left0.value(0)
Right1.value(0)
Right0.value(1)
'''定义网页图传相关函数,以及一些定义'''
#拍照
def take_picture():
global i
i = i+1
buf = camera.capture()
with open('/sd/{}.jpg'.format(i),'wb') as f:
f.write(buf)
print("拍照成功!")
sleep(0.01)
def connect():
wlan = network.WLAN(network.STA_IF)# 定义模式为连接热点
wlan.active(True)
if not wlan.isconnected(): #是否连接热点
wlan.connect('SSID', 'password')#连接网络,SSID和password改成目前的2.4G网络的名称(SSID)和密码(password)
while not wlan.isconnected():
pass
connect() # 联网
wlan = network.WLAN(network.STA_IF)# 定义模式为连接热点
ifconfig = wlan.ifconfig() # 获取网络信息
font.text(display, '请在浏览器打开:', 0, 0, show=True,clear=True, auto_wrap=True)
font.text(display, str('{}:5000'.format(ifconfig[0])), 0, 16,show=True, auto_wrap=True) # 提示网页图传的对应网址
app = Microdot() # 定义构建网站变量。
# 初始化摄像头
cam = camera.init(0, d0=38, d1=47, d2=14, d3=13, d4=12, d5=11, d6=10, d7=9,
format=camera.JPEG, framesize=camera.FRAME_HVGA,fb_location=camera.PSRAM,
xclk_freq=camera.XCLK_20MHz,
href=18, vsync=17, reset=8, pwdn=-1,
sioc=16, siod=15, xclk=40, pclk=39)#y2-d0
#调整camera参数
camera.brightness(2)
camera.contrast(2)
camera.quality(10)
camera.speffect(camera.EFFECT_NONE)
#camera.whitebalance(camera.WB_CLOUDY)
# 定义网站html代码。
@app.route('/')
def index(request):
return '''
ESP32S3蓝牙小车网页图传
ESP32S3蓝牙小车网页图传:
''', 200, {'Content-Type': 'text/html; charset=utf-8'}
# 网页图传
@app.route('/video_feed')
def video_feed(request):
def stream():
yield b'--frame\r\n'
while True:
frame = camera.capture()
yield b'Content-Type: image/jpeg\r\n\r\n' + frame + \
b'\r\n--frame\r\n'
return stream(), 200, {'Content-Type':
'multipart/x-mixed-replace; boundary=frame'}
class ESP32_BLE():
#蓝牙初始化
def __init__(self, name):
self.led = Pin(48, Pin.OUT) #配置LED灯引脚为输出模式
self.timer1 = Timer(0) #配置定时器
self.name = name
self.ble = bluetooth.BLE() #创建蓝牙对象
self.ble.active(True) #开启蓝牙
self.ble.config(gap_name=name) #配置蓝牙信息
self.disconnected() #设置定时器中断
self.ble.irq(self.ble_irq) #蓝牙时间处理
self.register() #配置蓝牙的uuid
self.ble.gatts_write(self.rx, bytes(100))#默认蓝牙只接收20字节,这里更改为接收100字节
self.advertiser() #蓝牙广播
self.ok = 0
#蓝牙连接,关闭LED灯
def connected(self):
self.timer1.deinit()
self.led.value(0)
print("connected ok")
#蓝牙未连接,LED闪烁
def disconnected(self):
self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))
#蓝牙事件处理
def ble_irq(self, event, data):
global BLE_MSG
if event == 1: #_IRQ_CENTRAL_CONNECT 手机连接了此设备
self.connected()
elif event == 2: #_IRQ_CENTRAL_DISCONNECT 手机断开此设备
if self.ok==0:
self.advertiser()
self.disconnected()
elif event == 3: #_IRQ_GATTS_WRITE 手机发送了数据
buffer = self.ble.gatts_read(self.rx)
BLE_MSG = buffer.decode('UTF-8').strip()
#蓝牙UUID配置
def register(self):
service_uuid = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
reader_uuid = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
sender_uuid = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
services = (
(
bluetooth.UUID(service_uuid),
(
(bluetooth.UUID(sender_uuid), bluetooth.FLAG_NOTIFY),
(bluetooth.UUID(reader_uuid), bluetooth.FLAG_WRITE),
)
),
)
((self.tx, self.rx,), ) = self.ble.gatts_register_services(services)
#蓝牙广播配置
def advertiser(self):
name = bytes(self.name, 'UTF-8')
adv_data = bytearray(b'\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name
self.ble.gap_advertise(100, adv_data)
print("等待连接:%s" % adv_data)
print("\r\n")
'''定义线程1网页图传函数'''
def main_cam(*args, **kwargs):
app.run(debug=True)#启动网页,并执行前面的网页图传相关函数
'''定义线程2蓝牙小车函数'''
def main_car(*args, **kwargs):
global BLE_MSG,e
try:
# 车先待命
carstop()
# 配置蓝牙
ble = ESP32_BLE("ESP32S3BLE")
# 配置LED
led = Pin(48, Pin.OUT)
while True:
if len(BLE_MSG)>0:
if BLE_MSG in ["!B507","!B606","!B705","!B804","!B10;","!B20:","!B309","!B408","stop"]: #松开按键停止
print(">>%s<<————停止" % BLE_MSG)
carstop()
elif BLE_MSG in ["!B516","upup"]: # 按下小程序的上键向前
print(">>%s<<————向前" % BLE_MSG)
cargo()
elif BLE_MSG in ["!B615","down"]: # 按下小程序的下键向后
print(">>%s<<————向后" % BLE_MSG)
carback()
elif BLE_MSG in ["!B714","left"]: # 按下小程序的左键向左运动
print(">>%s<<————向左" % BLE_MSG)
carleft()
elif BLE_MSG in ["!B813","right"]: # 按下小程序的右键向右运动
print(">>%s<<————向右" % BLE_MSG)
carright()
elif BLE_MSG in ["!B11:","act1"]: # 按下小程序的A键拍照
print(">>%s<<————拍照" % BLE_MSG)
take_picture()
BLE_MSG = ""
sleep_ms(100)
except KeyboardInterrupt:
pass
'''定义主函数'''
def main():
thread_1 = _thread.start_new_thread(main_cam, (None,)) #定义线程1
thread_2 = _thread.start_new_thread(main_car, (None,)) #定义线程2
'''运行'''
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt: #当出现KeyboardInterrupt异常
camera.deinit() #释放摄像头避免运行第二次出先错误提示
print("ok")
相关驱动(microdot、ssd1306、ufont)详见附件。
小车遥控和摄像效果详见视频。
注:若您的项目涉及软件开发,请在附件上传对应的工程源码。这里可以详细说明您的软件流程图、功能模块框图、相关算法的解释或科普、源码结构、编译环境的搭建和配置、源码编译方法、程序烧录方法等。推荐图文并茂的形式向别人介绍您的想法。
*6、BOM清单

自己统计的费用表:

注:项目涉及的BOM清单。在嘉立创EDA 生成/上传设计文件后,BOM将自动生成至项目详情;建议包括型号、品牌、名称、封装、采购渠道、用途等内容。具体内容和形式应以表达清楚项目构成为准。
*7、大赛LOGO验证


* 8、演示您的项目并录制成视频上传
ESP32S3摄像遥控小车具有地面移动摄像的功能,能用于开展农业作物观察、动植物观察、危险区域或无人区域探险、狭窄区域搜索、科学研究等活动。比如我们就尝试开展了农田作物生长情况观察(详见视频)、寻找躲在床底下的猫猫(详见下图)、乐高城探险等应用测试(详见视频)。

设计图
未生成预览图,请在编辑器重新保存一次BOM
暂无BOM
克隆工程

评论