使用ESP-NOW协议

Petoi 群控方案

1. 功能简介

ESP-NOW 是由乐鑫开发的另一款无线通信协议,可以使多个设备在没有或不使用 Wi-Fi 的情况下进行通信。这种协议类似常见于无线鼠标中的低功耗 2.4GHz 无线连接——设备在进行通信之前要进行配对。配对之后,设备之间的连接是持续的、点对点的,并且不需要握手协议。它是一种短数据传输、无连接的快速通信技术,可以让低功耗控制器直接控制所有智能设备而无需连接路由器,适用于智能灯、遥控控制、传感器数据回传等场景。

使用了 ESP-NOW 通信之后,如果某一个设备突然断电之后,只要它一旦重启,就是自动连接到对应的节点中重新进行通信。

ESP-NOW 的通信模式支持如下:

  • 一对一通信

  • 一对多通信

  • 多对一通信

  • 多对多通信

ESP-NOW 支持如下特性:

  • 单播包加密或单播包不加密通信;

  • 加密配对设备和非加密配对设备混合使用;

  • 可携带最长为 250 字节的有效 payload 数据;

  • 支持设置发送回调函数以通知应用层帧发送失败或成功。

同时,ESP-NOW 也存在一些限制:

  • 暂时不支持广播包;

  • 加密配对设备有以下限制:

    • Station 模式下最多支持10 个加密配对设备;

    • SoftAP 或 SoftAP + Station 混合模式下最多支持 6 个加密配对设备;

    • 非加密配对设备支持若干,与加密设备总数和不超过 20 个;

  • 有效 payload 限制为 250 字节。

Petoi群控完全可以采用ESP8266模块的ESP-NOW通信功能。

2. 准备工作

2.1 硬件准备

本案例准备2只Bittle(配备WiFi模块),一台连接有ESP模块的计算机。

图中模块的程序烧录和MAC地址的获取见下文。

2.2 软件准备

电脑安装Thonny,方便进行8266模块的MicroPython的调试。 使用ESP-NOW协议时,需要特殊的MicroPython固件(见Github)。因为普通版本的8266-MicroPython固件会提示找不到库。

打开Thonny并使用USB上载器连接ESP8266模块,在shelll界面中输入:

import espnow

如果出现错误提示如“找不到espnow”模块,表示固件烧录有问题;若没有任何提示,表示固件烧录正常。

3. 代码简介

群控代码分为3部分:

  • 查询模块的MAC地址

  • 发射端程序

  • 接收端程序

3.1 查询模块的MAC地址

MAC地址是一个用来确认网络设备位置的位址,由OSI网络模型第二层(数据链路层)负责。 MAC地址也叫物理地址、硬件地址,由网络设备制造商生产时烧录在网卡的非易失存储器(如EEPROM)中。

MAC地址的长度为48位(6个字节),通常表示为12个16进制数。 其中前3个字节代表网络硬件制造商的编号,它由IEEE(电气与电子工程师协会)分配, 而后3个字节代表该制造商所制造的某个网络产品(如网卡)的系列号。 只要不更改自己的MAC地址,MAC地址在世界是唯一的。形象地说,MAC地址就如同身份证上的身份证号码,具有唯一性。

ESPNOW最简单的使用方式是通过MAC地址发送。我们使用一个小的程序来查询模块的MAC地址。

import ubinascii
import network

wlan_sta = network.WLAN(network.STA_IF)
wlan_sta.active(True)
wlan_mac = wlan_sta.config('mac')
print(ubinascii.hexlify(wlan_mac).decode())

在Thonny中运行后,在终端打印出MAC地址。此时可以用一个不干胶贴写上模块的MAC地址并贴在模块上。

3.2 发射端程序

发射端程序由以下几个部分组成:

  • 启用模块的WiFi功能

  • 配置ESP-NOW协议并启用

  • 添加需要通信的节点(peer)

  • 发送消息

具体程序代码如下:

import network
import espnow
import time

sta = network.WLAN(network.STA_IF)    # Enable station mode for ESP
sta.active(True)
sta.disconnect()        # Disconnect from last connected WiFi SSID

e = espnow.ESPNow()     # Enable ESP-NOW
e.active(True)

peer1 = b'\xe8\x68\xe7\x4e\xbb\x19'   # MAC address of peer1's wifi interface
e.add_peer(peer1)                     # add peer1 (receiver1)

peer2 = b'\x60\x01\x94\x5a\x9c\xf0'   # MAC address of peer2's wifi interface
e.add_peer(peer2)                     # add peer2 (receiver2)

print("Starting...")            # Send to all peers

e.send(peer1, "walk", True)     # send commands to pear 1
e.send(peer2, "walk", True)     # send commands to pear 2
time.sleep_ms(2000)
e.send(peer1, "walk", True)
e.send(peer2, "back", True)
time.sleep_ms(2000)

3.3 接收端程序

接收端程序主要由以下几个部分组成

  • 启用模块的WiFi功能

  • 配置ESP-NOW协议并启用

  • 添加需要通信的节点(peer)

  • 接收消息并解码,通过串口给NyBoard发送指令

具体程序代码如下:

import network
import espnow
from machine import UART

def espnow_rx():
    #config UART
    uart = UART(0, baudrate=115200)

    # A WLAN interface must be active to send()/recv()
    sta = network.WLAN(network.STA_IF)
    sta.active(True)
    sta.disconnect()                # Disconnect from last connected WiFi SSID

    e = espnow.ESPNow()                  # Enable ESP-NOW
    e.active(True)

    peer = b'\x5c\xcf\x7f\xf0\x06\xda'   # MAC address of peer's wifi interface
    e.add_peer(peer)                     # Sender's MAC registration

    while True:
        host, msg = e.recv()
        if msg:                          # wait for message
            if msg == b'walk':           # decode message and translate
                uart.write("kwkF")       # to the NyBoard's command
            elif msg == b'back':
                uart.write('kbk')
            elif msg == b'stop':
                uart.write('d')

if __name__ == "__main__":
    espnow_rx()
    

此代码封装于一个名为espnow_rx()的函数中是为了方便上电后自动启动程序。

实现上电自动启动的方法有以下两种:

  • 将代码文件改名为main.py

  • 修改boot.py文件;

对于新手而言,我们更推荐第一种方法。

3.4 通信-指令转换程序

将串口命令转换写在接收端会使程序过于复杂且不易维护。我们可以新建一个函数在其中进行指令转换并输出命令。

Last updated