来源:
v1版本::【开源】百元内可自制的自平衡莱洛三角形_哔哩哔哩_bilibili
v2版本: 【开源】自平衡莱洛三角形V2 | 我加了RGB性能翻倍_哔哩哔哩_bilibili
原作者开源链接:https://gitee.com/coll45/foc
(本篇文章所有函数均为此开源网站下载函数)
说明:第一次接触Arduino和ESP32
关于此作品,作者在立创开源社区做了详细描述:
立创社区链接:v1:自平衡的莱洛三角_esp32_可充电_10*10版本 - 立创EDA开源硬件平台
v2:莱洛三角V2-esp32-无刷驱动EG2133 - 立创EDA开源硬件平台
参考文件:
灯哥开源FOC:【发布】不足百元!双路无刷电机驱动器 -灯哥双路无刷FOC驱动板正式开源!支持四足机器人!_哔哩哔哩_bilibili
simpleFOC库
KalmanFilter
FOC算法入门:FOC算法入门_梦如南伐的博客-CSDN博客_foc
爱转的光凌 :CH32读取MPU6050姿态数据(卡尔曼滤波法)_哔哩哔哩_bilibili
由于之前分析了v1版本的基本代码,v2版本和v1版本基本差不多,此次只考虑v2版本的RGB和he触摸按键的实现。
RGB有关
依照作者所提供原理图,RGB接口接在了ESP32的IO16端口。状态指示灯接在IO4端口。RGB灯组使用的WS2812通过Adafruit_NeoPixel库控制。
(发表一下自己的小看法:RGB和touch的函数文件非常不规范,引以为戒!!不要这么操作!)
在RGB.h文件中调用了Adafruit_NeoPixel库并且宏定义WS2812控制端口
//RGB.h
#include <Adafruit_NeoPixel.h>
// Which pin on the Arduino is connected to the NeoPixels?
#define LED_PIN 16
// How many NeoPixels are attached to the Arduino?
#define LED_COUNT 21
在main函数中的setup配置了RGB
//RGB.h
unsigned char brightness = 30;
//main
void setuo()
{
.........................
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
//调用此函数显示,操作后必须调用显示
strip.show(); // Turn OFF all pixels ASAP
//设置亮度,在RGB.h中配置了
strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
colorWipe_delay(strip.Color(255, 106, 106),50); //R,G,B
colorWipe_delay(strip.Color(0, 255, 255),50);
colorWipe_delay(strip.Color(148, 0, 211),50);
.........................
}
colorWipe_delay
//RGB.h
void colorWipe_delay(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
RGB.h文件下面包含了部分RGB灯效,通过判断触摸调用改变灯效。
//RGB.h
void strip1();
void strip2();
void strip3();
void rainbow1();
void rainbow2();
void pulse_rainbow1();
void rgb_off();
....................
触摸函数
触摸函数相关定义
//tourch.h
const int threshold_top = 40; //触摸阈值
const int single_count[3] = {10,10,10}; //单击时间 实际时间为20*10 = 200ms
const int long_count[3] = {80,80,80}; //长按时间 实际时间为80*10 = 800ms
unsigned long touch_last_time;
int touch_count[3] = {0,0,0}; //持续触摸计数
int touch_touched[3] = {0,0,0}; //单击,长按判断 单击值为1,长按值为2 没点击为0
bool touch_STATE[3] = {1, 1, 1}; // 定义按键触发对象状态变量初始值为true默认开启 T2 T3 T4
int rgb_flag = 1;
int rgb_modle = 8;//有几种RGB效果就写几
触摸感应判断
//tourch.h
//在main中loop函数调用touchAttach(touchID,touchPin)
void touchAttach(int touchID, uint8_t touchPin) {
int touchread = touchRead(touchPin); //触摸返回函数
if ( touchread <= threshold_top ) { //达到触发值的计数
//delay(38); // 0.038秒
touch_count[touchID]++; //持续触摸计数
}
//没有触摸时才进入触摸类型判断函数
else
{
if ( touch_count[touchID] >= single_count[touchID] &&
touch_count[touchID] < long_count[touchID])
touch_touched[touchID] = 1;//持续触摸时间达到单击
else if(touch_count[touchID] >= long_count[touchID])
touch_touched[touchID] = 2;
else
touch_touched[touchID]= 0;
touch_count[touchID] = 0; //持续触摸计数清零
}
}
loop函数中,通过触摸改变RGB灯效
//main
void loop()
{
.........................
// 触摸效果以及RGB灯效
unsigned long currentMillis = millis(); //获取开机后运行的时间长度ms
if(currentMillis - voltage_last_time >=1000)
{
voltage_last_time = currentMillis;
voltage_detection(); //有关电池电压检测加输出结果的函数!
}
if(currentMillis - touch_last_time >= 10) // Check for expired time
{
touch_last_time = currentMillis; // Run current frame
/*******************************************************
ESP32LED闪烁
功能:实现触摸按键按一下改变LED得状态
引脚:
T0:GPIO 4
T1:GPIO 0
T2:GPIO 2
T3:GPIO 15
T4:GPIO 13
T5:GPIO 12
T6:GPIO 14
T7:GPIO 27
T8:GPIO 33
T9:GPIO 32
arduino 也内置有相应的语法:touchRead(Touch Pin *);
https://img-blog.csdnimg.cn/d117f52b602e45f78ed63ca82a610b32.png
*******************************************************/
touchAttach(0,T2);
touchAttach(1,T3);
touchAttach(2,T4);
int i;
for(i = 0;i<3;i++)
{
if(touch_STATE[i]&&touch_touched[i]) //开启检测&&有按下
{
if(touch_touched[i] == 1)
{
single_event(i); //触摸单击函数
}
else
long_event(i); //触摸长按函数
}
}
}
.........................
}
按键模式处理函数
//main
void loop()
{
.........................
// Update current time 更新RGB效果
//就是隔一段时间运行一次
if(currentMillis - pixelPrevious >= pixelInterval) // Check for expired time
{
pixelPrevious = currentMillis; // Run current frame
switch(rgb_flag)
{
case 0 :
rgb_off();
break;
case 1 :
if(motor.shaft_velocity>0)
{
pixelInterval = 150 - motor.shaft_velocity;
strip2();
}
else
{
pixelInterval = 150 + motor.shaft_velocity;
strip3();
}
break;
case 2 :
pixelInterval = 100;
strip2();
break;
case 3 :
pixelInterval = 100;
strip3();
break;
case 4 :
strip1();
break;
case 5 :
rainbow1();
break;
case 6 :
rainbow2();
break;
case 7 :
pulse_rainbow1();
break;
}
}
.........................
}
触摸单机函数
//main
//触摸单击函数处理
void single_event(int touchID)
{
switch(touchID){
case 0 : //亮度减
if(brightness<=15) //亮度
brightness = 15;
brightness-=15;
EEPROM.writeUChar(28, brightness); EEPROM.commit();
strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
break;
case 1 : //亮度加
if(brightness>=240)
brightness = 240;
brightness+=15;
EEPROM.writeUChar(28, brightness); EEPROM.commit();
strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
break;
case 2 : //RGB开关
if(rgb_flag)
rgb_flag = 0;
else
rgb_flag = EEPROM.readUChar(32);
break;
}
}
触摸长按函数
//main
//触摸长按函数处理
void long_event(int touchID)
{
switch(touchID){
case 0 : //长按投币 //切换RGB
if(rgb_flag == 0)
rgb_flag = rgb_modle;
rgb_flag--;
strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
EEPROM.writeUChar(32, rgb_flag); EEPROM.commit();
break;
case 1 : //长按收藏 //切换RGB
rgb_flag++;
if(rgb_flag>=rgb_modle)
rgb_flag = 0;
strip.setBrightness(brightness); // Set BRIGHTNESS to about 1/5 (max = 255)
EEPROM.writeUChar(32, rgb_flag); EEPROM.commit();
break;
case 2 : //长按点赞
if(wifi_on_off)
{
motor.enable();
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
Serial.println("WIFI_OFF");
}
else
{
motor.disable();
AutoWifiConfig();//打开wifi
Serial.println("WIFI_ON");
}
wifi_on_off = !wifi_on_off;
Motor_enable_flag = !Motor_enable_flag;
break;
}
}
在setup函数中,写了brighyness、rgb_flag到EEPROM
//main
EEPROM.writeUChar(28,brightness); delay(10);EEPROM.commit();
EEPROM.writeUChar(32,rgb_flag); delay(10);EEPROM.commit();
电池检测的函数
这一部分比较简单
void voltage_detection()
{
#if defined(BAT_VOLTAGE_SENSE_PIN) //电池电压检测
bat_voltage = return_voltage_value(BAT_VOLTAGE_SENSE_PIN);
//driver.voltage_power_supply = bat_voltage;
//Serial.println(driver.voltage_power_supply);
if (bat_voltage < min_voltage && !battery_low)
{
battery_low = 1;
Serial.print(driver.voltage_power_supply);
Serial.println("V ");
Serial.print(bat_voltage);
Serial.println("V battery_low!!");
while (battery_low)
{
rgb_off();
motor.disable();
bat_voltage = return_voltage_value(BAT_VOLTAGE_SENSE_PIN);
if (bat_voltage >= (min_voltage + 0.5)) {
Serial.print(driver.voltage_power_supply);
Serial.println("V");
Serial.print(bat_voltage);
Serial.println("V battery ok");
digitalWrite(ACTIVE_PIN, 0); //电池电压恢复则常亮,需reset重启
//battery_low = 0;
} else { //电池电压低闪灯
if (millis() % 500 < 250)
digitalWrite(ACTIVE_PIN, 0);
else
digitalWrite(ACTIVE_PIN, 1);
}
}
}
#endif
}
return_voltage_value(int pin_on)
double return_voltage_value(int pin_no)
{
double tmp;
double ADCVoltage;
double inputVoltage;
analogSetPinAttenuation(pin_no, ADC_6db); //制定引脚输入衰减
for (int i = 0; i < 20; i++)
{
//默认12位分辨率
ADCVoltage = analogReadMilliVolts(pin_no) / 1000.0;
inputVoltage = (ADCVoltage * R1_VOLTAGE) / R2_VOLTAGE;
tmp = tmp + inputVoltage + ADCVoltage;
// formula for calculating voltage in i.e. GND
}
inputVoltage = tmp / 20;
if(inputVoltage!=0)
inputVoltage = inputVoltage + 0.001;
/*
for (int i = 0; i < 20; i++)
{
tmp = tmp + analogRead(pin_no);
}
tmp = tmp / 20;
ADCVoltage = ((tmp * 3.3) / 4095.0) + 0.165;
inputVoltage = ADCVoltage / (R2_VOLTAGE / (R1_VOLTAGE + R2_VOLTAGE));
// formula for calculating voltage in i.e. GND
*/
return inputVoltage;
}
有关OTA的问题没有探讨
最后、原作者代码很乱、引以为戒。
编译成功了!重装了好几个库,不知道是不是我的版本不对~
项目v1,v2的代码和实现方法有了简要的理解,嗯~ ~ ~ 对我的工作还是比较满意~硬件电路比较简单啦~ 看看作者给的原理图基本上就清晰啦!!总之,这个项目就这样吧,如果以后想继续研究SimpleFOC和Kalman的原理和代码实现的时候,再更新这个专栏吧~ ~ ~ !
加油学习~ 多看项目~ 多学原理~
一定要多看原理,不要单纯复刻,烧录谁不会
再次感谢大佬提供的开源项目!!!
最后附上大佬的B站链接:455555菌的个人空间_哔哩哔哩_Bilibili