萤火工场CEM5826-M11雷达模块应用
分享作者:caft
评测品牌:萤火工场
评测型号:CEM5826-M11
申请理由(产品应用):体感智能灯开发,漆黑的夜里保留一盏温馨的灯
发布时间:2024-11-04 09:49:13
0
前言
CEM5826-M11样片测评
开源口碑分享内容

1. 背景

首先非常感谢 iceasy 商城和萤火工场(Firefly Workshop)提供的 24GHz 毫米波雷达模块 CEM5826-M11(9.9 购买链接),我非常荣幸的获得了测评机会。本文在 ESP32C3 上通过 micropython 读取雷达数据,结合三色灯和蜂鸣器实现一套人体感应迎宾系统。

规格
正面
背面

2. 将 CEM5826-M11 接入 ESP32C3

ESP32C3

用的是这款 ESP32C3,CEM5826-M11 需要串口读取雷达数据,我选用 ESP32C3 的TX=GPIO0RX=GPIO1这组 UART 口。接线后这样

接线图1
接线图2

CEM5826-M11 模块未带焊针,这里用杜邦线连接有点丑,无奈之举,请忽略!!

3. 迎宾系统设计思路

从接线图可看到除了雷达模块外,还接入了一个蜂鸣器 + 一个三色 LED 灯,这套迎宾系统的第一目标是一定要酷炫。

3.1 系统状态定义

  1. 迎宾检测

当检测范围里第一次出现人时

  • 三色灯以红/绿/蓝交替闪烁
  • 蜂鸣器播放《小星星》歌曲欢迎

2. 活动检测

根据雷达检测到的人体不同活动幅度,分别亮灯

  • 小幅度活动:蓝灯亮
  • 中幅度活动:绿灯亮
  • 大幅度活动:红灯亮

3. 离开检测

检测范围里人离开后

  • 红灯闪烁
  • 蜂鸣器播放《敢问路在何方》歌曲欢送

3.2 活动幅度定义

这里不得不夸下CEM5826-M11,雷达数据获取方法如喝水般无比简单,只需周期性在 uart 上读取数据即可,读取到的数据格式:v=**,str=** 。(V 代表目标速度大小,str 代表信号强度)。在 micropython 操作下,没有比这种接口更简单的了。

根据雷达测试数据,我将活动幅度定义如下

1. 无人噪声信号 < 800

v=-1.1 km/h, str=370
v=1.0 km/h, str=394
v=1.1 km/h, str=325
v=-1.0 km/h, str=303
v=1.1 km/h, str=293
v=1.0 km/h, str=324
v=-1.0 km/h, str=317
v=1.1 km/h, str=364
v=1.2 km/h, str=387
v=-1.4 km/h, str=395

2. 可忽略的活动 < 1000

v=0.8 km/h, str=989
v=-0.9 km/h, str=746
v=0.9 km/h, str=629
v=0.9 km/h, str=630
v=-0.8 km/h, str=636
v=-0.9 km/h, str=543
v=0.8 km/h, str=611
v=0.5 km/h, str=697
v=0.5 km/h, str=843

3. 1000 <= 小幅度活动 < 2000

v=-0.2 km/h, str=1106
v=-0.1 km/h, str=1168
v=-0.1 km/h, str=1205
v=-0.1 km/h, str=1392
v=-0.1 km/h, str=1279
v=0.1 km/h, str=1343
v=-0.1 km/h, str=1289
v=-0.0 km/h, str=1329
v=-0.0 km/h, str=1401
v=-0.0 km/h, str=1333
v=-0.0 km/h, str=1198
v=-0.0 km/h, str=1133
v=-0.0 km/h, str=1005
v=-0.1 km/h, str=1005
v=-0.2 km/h, str=1037
v=0.2 km/h, str=1548

4. 2000 <= 中幅度活动 < 3000

v=0.4 km/h, str=2192
v=0.5 km/h, str=2319
v=0.6 km/h, str=2549
v=0.9 km/h, str=2832
v=1.0 km/h, str=2836
v=1.1 km/h, str=2816
v=1.1 km/h, str=2816
v=-1.1 km/h, str=2724

5. 大幅度活动 >= 3000

v=-1.0 km/h, str=4074
v=-1.1 km/h, str=7792
v=-1.0 km/h, str=10723
v=-1.0 km/h, str=12217
v=-0.9 km/h, str=12513
v=0.8 km/h, str=13748
v=0.8 km/h, str=13757
v=-0.8 km/h, str=13799
v=0.6 km/h, str=13506
v=0.5 km/h, str=10242
v=-0.4 km/h, str=7675
v=-0.4 km/h, str=4697
v=-0.2 km/h, str=3407

3.3 蜂鸣器唱歌

经过一番尝试最终用蜂鸣器模拟出不同音调,感兴趣的读者可参考:micropython 驱动蜂鸣器唱歌

