ESP8266动耳控制板教程(?)
高情商:可动兽耳
低情商:ESP8266通过BMI160数据控制舵机(确信)
此教程为22年教程后续填坑√
基于ESP8266的电子兽耳3.0教程_哔哩哔哩_bilibili
鉴于有群友反应不会连线、不会找电源、不会烧程序等问题,搞出的新主板,基于前烂尾的slimevr工程改版(一堆烂尾工程),集成了2S充电、自动烧录、ESP12和BMI160。
接下来开始讲解
整个教程分为四部分,分别是材料选型,电路介绍,程序介绍,以及问题答疑。
首先是材料选型,淘宝上都有,全部购买的话一个板子30左右。
2.BMI1606轴陀螺仪模块,淘宝5元左右
3.IP2325充电模块,淘宝1元左右
4.AMS1117-3.3,淘宝抽象价格4块钱50个
5.TYPE-C接口,淘宝几毛钱一个
6.CH340串口芯片,淘宝1.5元一片
7.电容、电阻、LED等常用原件,5块钱之内拿下
其次是电路介绍
电路的原理图以及PCB已经放在了立创开源广场点击前往
电路主要可以分为三个部分,第一个是充电电路,采用的是一颗英集芯的IP2325,它可以将5V的输入电压升压至8.4V对2S电池进行充电,下图为充电电路部分。
红色框内为一个充电电源灯,当插上充电器时会常亮。
绿色框内为IP2325的充电指示灯,指示灯常亮时处于充电状态,指示灯熄灭时代表充电完成,如果指示灯闪烁则充电异常停止充电。
黄色框内可以接一个NTC电阻,可以检测电池or主板温度,当温度异常时停止充电,如果不需要测温则焊接上51K电阻。
第二部分是烧录电路,采用的是CH340串口烧录,并且支持自动烧录(玄学?),原理图如下
在正常烧录时,需要将IO0口接地并复位,通过自动烧录电路可以通过CH340以及8050将IO0自动拉低复位(8050没了,换的9012会有问题?),程序烧录完成后会自动复位开始运行。
第三部分是外部接口,如下图
其中BMI160是BMI160陀螺仪的接口,通过IIC与主控通信。VIN为从电池来的输入电压满电为8.4V,对比5V将有更大的扭矩。servo引出了三个IO口,可以作为舵机的控制引脚或者按键(别的功能也可以)。
第三个内容为程序介绍
首先,你的电脑需要安装CH340驱动,点击可以直接下载CH340驱动下载
为了方便编写及二创,这次采用的的依旧是arduino IDE。鉴于上次点灯科技致死量的延迟,所以这次通信采用的是ESP NOW通信协议,控制设备也从手机更换为另一个同样的主板(doge)程序在此
程序部分分为两个部分,一个是舵机控制板,一个是遥控器(俩东西虽然可以用同一个板子,但是程序不一样)。
这次为了防止找不到库,所以使用的库都是在IDE内可以搜到的
2.espnow(这个好像是芯片包自带的)
3.DFRobot_BMI160
4.MobaTools
程序有三个,一个是用于获取esp8266地址的程序(可以不用,烧录程序时会显示),另一个是舵机控制板程序,最后一个是遥控器程序
接下来按顺序介绍
首先是获取ESP8266地址的程序,需要获取地址的板子是作为接收方的舵机控制板(以下程序都不要复制使用,由于编辑器特性,网页上所写程序会和正确程序有格式上的出入)
#include <ESP8266WiFi.h> 调用特定的库 void setup(){ Serial.begin(115200); 初始化串口用于调试 WiFi.mode(WIFI_AP_STA); 设置WIFI模式 } void loop(){ Serial.println(WiFi.macAddress()); 输出当前芯片的地址 }
第二个程序是舵机控制板的程序,他会读取本身的BMI160或者通过ESP NOW读取遥控器上的BMI160来控制舵机
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <DFRobot_BMI160.h>
#include <MobaTools.h> //这些是调用库
MoToServo myServo1; //创建舵机
MoToServo myServo2;
float filteredPos = 90; // 初始滤波后的值
float alpha = 0.5; // 平滑因子,0 < alpha < 1 //低通滤波器所需
DFRobot_BMI160 bmi160; //定义BMI160传感器
const int8_t i2c_addr = 0x68; //设置地址
int mode =0; //创建模式变量
int16_t accelGyro[6] = {0}; //创建传感器返回值变量
int pos1,pos2; //创建舵机角度变量
typedef struct struct_message { //创建发送数据结构体
int message[3];
} struct_message;
struct_message myData;
// 接收回调函数
void onDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) { //ESP NOW接收回调函数
memcpy(&myData, incomingData, sizeof(myData)); //读取接收值
Serial.print(myData.message[0]);
Serial.print("\t");
Serial.println(myData.message[1]);
mode=myData.message[2]; //赋值模式
}
void ICACHE_RAM_ATTR IntCallback(); //中断
void setup() { //初始化
Serial.begin(115200); // 初始化串口波特率112500用于调试
attachInterrupt(digitalPinToInterrupt(0), IntCallback, RISING); //初始化按键中断
pinMode(2, OUTPUT); //初始化LED
WiFi.mode(WIFI_STA); //设置WIFI模式
myServo1.attach(14); //初始化舵机引脚
myServo2.attach(13);
myServo1.setSpeed( 200 ); //设置舵机运行速度
myServo2.setSpeed( 200 );
if (bmi160.softReset() != BMI160_OK){ //确认BMI160是否初始化
Serial.println("reset false");
while(1);
}
//set and init the bmi160 i2c address
if (bmi160.I2cInit(i2c_addr) != BMI160_OK){ //确认IIC地址是否正确
Serial.println("init false");
while(1);
}
if (esp_now_init() != 0) { //确认ESP NOW是否初始化
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); //设置为接收设备
esp_now_register_recv_cb(onDataRecv); //创建回调函数
}
void IntCallback(){ //按键中断函数(无遥控器时可用,有遥控器时失效)
if(mode==0)
{
mode=1;
}
else if(mode==1)
{
mode =0;
}
if (mode==0) {
// turn LED on:
digitalWrite(2, HIGH);
} else {
// turn LED off:
digitalWrite(2, LOW);
}
}
float lowPassFilter(float input, float prevOutput, float alpha) { //低通滤波器,效果一般
return alpha * input + (1 - alpha) * prevOutput;
}
void loop() {
if(mode==0) //模式一,自身BMI160获取数据(模式数量和功能可自定义,不过要有一定基础)
{
int rslt = bmi160.getAccelGyroData(accelGyro); //获取BMI160数值
if (rslt == 0) { //如果有数据开始处理
float ax = accelGyro[3] * 1.0 / 16384.0; // Convert to g
float ay = accelGyro[4] * 1.0 / 16384.0; // Convert to g
float az = accelGyro[5] * 1.0 / 16384.0; // Convert to g
float roll = atan2(ay, az) * 180.0 / PI; // Roll in degrees
float pitch = atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / PI; // Pitch in degrees
pos1=pitch*2+90; //将获取到的角度转换给舵机(随便写的,能用,要是有别的好方法可以自行替换)
pos2=pitch*2+90;
Serial.print("Roll: "); //串口输出调试
Serial.print(roll);
Serial.print(" °\tPitch: ");
Serial.print(pitch);
Serial.println(" °");
} else {
Serial.print("Error reading data: ");
Serial.println(rslt);
}
}
else if(mode==1) //模式二,遥控器获取数据
{
pos1=myData.message[1]*2+90;
pos2=myData.message[1]*2+90;
}
else if(mode==2) //模式三,可以自己动
{
for(pos1;pos1<179;pos1++) { myServo1.write(pos1); myServo2.write(180-pos1); delay(20); } for(pos1;pos1>0;pos1--)
{
myServo1.write(pos1);
myServo2.write(180-pos1);
delay(20);
}
}
myServo1.write(lowPassFilter(pos1,filteredPos,alpha)); //把角度输出给舵机,函数里面的是低通滤波器
myServo2.write(lowPassFilter(pos2,filteredPos,alpha));
Serial.println(mode);
}
程序的大致思路是模式一通过读取自身的BMI160数据控制舵机,模式二通过遥控器上的BMI160控制舵机,模式三角度随时间改变,不受陀螺仪控制(有别的需求的也可以自行编写,需要一定基础)
第三个程序是遥控器的程序,他的功能是不断读取bmi160的数据并通过ESP NOW发送给舵机控制板(程序大部分相似只介绍不同的地方)
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <DFRobot_BMI160.h>
// 广播地址,所有设备均可接收
uint8_t broadcastAddress[] = { //舵机控制板的地址,通过第一个程序获取
0xec, 0xfa, 0xbc, 0xca, 0x8c, 0xb2};
DFRobot_BMI160 bmi160;
const int8_t i2c_addr = 0x68;
int gy[3],mode=0;;
float roll;
float pitch;
// 发送数据结构
typedef struct struct_message {
int message[3];
} struct_message;
struct_message myData;
void setup() {
// 初始化串口监视器
Serial.begin(115200);
// 初始化Wi-Fi
WiFi.mode(WIFI_STA);
// 初始化ESP-NOW
if (bmi160.softReset() != BMI160_OK){
Serial.println("reset false");
while(1);
}
//set and init the bmi160 i2c address
if (bmi160.I2cInit(i2c_addr) != BMI160_OK){
Serial.println("init false");
while(1);
}
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 注册发送回调
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); //设置发送函数
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0); //发送设置
pinMode(0,INPUT);
}
void loop() {
if(digitalRead(0)==0) //按键切换功能
{
while(digitalRead(0)==0)
{}
mode++;
}
int16_t accelGyro[6] = {0};
int rslt = bmi160.getAccelGyroData(accelGyro);
if (rslt == 0) {
float ax = accelGyro[3] * 1.0 / 16384.0; // Convert to g
float ay = accelGyro[4] * 1.0 / 16384.0; // Convert to g
float az = accelGyro[5] * 1.0 / 16384.0; // Convert to g
roll = atan2(ay, az) * 180.0 / PI; // Roll in degrees
pitch = atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / PI; // Pitch in degrees
// Serial.print("Roll: ");
Serial.print(mode);
Serial.print("\t ");
Serial.print(roll);
Serial.print("\t ");
Serial.println(pitch);
// Serial.println(" °");
} else {
Serial.print("Error reading data: ");
Serial.println(rslt);
}
// 填充发送数据
myData.message[0]=roll;
myData.message[1]=pitch;
myData.message[2]=mode; //将数据赋值给数组
// 发送数据
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); //发送
}
程序的大致思路是不断读取BMI160的值并进行解算,然后连同模式一起发送给舵机控制板。
最后一项就是答疑了,鉴于目前没有大量使用,所以如果有这里没有写的问题可以发送的我的邮箱(2225203467@qq.com)或者进群(916323814)反馈,解决后会更新在下方,欢迎提问。
如果是使用的NTC电阻,检查阻值、连接或者温度有没有异常
如果使用的是电阻,请检查阻值以及焊接
这就是这块电路板的全部说明了,如果有问题欢迎大家指正。
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:http://heiya.top/?p=159
共有 0 条评论