本文作者:默(笔名)。默是一名创客技术宅,也是铁熊的好友。
前不久群里老师在讨论 PS2 手柄的问题,很多老师对手柄控制小车或者是机械臂有着极大地兴趣,但是却感到无从下手。刚好我手上有一个常年吃灰的 VR 手柄,趁着这个机会我给大家带来一个 DIY 手柄的教程,希望对大家有帮助,本期讲授的内容并非是如何制作手柄,而是教你一些 Arduino 的开发技巧(串口通讯、JSON 字符串序列化与解析、ESP-NOW 无线通讯等),进而去改造各种手柄或遥控器。
废话不多说,我们一起先来看看下面的演示视频吧,视频中我们使用改造的 VR 手柄玩贪吃蛇小游戏。
预期目标及功能
摇杆方向反馈;
摇杆位移量反馈;
多功能按键;
便捷电池充电与管理;
主动反馈与被动反馈;
无线控制任意开发板。
材料清单
ESP8266 01S 模块;
400 mA 锂电池;
AMS1117 3.3V 稳压芯片;
Arduino Nano 开发板;
Micro USB 接口座;
锂电池充放电一体模块;
手柄(可为任意手柄或 3D 打印手柄或各种遥控器)。

开发环境的选择
我们使用 Arduino 软件来编写本项目的程序,开发板选择 ESP8266 类型。至于如何在 Arduino 中配置 ESP8266 的开发环境,不在本文的介绍范围,请自行查阅相关资料。推荐大家使用 Mixly 图形化编程软件,因为 Mixly 软件自带了 Arduino 开发环境及相关库文件。
DIY 可编程手柄思维导图

我们将根据上面的思维导图逐步实现 DIY 可编程手柄的制作。
什么是 ESP-NOW
第一步是通讯方式的选择,这里我们需要使用无线通讯的方式去控制。无线通讯的方式常见的有 WiFi、蓝牙、串口透传模块等,在我们的 DIY 可编程手柄中我们不采用这些传统的无线通讯方式,我们采用 ESP-NOW。
那么 ESP-NOW 是什么呢?ESP-NOW 是由乐鑫开发的一款协议,可以使多个设备在没有或不使用 WiFi 的情况下进行通信。这种协议类似无线鼠标中的低功耗 2.4GHz 无线连接——设备在进行通信之前要进行配对。配对之后,设备之间的连接是持续的、点对点的,并且不需要握手协议。
ESP-NOW 通讯示意图如下所示:

我们为什么要采用 ESP-NOW 呢?在学习 Arduino 的过程中,Uno 是最基础的开发板,它的学习资源丰富,是初学者的福音,但是随着我们学习的不断深入,我们也会发现 Uno 一些无法避免的缺陷,比如处理速度低、内存空间小等,Uno 在 Arduino 系列开发板中处于一个比较尴尬的地位。而 ESP8266 与 ESP32 是 Arduino 的后起之秀,其中 ESP32 是 ESP8266 的升级版,它们均自带 WiFi 功能且硬件资源丰富,是进阶学习 Arduino 的不二之选,又因 ESP-NOW 协议的开发,使得 ESP 系列开发板成为了离线使用的最佳方式之一。传统的无线通讯模块只要脱离了单片机的控制,就会变得很鸡肋。而如果使用差不多价格的 ESP 系列开发板,你就相当于同时购买了单片机及无线通讯模块,这是一个不错的经济账,当使用多个 ESP 系列开发板时,这种性价比优势就显得格外明显。
ESP-NOW 使用方法
ESP-NOW 是点对点的通讯方式,我们发送数据时需要指定接收者(这好比你给对方发送 QQ 消息必须先获取对方的 QQ 号),在这里通过 MAC 地址作为区分接收方的唯一凭证,至于什么是 MAC 地址小伙伴们可以自行百度。下面我们看看如何获取 MAC 地址。
对于 ESP8266,获取 MAC 地址的代码如下:
#include <ESP8266WiFi.h>
void setup() {
Serial.begin(9600);
Serial.println();
Serial.print("ESP8266 Board MAC Address: ");
Serial.println(WiFi.macAddress());
}
void loop() {
}
对于 ESP32,获取 MAC 地址的代码如下:
#include <WiFi.h>
void setup() {
Serial.begin(9600);
WiFi.mode(WIFI_MODE_STA);
Serial.print("ESP32 Board MAC Address: ");
Serial.println(WiFi.macAddress());
}
void loop() {
}
使用掌控板(ESP32)上传代码后,打开串口监视器如下图所示:

其中 24:6F:28:43:F0:64 就是该开发板的 MAC 地址,该地址有 6 位 16 进制数构成。每一块开发板都有对应的 MAC 地址,我们可以记录下这个 MAC 地址,一会会用到。
获取到 MAC 地址后,我们来看看如何发送消息。这里我们采用 ESP8266 01 模块及 Arduino Nano 搭配使用作为手柄的发送端,那为什么要采用 ESP8266 01 模块及 Nano 作为发送端呢?原因是改造的 VR 手柄内部空间有限,现有的所有 ESP 系列开发板都无法放入手柄内,再加上手柄有一个摇杆,摇杆需要最少需要 2 路的 ADC 转换,但 ESP8266 模块只有一路 ADC 管脚,ESP32 模块虽然管脚多,但是需要搭配单独的 TTL 下载模块才能上传程序,且要将一些特殊管脚的电平进行设置比较繁琐。Nano 刚好能弥补这个不足,采用 ESP8266 01 模块与 Nano 一起使用这是相对理想的解决方案。这里为了调试方便我们先采用普通 ESP8266 开发板进行 ESP-NOW 的发送实验实验代码如下:
#include <ESP8266WiFi.h>
#include <ESP-NOW.h>
typedef struct struct_message {
char a[250];
} struct_message;
struct_message myData;
uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x58, 0x9D, 0x7C};
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
if (sendStatus == 0) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
}
void setup() {
Serial.begin(9600);
WiFi.disconnect();
WiFi.mode(WIFI_STA);
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_register_send_cb(OnDataSent);
esp_