4. 最终效果展示


B站视频

5. 完整代码

https://github.com/tinnfu/CEM5826-M11

from machine import UART, Pin, PWM
import time
import re
import asyncio

class Buzzer:
    # 定义音调频率
    TONES = {
        '1-': 262,
        '2-': 294,
        '3-': 330,
        '4-': 349,
        '5-': 392,
        '6-': 440,
        '7-': 494,
        '1=': 523,
        '2=': 587,
        '3=': 659,
        '4=': 698,
        '5=': 784,
        '6=': 880,
        '7=': 988,
        '1+': 1046,
        '2+': 1175,
        '3+': 1318,
        '4+': 1397,
        '5+': 1568,
        '6+': 1760,
        '7+': 1976,
        '__': 0
    }

    def __init__(self, pin = 6):
        self.buzzer = PWM(Pin(pin, Pin.OUT), freq=1000, duty=0)

    def __del__(self):
        self.buzzer.deinit()

    async def play(self, melody, duty = 10):
        i = 0
        keep = False
        while i  < len(melody):
            if melody[i] == '(':
                i += 1
                keep = True
                continue
            elif melody[i] == ')':
                i += 1
                keep = False

                # 连音结束后稍微停顿下
                self.buzzer.duty(0)
                await asyncio.sleep(0.05)
                continue

            tone, level = melody[i], melody[i+1]
            i += 2
            freq = Buzzer.TONES[tone+level]
            if freq:
                self.buzzer.init(duty=duty, freq=freq)
            else:
                self.buzzer.duty(0)  # 空拍时静音

            # 停顿一下 (四四拍每秒两个音,每个音节中间稍微停顿一下)
            await asyncio.sleep(0.2)
            if not keep:
                self.buzzer.duty(0)  # 设备占空比为0,即不上电
            await asyncio.sleep(0.05)

class Bye:
    def __init__(self, buzzer):
        self.buzzer = buzzer

    async def Song(self):
        # 《路在何方》
        melody = \
        "(6-1=1=6-)(3=3=3=)2=(2=1=1=1=1=1=1=1=)(7-6-6-7-)(2=2=2=)3=(1=6-6-6-6-6-6-6-)" \
        "(3=3=3=3=)(6=6=6=3=)(6=6=5=4=)(3=3=3=3=)(1=1=1=)2=(3=3=4=3=)(2=2=2=2=2=2=2=2=)" \
        "(6-6-)(3=3=)(2=3=6-6-)(1=1=1=1=1=1=3=3=)(2=7-7-3=)(2=6-1=2=)(3=3=3=3=3=3=3=3=)" \
        "(3=3=3=3=)(6=6=6=3=)(6=6=5=4=)(3=3=3=3=)(5=2=2=4=)(3=2=1=1=)(2=2=2=2=2=2=3=3=)" \
        "(2=7-7-3=)(7-6-5-5-)(6-6-6-6-6-6-)(3=3=)(5=5=5=5=5=5=)(3=5=)(6=6=6=)1+(7=6=)(5=5=)" \
        "(6=6=6=6=6=6=6=6=)(1+1+1+1+)(7=7=7=)6-(5=6=)(5=5=5=5=)(5=6=)(3=3=3=3=3=3=3=3=)" \
        "(1+1+1+1+)(7=7=7=)6=(5=6=)(5=5=5=5=)(5=6=)(3=3=3=3=3=3=3=3=)(5-6-)1=(3=3=3=)1=" \
        "(2=3=)(2=2=2=2=2=2=)(2=7-7-)3=(7-6-5-5-)(6-6-6-6-6-6-6-6-)(5-6-6-)1=(3=3=3=)1=" \
        "(2=3=)(2=2=2=2=2=2=)(3=3=5=5=5=5=)(3=3=)(7=7=7=1+7=6=5=5=)(6=6=6=6=6=6=6=6=6=6=6=6=6=6=6=6=)" \
        "(3=3=5=5=5=5=)(3=3=)(7=7=7=1+7=6=5=5=)(6=6=6=6=6=6=6=6=6=6=6=6=6=6=6=6=)"

        await self.buzzer.play(melody)

class Welcome:
    def __init__(self, buzzer):
        self.buzzer = buzzer

    async def Song(self):
        # 《小星星》
        melody = "1=1=5=5=6=6=5=__4=4=3=3=2=2=1=__5=5=4=4=3=3=2=__5=5=4=4=3=3=2=__1=1=5=5=6=6=5=__4=4=3=3=2=2=1="
        await self.buzzer.play(melody)

class Warning:
    def __init__(self, buzzer):
        self.buzzer = buzzer

    async def Song(self):
        melody = "(7=7=)(5=5=)(7=7=)(5=5=)(7=7=)(5=5=)(7=7=)(5=5=)"
        await self.buzzer.play(melody)

