桌面电子小狗ESP8266调狗系统详解
目录
1.先上代码
2.使用方法:
3.配置管脚
4.串口数据解析:
5.val为什么要转换?
6.舵机位置判断
7.舵机控制
8.结果展示
1.先上代码
本文章用于调试B站的桌面电子小狗腿部动作,因为调试小狗的动作时,不知动作幅度是否符合位置,每次改代码重新下载太占用时间也不方便。所以通过串口调试大大减少难度,方便得出符合自己的电子小狗动作。各位可以运行成功后,哪里不懂的,可以再看一下下面的解释。
int myangle;//定义角度变量
int pulsewidth;//定义脉宽变量
int Front_left = 4;//前左,IO4(D2)引脚
int Front_right = 14;//前右,IO14(D5)引脚
int rear_right = 12;//后右,IO12(D6)引脚
int rear_left = 15;//后左,IO15(D8)引脚
void setup()
{
Serial.begin(9600);
pinMode(Front_left,OUTPUT);//设置前左的IO为舵机
pinMode(Front_right,OUTPUT);//设置前右的IO为舵机
pinMode(rear_right,OUTPUT);//设置后右的IO为舵机
pinMode(rear_left,OUTPUT);//设置后左的IO为舵机
}
void loop()
{
separate();//分离
}
String letters = "";//分离的字母
String numbers = "";//分离的数字
void separate()//分离
{
if (Serial.available() > 0) //检查串口缓冲区中是否有可用的数据
{
String input = Serial.readStringUntil('\n');//读取串口数据直到遇到换行符'\n'
for (int i = 0; i < input.length(); i++) {
if (isDigit(input[i])) //判断当前字符是否是数字(0-9)
{
numbers += input[i];
} else if (isAlpha(input[i])) //判断当前字符是否是字母
{
letters += input[i];
}
}
// Serial.print("字母: ");
// Serial.println(letters);
// Serial.print("数字: ");
// Serial.println(numbers);
Action1();
letters = "";//清除字母
numbers = "";//清除数字
}
}
//判断字母(letters)是什么,这里设定z为前左舵机,x为前右舵机,c为后右舵机,v为后左舵机,b为全部舵机
//例如串口输入为z90,就是前左舵机转90度,b90就是全部舵机转90度
void Action1()
{
int val = numbers.toInt();//将String 类型的数据转换为 int 类型
if(letters == "z")
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse1(Front_left,val);//前左舵机动作
}
Serial.print("前左: ");
Serial.print(val,DEC);
Serial.println();
}
if(letters == "x")
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse2(Front_right,val);//前右舵机动作
}
Serial.print("前右: ");
Serial.print(val,DEC);
Serial.println();
}
if(letters == "c")
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse3(rear_right,val);//后右舵机动作
}
Serial.print("后右: ");
Serial.print(val,DEC);
Serial.println();
}
if(letters == "v")
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse4(rear_left,val);//后左舵机动作
}
Serial.print("后左: ");
Serial.print(val,DEC);
Serial.println();
}
if(letters == "b")
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse1(Front_left,val);//前左舵机动作
servopulse2(Front_right,val);//前右舵机
servopulse3(rear_right,val);//后右舵机
servopulse4(rear_left,val);//后左舵机
}
Serial.print("全部: ");
Serial.print(val,DEC);
Serial.println();
}
}
void servopulse1(int Front_left,int myangle)//定义一个脉冲函数
{
pulsewidth=(myangle*11)+500;//将角度转化为500-2480 的脉宽值
digitalWrite(Front_left,HIGH);//将舵机接口电平至高
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
digitalWrite(Front_left,LOW);//将舵机接口电平至低
delay(20-pulsewidth/1000);
}
void servopulse2(int Front_right,int myangle)//定义一个脉冲函数
{
pulsewidth=(myangle*11)+500;//将角度转化为500-2480 的脉宽值
digitalWrite(Front_right,HIGH);//将舵机接口电平至高
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
digitalWrite(Front_right,LOW);//将舵机接口电平至低
delay(20-pulsewidth/1000);
}
void servopulse3(int rear_right,int myangle)//定义一个脉冲函数
{
pulsewidth=(myangle*11)+500;//将角度转化为500-2480 的脉宽值
digitalWrite(rear_right,HIGH);//将舵机接口电平至高
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
digitalWrite(rear_right,LOW);//将舵机接口电平至低
delay(20-pulsewidth/1000);
}
void servopulse4(int rear_left,int myangle)//定义一个脉冲函数
{
pulsewidth=(myangle*11)+500;//将角度转化为500-2480 的脉宽值
digitalWrite(rear_left,HIGH);//将舵机接口电平至高
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
digitalWrite(rear_left,LOW);//将舵机接口电平至低
delay(20-pulsewidth/1000);
}
2.使用方法:
arduino 软件的串口监视器输入対应的字母加数字,舵机対应作出相应的动作,方便我们调试电子小狗的各个腿。设定z为前左舵机,x为前右舵机,c为后右舵机,v为后左舵机,b为全部舵机。
例如串口输入为z90,就是前左舵机转90度,b90就是全部舵机转90度
3.配置管脚
舵机与8266引脚连接,电源可以直接连接板子上的G/VIN。这个是与下载线连接的,输出电压为5V。
int Front_left = 4;//前左,IO4(D2)引脚
int Front_right = 14;//前右,IO14(D5)引脚
int rear_right = 12;//后右,IO12(D6)引脚
int rear_left = 15;//后左,IO15(D8)引脚
小狗正上方图(有点丑,有点乱————————不要笑(威胁))
根据小狗正上方图,设定左上方为前左舵机,设定右上方为前右舵机,设定左下方为后左舵机,设定右下方为后右舵机。
4.串口数据解析:
if (Serial.available() > 0) //检查串口缓冲区中是否有可用的数据
{
String input = Serial.readStringUntil('\n');//读取串口数据直到遇到换行符'\n'
for (int i = 0; i < input.length(); i++) {
if (isDigit(input[i])) //判断当前字符是否是数字(0-9)
{
numbers += input[i];
} else if (isAlpha(input[i])) //判断当前字符是否是字母
{
letters += input[i];
}
}
// Serial.print("字母: ");
// Serial.println(letters);
// Serial.print("数字: ");
// Serial.println(numbers);
Action1();
letters = "";//清除字母
numbers = "";//清除数字
}
- 首先通过条件判断
if (Serial.available() > 0)
来检查串口缓冲区是否有数据可供读取。如果有数据,程序进入后续处理流程。 - 使用
String input = Serial.readStringUntil('\n');
语句读取串口数据直到遇到换行符,将数据存储在input
字符串变量中。 - 接着通过
for
循环for (int i = 0; i < input.length(); i++)
遍历input
字符串中的每一个字符。 - 在循环体内,利用条件判断语句来区分字符的类型。
- 如果
isDigit(input[i])
返回true
,说明当前字符是数字,就将其添加到numbers
字符串中,即numbers += input[i];
。 - 如果
isAlpha(input[i])
返回true
,表示当前字符是字母,就把它添加到letters
字符串中,即letters += input[i];
。 - 最后通过
Serial.print()
和Serial.println()
函数将分离出来的字母和数字分别输出到串口监视器上,方便我们查看结果。
5.val为什么要转换?
int val = numbers.toInt();//将String 类型的数据转换为 int 类型
String letters = "";//分离的字母
String numbers = "";//分离的数字
原始数据是从串口读取分离出来的字符串,其中的数字部分存储在 String
类型的 numbers
变量中。后续的数学运算(如乘法、比较等)和与角度相关的操作通常需要使用整数类型的数据。
toInt() 是 String 类的一个成员函数。它的主要作用是将 String 类型中存储的数字字符串转换为整数(int 类型)。
转换过程如下:
1.首先,它会读取 numbers 字符串中的字符。
2.然后,根据数字字符的 ASCII 值,将其转换为对应的整数值。例如,字符 '0' 到 '9' 的 ASCII 值是连续的,通过减去 '0' 的 ASCII 值,就可以将其转换为相应的整数 0 到 9。
3.如果字符串中包含多个数字字符,它会根据数字的位置和权值进行计算。例如,对于字符串 "123",百位上的 '1' 转换为 1,十位上的 '2' 转换为 2,个位上的 '3' 转换为 3,最终得到的整数值就是 123 = 1 * 100 + 2 * 10 + 3。
6.舵机位置判断
这里使用if不用switch/case是因为我懒。
判断根据不同的字母来确定要控制哪个舵机。z为前左舵机,x为前右舵机,c为后右舵机,v为后左舵机,b为全部舵机。
例如 if(letters == "z")
表示当接收到的字母是 "z" 时,控制前左舵机。
当接收到的字母是 "b" 时,同时控制所有的舵机(前左、前右、后右、后左)旋转到相同的角度。但是我们安装的舵机方向都不相同,所以串口输入“b+数字”时,舵机会转动不同的方向,当串口输入“b90”时,舵机都转到90度,电子小狗成立正状态。
if(letters == "z")
{
}
if(letters == "x")
{
}
if(letters == "c")
{
}
if(letters == "v")
{
}
if(letters == "b")
{
}
7.舵机控制
不用arduino库中的舵机库(Servo.h)的原因是:舵机库(Servo.h)不好用,转动角度达不到理想状态。
void servopulse2(int Front_right,int myangle)//定义一个脉冲函数
{
pulsewidth=(myangle*11)+500;//将角度转化为500-2480 的脉宽值
digitalWrite(Front_right,HIGH);//将舵机接口电平至高
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
digitalWrite(Front_right,LOW);//将舵机接口电平至低
delay(20-pulsewidth/1000);
}
根据输入的角度 myangle 计算出对应的脉冲宽度 pulsewidth。(角度myangle就是串口输入的字母+数字中的数字),这里的 (myangle * 11) + 500 是一种特定的计算方式,将角度值映射到一个合适的脉冲宽度范围(通常舵机的控制脉冲宽度在一定范围内与角度有对应关系)。
之后开始发送控制舵机的脉冲信号(引脚设置为高电平),延时后,引脚设置为低电平,完成一个脉冲周期。
delayMicroseconds(pulsewidth);//延时脉宽值的微秒数
延时 pulsewidth
微秒数。这个延时时间就是控制舵机的脉冲高电平持续时间,不同的脉冲宽度会使舵机转动到不同的角度。
delay(20-pulsewidth/1000);
再次进行延时,这里的延时时间是 20 - pulsewidth / 1000
毫秒。是为了确保脉冲发送的节奏和稳定性,满足舵机控制的时序要求。
8.结果展示
调试结果记录,后面开发根据动作记录进行进一步开发,比如加入语音模块,触摸按键等等,来完成相对应的动作。
case 'a': //站立
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse1(Front_left,90);//设置前左的IO为舵机
servopulse2(Front_right,90);//设置前右的IO为舵机
servopulse3(rear_right,90);//设置后右的IO为舵机
servopulse4(rear_left,90);//设置后左的IO为舵机
}
break;
}
case 's'://后趴
{
for(int i=0;i<=50;i++) //给予舵机足够的时间让它转到指定角度
{
servopulse1(Front_left,180);//设置前左的IO为舵机
servopulse2(Front_right,0);//设置前右的IO为舵机
servopulse3(rear_right,180);//设置后右的IO为舵机
servopulse4(rear_left,0);//设置后左的IO为舵机
}
break;
}
参考文章,感谢大神:用 Arduino 控制舵机 – Arduino 实验室
作者:头发慢慢离开了,它土生土长的头