ESP32:蓝牙BLE控制M3508电机
先给各位朋友拜个年,祝大家新春快乐,事事顺利,身体健康啊!
还是熟悉的3508,内容概述:
- ESP32主控
- 蓝牙BLE通信
- 使用实时系统(FreeRTOS)
- 使用ESP32的TWAI总线(CAN)
ESP32使用ESP-IDF v4.3开发,仓库地址放在文末。
目录
目录ESP32的TWAI(CAN)
概览与对比
有人说ESP32没有CAN总线控制器,其实不然,只不过它被称作TWAI,two-wire automotive interface。这也是ESP32可以用来控制大疆M3508、M2006等电机的根本原因。由于官方放出的资料很少,所以不被大家所熟知。
ESP32的CAN控制器在功能上比STM32略逊一筹,同时技术披露较少,其硬件设计参数基本都是未知的。但从另一方面说,整体配置使用比STM32更简单一些的,特别是结合实时系统提供的一些组件,不需要过多的考虑中断等问题。
最大区别在于,STM32有三组FIFO和灵活分配的filter,ESP32则采用收发buffer,控制器硬件将接受到的消息放入buffer中,软件驱动再把buffer中的报文处理过后放入queue,用户应用读取queue获取报文,发送同理。
反馈的获取
ESP32没有提供中断回调函数接口。意味着STM32上使用接收中断来更新电机反馈的方法是行不通的,为保证反馈量的实时性,有以下三种方法可以选择:
- 使用优先级合适的任务进行轮询
- 利用定时器中断回调进行轮询
- 利用TWAI控制器的alert查询阻塞读取
由于我使用的FreeRTOS的tick为10ms,而大疆C620电调的发送速率默认为1KHz,所以我使用了第一个方法来获取电机反馈数据。创建一个从queue中读取报文的任务,不断阻塞查询queue,计算更新反馈数据。
蓝牙BLE
ESP32的最大亮点就是支持WiFi、蓝牙协议栈,使用蓝牙代替串口的应用场景无需多言。其中低功耗蓝牙BLE非常合适少量文本数据的发送。下面简要介绍几个蓝牙BLE概念。
GAP
GAP定义了设备的广播行为,例如手机可以扫描到很多蓝牙BLE设备便是靠GAP。GAP把设备分成两种:中心设备(Central)、外围设备(Peripheral),外围设备对外不断广播,中心设备扫描、接收广播。发现后进而建立连接,再利用下文的GATT协议进行数据传输。
举例来说,我们的手机往往扮演中心设备的角色,而智能手环、智能家居、蓝牙耳机、电动牙刷等设备则是外围设备。
GATT
利用GAP发现并连接相应设备后,就可以开始传输数据了。蓝牙BLE的数据传输建立在GATT协议上,它定义了BLE设备之间如何传输数据。GATT把设备分为Client和Server,其中命令与请求由Client主动发起,Server被动接受。
请注意:GATT的Client、Server身份与GAP的中心、外围设备没有任何关系,它们可以任意搭配,甚至可以既是Server又是Client。
参考:Getting Started with Bluetooth Low Energy:https://www.oreilly.com/library/view/getting-started-with/9781491900550/ch04.html
在本例中,运行着GATT Server的ESP32在建立连接前主动对外广播,充当外围设备。手机作为GATT Client,可以主动发起数据传输。
下面是典型的GATT Server的数据层级结构图,服务端上可以同时提供多个Service让客户端选择,每个Service内可以有多个Characteristic,其中就保存着数据的内容和描述。客户端请求的时候就可以单独请求某个Service里的某个Characteristic包含的数据。
举例说明,某款智能手环作为GATT Server,定义了电量和运动两个Service。电量服务内有一个Characteristic保存着电池电量百分比,手机请求它即可获得手环电量。运动Service内有步数、消耗卡路里、睡眠时间等Characteristic,手机可以在需要的时候分别请求这些数据。
由于蓝牙协议内容较多,这里暂不展开,后面有机会可以进一步深入讨论。
ESP32 API
为了使用BLE,首先要把蓝牙外设驱动、硬件初始化,按照之前说的,为了建立连接我们要初始化GAP,为了传输数据要初始化GATT。具体表现为要为GAP、GATT注册处理事件的回调函数。
ret = esp_ble_gatts_register_callback(gatts_event_handler);
//错误处理
ret = esp_ble_gap_register_callback(gap_event_handler);
//错误处理
ret = esp_ble_gatts_app_register(PROFILE_A_APP_ID);
//错误处理
这些回调函数使用switch语句判断由底层驱动传递上来的事件编号,并给出处理步骤,我们对其中的读写事件处理进行修改,使其符合我们的数据传输需求。
结合前面完成的TWAI驱动、移植的PID程序,电机控制程序基本完成。
实际上手
使用微信上的BLE调试小程序或者Nordic Connect软件都可以,后者较为专业简洁,但两者功能上差别不大。
向图中的Characteristic发送速度目标值,会触发ESP_GATTS_WRITE_EVT
事件,在处理中加入解析并向发送设备返回一个notify告知写入成功:
char data[30];
memcpy(data,param->write.value,param->write.len);
data[param->write.len]=0;
moto_pid.target=atof(data);
printf("resetting target:%.2f\n",moto_pid.target);
sprintf(data,"SET TARGET:%.2f",moto_pid.target);
if (a_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY){//发送notice
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id,
gl_profile_tab[PROFILE_A_APP_ID].char_handle,
strlen(data),(unsigned char *)data, false);}
当按下左边的获取按钮时,会触发ESP_GATTS_READ_EVT
事件,使用response让Client获得图中的速度值:
char spd[20];
sprintf(spd,"speed:%hd",moto_chassis->speed_rpm);
rsp.attr_value.len = strlen(spd);
memcpy(rsp.attr_value.value,spd,rsp.attr_value.len);
esp_ble_gatts_send_response(gatts_if, param->read.conn_id,
param->read.trans_id,
ESP_GATT_OK, &rsp);
总结
临近年关,事也多,心也燥。这次本是简单的移植,文章却一直拖到正月初二才写完。涉及蓝牙协议栈的东西不敢多说,还需要多加研究。最后,祝大家新春快乐,工作顺利,身体健康!
工程仓库地址:GitHub:https://github.com/HuXioAn/ESP32-M3508-BLE
技术新人,水平有限,文中纰漏请一定指出,如有其他意见也请不吝赐教。更多嵌入式相关内容请移步公众号,来找我聊聊天吧:
欢迎转载,转载请注明作者与原文地址。
作者:胡小安
原文地址:https://www.cnblogs.com/huxiaoan/p/15861624.html