class Led:
    def __init__(self, r = 2, g = 3, b = 10):
        self.r_led = Pin(r, Pin.OUT)
        self.g_led = Pin(g, Pin.OUT)
        self.b_led = Pin(b, Pin.OUT)
        self._flash_done = False

    def off(self, excludes = []):
        if 'r' not in excludes:
            self.r_led.off()
        if 'g' not in excludes:
            self.g_led.off()
        if 'b' not in excludes:
            self.b_led.off()

    def on(self, signal):
        if 'r' == signal:
            self.r_led.on()
        elif 'g' == signal:
            self.g_led.on()
        elif 'b' == signal:
            self.b_led.on()

    async def flash_begin(self, signal = ['r', 'g', 'b']):
        self._flash_done = False
        self.off()
        while not self._flash_done:
            if 'r' in signal:
                self.on('r')
                await asyncio.sleep(0.2)
            self.off()
            if 'g' in signal:
                self.on('g')
                await asyncio.sleep(0.2)
            self.off()
            if 'b' in signal:
                self.on('b')
                await asyncio.sleep(0.2)
            self.off()
            await asyncio.sleep(0.2)

    def flash_end(self):
        self._flash_done = True

class Monitor:
    def __init__(self, buzzer, led):
        self.buzzer = buzzer
        self.led = led
        self.incoming = False
        self.agitation_begin = 0
        self.idle_begin = 0
        self.last_warning = 0
        self.no_signal_begin = 0

    async def bye(self):
        self.led.off()
        if self.incoming:
            # 闪红灯+一首歌欢送
            led = asyncio.create_task(self.led.flash_begin(['r']))
            await asyncio.create_task(Bye(self.buzzer).Song())
            self.led.flash_end()
            await led
        self.incoming = False

        # 清理所有状态,等下个状态机
        self.agitation_begin = 0
        self.idle_begin = 0
        self.last_warning = 0
        self.no_signal_end = 0

    async def welcome(self):
        self.incoming = True
        # 第一次来人,用酷炫的灯光+唱首歌欢迎
        led = asyncio.create_task(self.led.flash_begin(['r', 'g', 'b']))
        await asyncio.create_task(Welcome(self.buzzer).Song())
        self.led.flash_end()
        await led

    async def warning(self):
        led = asyncio.create_task(self.led.flash_begin(['r', 'g', 'b']))
        await asyncio.create_task(Warning(self.buzzer).Song())
        self.led.flash_end()
        await led
        self.last_warning = time.time()

    async def process(self, info):
        if not info:
            if self.no_signal_begin == 0:
                self.no_signal_begin = time.time()
            # 去噪
            if time.time() - self.no_signal_begin > 5:
                await self.bye()
            self.led.off()
            return

        self.no_signal_begin = 0

        try:
            lines = info.decode().split('\n')
        except Exception as e:
            print(e)
            self.led.off()
            return

        # v=-0.8 km/h, str=1083
        signal = 0
        count = 0
        for line in lines:
            if not line.strip():
                continue

            print(line)
            ret = re.search('str=(\d+)', line)
            if not ret:
                continue

            signal += int(ret.group(1))
            count += 1

        if count == 0:
            self.led.off()
            return
        signal /= count

        if signal < 700:
            self.agitation_begin = 0
            if self.idle_begin == 0:
                self.idle_begin = time.time()
            if time.time() - self.idle_begin > 10:
                await self.bye()
            self.led.off()
            return

        if not self.incoming:
            await self.welcome()

        self.idle_begin = 0

        if signal < 1000:
            self.agitation_begin = 0
            self.led.off()
            return

        if signal < 2000:
            self.led.off(['b'])
            self.led.on('b')
        elif signal < 3000:
            self.led.off(['g'])
            self.led.on('g')
        else:
            self.led.off(['r'])
            self.led.on('r')

        if self.agitation_begin == 0:
            self.agitation_begin = time.time()
        # 检测到持续3s的大幅动作并且距上次报警超过5s,提示安静下来
        if (time.time() - self.agitation_begin > 3) and (time.time() - self.last_warning > 5):
            await self.warning()

async def main():
    uart = UART(1, rx=1, tx=0)
    buzzer = Buzzer()
    led = Led()
    monitor = Monitor(buzzer, led)

    while 1:
        info = uart.read()
        await monitor.process(info)
        await asyncio.sleep(1)

time.sleep(5)
asyncio.run(main())

6. 总结

本文在 ESP32C3 上用 micropython 驱动 CEM5826-M11 雷达检测模块,实现了一套酷炫的人体感应迎宾系统。CEM5826-M11 模块对外输出简单的数据接口大大节省了开发调试时间,点赞!

一点建议:CEM5826-M11 模块没有焊接好也没有送焊针,无奈之下只能用杜邦线插入邮票口连线做开发调试。要是能提供焊接好的模块可选就更完美了。

全部评论
暂无评论
0/144