基于Arduino通过并联L298N实现四驱麦克纳姆轮巡迹小车

1 前言

本人也是零基础进行Arduino学习的初学者,做小车期间遇到过很多困难,在此写下整个小车的制作流程以及遇到的问题与解决方案,希望对后来者有所帮助。在制作期间参考了许多文章得到了大佬的指点,以及下面展示成果如建模等是由朋友做的,在此一并表示感谢。

总结来说,小车基于Arduino UNO单片机,通过并联L298N电机驱动板实现八输出(因为同时控制四个轮的正反转需要八个变量)来控制小车除前后直线移动,左拐右拐之外,还可以顺时针逆时针原地自旋以及向左向右横向平移。并加载Arduino扩展板实现循迹、寻光、避障、蓝牙遥控和无源蜂鸣器报警功能。

2 总体结构概括

2.1 机械结构

首先整体结构为双层亚克力板,如图其下层承载四个TT电机、三个循迹模块传感器以及两个红外避障传感器和18650电池组,上层承载Arduino开发板与拓展板、两个L298N电机驱动板、蜂鸣器、蓝牙模块和两个循光传感器。两层亚克力板间采用铜柱与螺栓联接。

车体亚克力板部分以及循迹、寻光、红外避障传感器、蓝牙模块、tt电机都是由淘宝买的套件小车的产品,不需要自己配置散件。可以购买时仔细阅读套件清单或者直接向商家问个清楚,商家都很有耐心的。(依次为红外避障、寻光、循迹传感器)

麦克纳姆轮是需要单独购买的,小车套件里面的是四个普通的轮子。电池也是单独购买的两节18650可充电锂电池,电机驱动板是两个L298N,此外还单独购买了一个无源蜂鸣器。这些单独购买的也可以很容易在淘宝上找到,但是有一些购买细节,这些在下文会单独说明。

 2.2 电路连接

需要说明的是,虽然Arduino需要5V的供电电压,但是并不需要再额外配置一个5V电压源,因为两节18650接入电机驱动板供电后,电机驱动板可以有一路降压输出5V给Arduino板子。

对于蓝牙模块接线,除了蓝牙模块的+-与Arduino板子的+-对应以外。蓝牙模块上标注RX的接口需要连接板子TX的接口,同样蓝牙TX要对应板子RX(rx是接收receive,tx是发送transport)。同样容易出错的是上传程序时需要把蓝牙模块卸下,因为其占用着Arduino板子的RX与TX,程序报错无法上传。

对于不同的套件、接入不同的传感器有不同的接线图,认清是A口还是D口,哪里是VCC哪里是GND,灵活变通即可。接线图如图所示。

3 具体细节说明

3.1 电机驱动板

电机驱动板是在Arduino主板和tt电机之间的角色,以实现对TT电机的控制。虽然只需要一个L293D就可以实现八输出,但是需要插到Arduino主板上进行供电,就因此无法再安装扩展板,也就没法安装众多的传感器(其实是可以的,但我不会,对不起)。

每个L298N有四个输入接口:IN1、IN2、IN3、IN4,用四根线和Arduino的四个Digital接口连接,以实现主板对电机驱动板的控制。每个L298N同时有四个输出接口OUT1、OUT2、OUT3、OUT4(与四个输入接口是一一对应的),因此用四根线可以分别连接两个电机的正负极,这样两个电机驱动板可以实现四个电机的正反转控制。由于电机安装方向和接线方向的影响,直接判断哪个接口可以使轮子正转也可以,单建议安装完电机后通过程序试一试来确定IN1、IN2、IN3、IN4四个接口中哪个接口输入高电平可以使轮子正转。

然后是电机驱动板之间的并联,就是电源的正极和两个电机驱动板的正极连接,从电机驱动板的5V引出一路给Arduino主板供电,电源负极和两个电机驱动板还有主板的负极连接在一起,如上图左侧电路示意图。并联的原因就是为了可以少用一个电源,减少麻烦,所以若是不想并联各自给电机驱动板配置一个电源也无所谓,记得两个电机驱动板和Arduino主板的GNG要接在一起就可以了。

3.2 麦克纳姆轮

对于四轮小车来说,一套麦克纳姆轮至少应含有两种不同的轮子。我们选择两种就好—两个左轮两个右轮(注意这个左右不是位于左边的轮子和位于右边的轮子的意思,是轮子的构造方向不一样)。左轮右边轮构型如图所示,所以购买的时候一定要和商家说清楚。

在这里插入图片描述

在这里插入图片描述

具体麦克纳姆轮如何实现平移以及自旋,还有轮子的安装顺序都可以看这篇文章,在此对作者表达感谢(不知道这样引用对不对)。然后控制程序可以见下文,我的控制程序更零基础(小白)一些。

https://blog.csdn.net/handsome_Ares/article/details/120140997?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167679074216782429723326%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167679074216782429723326&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-120140997-null-null.142^v73^insert_down2,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=%E9%BA%A6%E5%85%8B%E7%BA%B3%E5%A7%86%E8%BD%AE&spm=1018.2226.3001.4187icon-default.png?t=N176https://blog.csdn.net/handsome_Ares/article/details/120140997?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167679074216782429723326%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167679074216782429723326&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-120140997-null-null.142^v73^insert_down2,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=%E9%BA%A6%E5%85%8B%E7%BA%B3%E5%A7%86%E8%BD%AE&spm=1018.2226.3001.4187

3.3 无源蜂鸣器

有源无源可能不是没有了解过的人想像的那个意思, “源” 不是指电源,而是指振荡源。简而言之无源蜂鸣器可以自己编写一些勉强分得清在唱什么的曲调,有源的就不可以。

需要注意的是想要实现蜂鸣器唱歌需要在程序中加入头文件 pitches.h,该文件包含典型音符的所有音高值。加入头文件的方法十分容易,若是不会可以百度一下。记得把头文件和Arduino程序文件放在同一个文件夹里就好。

如果有兴趣可以看下面这篇文章。(谢谢作者!)

https://luhuadong.blog.csdn.net/article/details/103395351?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-103395351-blog-128067566.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-103395351-blog-128067566.pc_relevant_recovery_v2&utm_relevant_index=5icon-default.png?t=N176https://luhuadong.blog.csdn.net/article/details/103395351?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-103395351-blog-128067566.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-103395351-blog-128067566.pc_relevant_recovery_v2&utm_relevant_index=5

3.4 电源

电源是受挫最多的地方,起初图方便用六节南孚电池作为电源,结果程序在电脑上调试时好好的,一断开USB线用电源供电就执行的晕头转向,十分玄学。后来由大佬的指点发现是因为南孚电池电流太大导致Arduino主板一直不定时重启。

所以后来更换了更为稳定的两节18650可充电锂电池,一共7.4V,问题得以解决(要是实在解决不了可以先把所有程序都调好了后上传试试,说不定就可以了呢)。

3.5 其他

还有就是不可忽略的小车的传感器的调试环节,上传代码成功后小车依旧无法巡线无法避障,这时候可能不是代码的问题,可能是传感器输入调试没做好。网上或者淘宝商家也有一些传感器的调试方法可以借鉴,最重要的就是亲自一点点扭转传感器上的电位器一遍遍试,找到最合适的电位器位置以及最合适的传感器安装位置。(比如三个巡线传感器就可以适当离的宽一些)

最后小车还有一个非常玄学的地方,就是右侧后轮经常莫名其妙地没有指令就转起来了。即使重新接线也不行,令人困惑。没有找到根源,但是基于经验是只要按压小车前端就可以让他停止这种现象,所以用轧带将前端进行固定。

4 结果展示

4.1 建模

有点地方不太对,不过无伤大雅,加了一个车壳和保险杠,不过没加工出来。

4.2 巡线 

GIF太大无法上传,想看看巡线、蓝牙遥控的视频可以去主页,写的时候还在审核不知道能不能过。至于避障、寻光也没必要上传了。

4.5 蓝牙遥控

蓝牙遥控的app是一个朋友做的,不方便共享,不过这玩意可以在应用市场下载,就是有些广告。下面是操作命令表,也可以到程序里自己差(避障模式2的指令是p,忘记写上了):

5 代码说明

俯看小车,车头在上将四个轮子分别编号为左1左2右1右2(程序中轮子的对应名称,这个需要根据前文所说的哪个接口接入高电平是正转自己更改程序,很简单小学二年级就学过)。

这是无源蜂鸣器播放《致爱丽丝》的功能,需要的pitches.h头文件。头文件下面是各个功能合并后的代码,可以用蓝牙来进行功能模式的切换。由于用的都是些学c语言第一课就能学完的基础语句,具体原理看代码就能很容易看懂,就无需多言了。

//pitches.h 音高定义//pitches.h 定义了不同音符对应的不同频率#define NOTE_B0 31 //B0 ····7#define NOTE_C1 33 //C1 ···1#define NOTE_CS1 35 //C1##define NOTE_D1 37 //D1 ···2#define NOTE_DS1 39 //D1##define NOTE_E1 41 //E1 ···3#define NOTE_F1 44 //F1 ···4#define NOTE_FS1 46 //F1##define NOTE_G1 49 //G1 ···5#define NOTE_GS1 52 //G1##define NOTE_A1 55 //A1 ···6#define NOTE_AS1 58 //A1##define NOTE_B1 62 //B1 ···7#define NOTE_C2 65 //C2 ··1#define NOTE_CS2 69 //C2##define NOTE_D2 73 //D2 ··2#define NOTE_DS2 78 //D2##define NOTE_E2 82 //E2 ··3#define NOTE_F2 87 //F2 ··4#define NOTE_FS2 93 //F2##define NOTE_G2 98 //G2 ··5#define NOTE_GS2 104 //G2##define NOTE_A2 110 //A2 ··6#define NOTE_AS2 117 //A2##define NOTE_B2 123 //B2 ··7#define NOTE_C3 131 //C3 ·1#define NOTE_CS3 139 //C3##define NOTE_D3 147 //D3 ·2#define NOTE_DS3 156 //D3##define NOTE_E3 165 //E3 ·3#define NOTE_F3 175 //F3 ·4#define NOTE_FS3 185 //F3##define NOTE_G3 196 //G3 ·5#define NOTE_GS3 208 //G3##define NOTE_A3 220 //A3 ·6#define NOTE_AS3 233 //A3##define NOTE_B3 247 //B3 ·7#define NOTE_C4 262 //C4 1(中央C大调)#define NOTE_CS4 277 //C4##define NOTE_D4 294 //D4 2#define NOTE_DS4 311 //D4##define NOTE_E4 330 //E4 3#define NOTE_F4 349 //F4 4#define NOTE_FS4 370 //F4##define NOTE_G4 392 //G4 5#define NOTE_GS4 415 //G4##define NOTE_A4 440 //A4 6#define NOTE_AS4 466 //A4##define NOTE_B4 494 //B4 7#define NOTE_C5 523 //C5 1·#define NOTE_CS5 554 //C5##define NOTE_D5 587 //D5 2·#define NOTE_DS5 622 //D5##define NOTE_E5 659 //E5 3·#define NOTE_F5 698 //F5 4·#define NOTE_FS5 740 //F5##define NOTE_G5 784 //G5 5·#define NOTE_GS5 831 //G5##define NOTE_A5 880 //A5 6·#define NOTE_AS5 932 //A5##define NOTE_B5 988 //B5 7·#define NOTE_C6 1047 //C6 1··#define NOTE_CS6 1109 //C6##define NOTE_D6 1175 //D6 2··#define NOTE_DS6 1245 //D6##define NOTE_E6 1319 //E6 3··#define NOTE_F6 1397 //F6 4··#define NOTE_FS6 1480 //F6##define NOTE_G6 1568 //G6 5··#define NOTE_GS6 1661 //G6##define NOTE_A6 1760 //A6 6··#define NOTE_AS6 1865 //A6##define NOTE_B6 1976 //B6 7··#define NOTE_C7 2093 //C7 1···#define NOTE_CS7 2217 //C7##define NOTE_D7 2349 //D7 2···#define NOTE_DS7 2489 //D7##define NOTE_E7 2637 //E7 3···#define NOTE_F7 2794 //F7 4···#define NOTE_FS7 2960 //F7##define NOTE_G7 3136 //G7 5···#define NOTE_GS7 3322 //G7##define NOTE_A7 3520 //A7 6···#define NOTE_AS7 3729 //A7##define NOTE_B7 3951 //B7 7···#define NOTE_C8 4186 //C8 1····#define NOTE_CS8 4435 //C8##define NOTE_D8 4699 //D8 2····#define NOTE_DS8 4978 //D8#
//(寻线 红外避障 蓝牙遥控 寻光)多功能程序
//***********************定义电机腳位*************************
#include "pitches.h"
int MotorLeft1R = 2;
int MotorLeft1B = 3;
int MotorLeft2R = 5;
int MotorLeft2B = 4;
int MotorRight1R = 10;
int MotorRight1B = 9;
int MotorRight2R = 6;
int MotorRight2B = 7;// 记录曲子的音符
int melody[] = { 0, 0, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_B4, NOTE_D5, NOTE_C5, NOTE_A4, 0, NOTE_C4, NOTE_E4, NOTE_A4, NOTE_B4, 0, NOTE_E4, NOTE_G4, NOTE_B4, NOTE_C5, 0, NOTE_E4, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_D5, NOTE_E5, NOTE_B4, NOTE_D5, NOTE_C5,NOTE_A4, 0, NOTE_C4, NOTE_E4, NOTE_A4, NOTE_B4, 0, NOTE_E4, NOTE_C5, NOTE_B4,NOTE_A4};
// 音符持续时间:4为四分音符,8为八分音符
int noteDurations[] = { 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 4, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 4, 8, 8, 8, 8,4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4};int counter = 0;
char val;
//*************************定义寻线模块脚位************************************
const int SensorLeft = 8;      //左传感器
const int SensorMiddle = 11;   //中传感器
const int SensorRight = 12;     //右传感器
int SL;    //左传感器状态
int SM;    //中传感器状态
int SR;    //右传感器状态const int barrier_left = A5; //左红外避障
const int barrier_right = A4; //右红外避障const int followLight_left = A3; //左寻光
const int followLight_right = A2; //右寻光//********************************************************************(SETUP)
void setup()
{Serial.begin(9600);pinMode(MotorLeft1R,OUTPUT);pinMode(MotorLeft1B,OUTPUT);pinMode(MotorLeft2R,OUTPUT);pinMode(MotorLeft2B,OUTPUT);pinMode(MotorRight1R,OUTPUT);pinMode(MotorRight1B,OUTPUT);pinMode(MotorRight2R,OUTPUT);pinMode(MotorRight2B,OUTPUT);pinMode(SensorLeft, INPUT); //pinMode(SensorMiddle, INPUT);//pinMode(SensorRight, INPUT); //pinMode(barrier_left, INPUT);pinMode(barrier_right, INPUT);pinMode(followLight_left, INPUT);pinMode(followLight_right, INPUT);Serial.println("-----------------");
}
//******************************************************************(Void)
void advance(int a) // 前进
{Serial.println("advance");//直走 1的R为前,2的B为前digitalWrite(MotorLeft1R, HIGH);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, HIGH);digitalWrite(MotorRight1R, HIGH);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, HIGH);delay(a * 100);
}
void right(int b) //右转
{Serial.println("right");//右转(普通)digitalWrite(MotorLeft1R, HIGH);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, HIGH);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, LOW);delay(b * 100);
}
void left(int c) //左转
{Serial.println("left");//左转(普通)digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, HIGH);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, HIGH);delay(c * 100);
}
void turnR(int d) //右转 双轮
{Serial.println("turnR");//右转自旋(快速)digitalWrite(MotorLeft1R, HIGH);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, HIGH);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, HIGH);digitalWrite(MotorRight2R, HIGH);digitalWrite(MotorRight2B, LOW);delay(d * 100);
}
void turnL(int e) //左转 双轮
{Serial.println("turnL");//左转(快速)digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, HIGH);digitalWrite(MotorLeft2R, HIGH);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, HIGH);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, HIGH);delay(e * 100);
}
void stopp(int f) //停止
{Serial.println("stopp");//停止digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, LOW);delay(f * 100);
}
void back(int g) //后退
{Serial.println("back");digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, HIGH);digitalWrite(MotorLeft2R, HIGH);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, HIGH);digitalWrite(MotorRight2R, HIGH);digitalWrite(MotorRight2B, LOW);delay(g * 100);
}
void toR(int v) //右平移
{Serial.println("toR");digitalWrite(MotorLeft1R, HIGH);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, HIGH);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, HIGH);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, HIGH);delay(v * 100);
}
void toL(int x) //左平移
{Serial.println("toL");digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, HIGH);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, HIGH);digitalWrite(MotorRight1R, HIGH);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, HIGH);digitalWrite(MotorRight2B, LOW);delay(x * 100);
}
//******************************************************************************(LOOP)
void loop()
{SL = digitalRead(SensorLeft);SM = digitalRead(SensorMiddle);SR = digitalRead(SensorRight);performCommand();
}void performCommand() 
{if (Serial.available()) {val = Serial.read();}
//**********************红外避障模式if (val == 'q') //红外壁障{while (1){val = Serial.read();if ((digitalRead(barrier_left)==LOW) && (digitalRead(barrier_right)==LOW)){back(3);//后退}else if (digitalRead(barrier_left)==LOW){turnR(3); // 右转;}else if (digitalRead(barrier_right)==LOW){turnL(3); // 左转;}else{advance(3);//前进}if (val == 'a'){digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, LOW);break;} }}
//**********************红外避障模式2if (val == 'p') //红外壁障{while (1){val = Serial.read();if ((digitalRead(barrier_left)==LOW) && (digitalRead(barrier_right)==LOW)){stopp(3);//停止for(int thisNote = 0; thisNote < sizeof(melody)/sizeof(melody[0]); thisNote++) {// 需要根据音符类型换算音符的持续时间int noteDuration = 1000/noteDurations[thisNote];tone(A1, melody[thisNote], noteDuration);// 为了能辨别出不同的音调,需要在两个音调间设置一定的延时,增加30%比较合适int pauseBetweenNotes = noteDuration * 1.30;delay(pauseBetweenNotes);noTone(A1);}}else if (digitalRead(barrier_left)==LOW){turnR(3); // 右转;}else if (digitalRead(barrier_right)==LOW){turnL(3); // 左转;}else{advance(3);//前进}if (val == 'a'){digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, LOW);break;} }}
//**********************寻光模式if (val == 't') {while (1){val = Serial.read();if ((digitalRead(followLight_left)==LOW) && (digitalRead(followLight_right)==LOW)){advance(3);//前进}else if (digitalRead(followLight_left)==LOW){turnL(3); // 左转;}else if (digitalRead(followLight_right)==LOW){turnR(3); // 右转;}else{stopp(3);}if (val == 'a'){digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, LOW);break;} }}//**********************寻线模式if (val == 'd') {while (1){val = Serial.read();{SL = digitalRead(SensorLeft);SM = digitalRead(SensorMiddle);SR = digitalRead(SensorRight);Serial.print(SL);Serial.print("-");Serial.print(SM);Serial.print("-");Serial.println(SR);if (SM == HIGH)//中间传感器检测到黑线  黑线为1 白为0{if (SL == LOW & SR ==  HIGH) //左白右黑, 向右转弯{Serial.println("BL");right(1); // 右转;}else if ( SL ==  HIGH & SR == LOW) // 左黑右白, 向左转弯{Serial.println("BR");left(1); // 左转;}else  // 两侧为白色,前进{Serial.println("Bw");advance(1); //前进;}}else // 中间传感器在白色区域{if (SL == LOW & SR == HIGH ) // 左白右黑, 快速右转{Serial.println("WL");turnR(1);}else if ( SL == HIGH & SR == LOW ) // 左黑右白, 快速左转{Serial.println("WR");turnL(1);}else // 都是白色, 保护不变{Serial.println("ww");}}  }if (val == 'a'){digitalWrite(MotorLeft1R, LOW);digitalWrite(MotorLeft1B, LOW);digitalWrite(MotorLeft2R, LOW);digitalWrite(MotorLeft2B, LOW);digitalWrite(MotorRight1R, LOW);digitalWrite(MotorRight1B, LOW);digitalWrite(MotorRight2R, LOW);digitalWrite(MotorRight2B, LOW);break;} }}
//**********************无源蜂鸣器if (val == 'i') //致爱丽丝{while (1){val = Serial.read();// 遍历整个曲子的音符for(int thisNote = 0; thisNote < sizeof(melody)/sizeof(melody[0]); thisNote++) {// 需要根据音符类型换算音符的持续时间int noteDuration = 1000/noteDurations[thisNote];tone(A1, melody[thisNote], noteDuration);// 为了能辨别出不同的音调,需要在两个音调间设置一定的延时,增加30%比较合适int pauseBetweenNotes = noteDuration * 1.30;delay(pauseBetweenNotes);noTone(A1);}if (val == 'a'){break;} }}//蓝牙控制**********************正常遥控模式if (val == 'f') { // Forwardadvance(10);} else if (val == 'b') { // Backwardback(10);} else if (val == 'r') { // Rightright(10);} else if (val == 'l') { // Leftleft(10);} else if (val == 's') { // Stopstopp(10) ;}else if (val == 'y') { // RightturnR(10);} else if (val == 'z') { // LeftturnL(10);} else if (val == 'v') { // toR(10) ;}else if (val == 'x') { // toL(10) ;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39165.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chatgpt赋能python:Python怎么打竖线:学习竖线在Python中的应用

Python怎么打竖线&#xff1a;学习竖线在Python中的应用 1.引言 Python是和其他编程语言一样有许多基本语法&#xff0c;但是新手可能会遇到某些问题&#xff0c;例如&#xff0c;在Python中如何打竖线&#xff1f;在本篇文章中&#xff0c;我们将介绍如何在Python中打竖线以…

双色球彩票生成之一用户彩票号码随机生成

主要流程如下:1. 使用WinningNumber()方法随机生成一组1-33的红球号码和1-16的蓝球号码,作为中奖号码。2. 同样使用WinningNumber()方法随机生成一组作为用户号码。3. 判断用户号码中红球和蓝球的中奖情况: - 红球判断使用contains()方法检查用户号码的红球是否在中奖号码的…

【用java写的】双色球中奖模拟器

双色球&#xff0c;6个红球&#xff0c;1个蓝球&#xff0c;而且红球中的数据不能重复&#xff0c;红球的数字范围为1-33&#xff0c;蓝球的数字范围为1-16。 然后我们作为彩民&#xff0c;自己买号&#xff0c;在模拟器中则自己依次输入每个球对应的号码&#xff0c;最后开奖…

java案例:模拟双色球中奖

1、双色球系统-业务分析、随机生成一组中奖号码 中奖号码由 6 个红球和 1 个篮球组成 ( 注意&#xff1a; 6 个红球要求不能重复 ) 。 可以定义方法用于返回一组中奖号码(7个数据)&#xff0c;返回的形式是一个整型数组 如何去保证随机的6个中奖的红球号码不重复&#xff1f; …

magento email:发送自定义邮件

邮件是几乎所有电商系统都要用到的功能&#xff0c;在magento中实现简单的邮件发送并不复杂&#xff0c;不过要想用特定邮件模板&#xff0c;就需要对magento邮件系统做一些深入了解&#xff0c;本文就分析一下如何发送自定义邮件。之前已经发了一篇介绍magento基本邮件设置的文…

magento email:快速实现发送自定义邮件

之前介绍了一下稍微复杂一点的 magento email:发送自定义邮件 但是呢&#xff0c;当我们对magento email机制有一定的了解之后&#xff0c;便可以在模块中使用自定义邮件模板快速实现发送邮件功能&#xff01; 登入后台system->Transactional Emails,单击右上角Add New T…

postfix自动搭建邮箱黑科技、邮件群发、批量自建邮局系统

大家好今天给大家分享一个 先进的自建邮箱黑科技&#xff0c;零基础3-5分钟快速搭建几百上千个自建邮箱系统。 软件特点&#xff1a;自动搭建&#xff0c;自动解析&#xff0c;多线程操作 自建邮件系统服务器要求 须开通25端口。另要求必须Centos系统&#xff0c;有固定公网I…

Excel VBA开发自动发送邮件

一、.设置Outlook邮箱帐(略不是本文章的重点) 二、.设置Outlook信任中心如下步骤 若没有做如下操作设置&#xff0c;则Excel VBA调用Outlook自动发送邮件时提示如下 2.1 Outlook->工具->信任中心 2.2 编程访问->选中”从不向我发出可疑活动警告(不推荐)“&#xff0c…

使用Excel和OutLook实现自动发送邮件

参考我的资源: https://download.csdn.net/download/paul50060049/11805973 问题的产生 我们在平时工作中可能会遇到要批量发送邮件的工作&#xff0c;例如财务部根据每个人的工资情况发放工资条到个人的邮箱&#xff0c;因为邮件因人而异&#xff0c;所以需要完成大量而细致…

模拟人生显示无法连接服务器,模拟人生总是显示无法连接网络

模拟人生中不少玩家反馈都会遇到模拟人生总是显示无法连接网络的问题&#xff0c;那么怎么解决这个问题呢&#xff0c;这边ourplay小编为大家分享几个解决方案。 模拟人生游戏简介 《模拟人生移动版》The Sims Mobile)是EA推出的系列作品。玩家可以操作自己的人物完成工作、与他…

编辑合成图片怎么做?手把手教你合成

小伙伴们平时喜欢拍完照片后&#xff0c;将这些照片分享在社交平台上吗&#xff1f;有时我们拍摄的照片会有一些瑕疵&#xff0c;我们可以通过对这些照片进行编辑、合成&#xff0c;以此来填补瑕疵&#xff0c;提高照片的观感。那你们知道如何编辑图片并合成吗&#xff1f;还不…

NFT批量图片合成制作

这是拼接教学&#xff0c;如有兴趣&#xff0c;请扫描底部二维码加群交流 1 按照目前最火的头像来说&#xff0c;一般分为算法生成和拼接图片两种。 2 算法生成相对于普通人来说比较难&#xff0c;拼接图像无疑是一种更好的选择 3 如何批量制作NFT图片呢。 ① 准备组合元素…

chatgpt赋能python:Python图片合成:快速合成图片的最佳选择

Python图片合成&#xff1a;快速合成图片的最佳选择 图片合成是数字图像处理领域的一项关键技术。在很多场景下&#xff0c;我们需要把多个图片合成成一个整体&#xff0c;以达到更好的效果。Python是一种强大而灵活的编程语言&#xff0c;因此也成为了许多开发者进行图片合成…

全民AI计划:通过langchain给LLM接上落地的大腿

langchain是一个开源项目 github.com/hwchase17/l… 。这个项目在GitHub上已经有45.5K个Star了。此项目由一位叫hwchase17的国外小哥在2022年底发布。 我有理由相信&#xff0c;这个项目是为了对接大语言模型才搞的。 一、企业困境: 如何应用大语言模型 大语言模型(Large La…

币圈“土狗”万倍狂欢:一面暴富 一面归零

在币圈&#xff0c;有一类奇葩的虚拟代币项目颇受追捧&#xff0c;人们通常叫它“土狗”。这些项目一般团队匿名&#xff0c;没啥技术含量&#xff0c;强调草根文化&#xff0c;甚至会明说“代币没有价值”。它们身上具有浓厚的meme基因&#xff0c;项目logo有时候就是个表情包…

巴比特 | 元宇宙每日必读:欧洲议会投票通过《人工智能法案》,基础模型供应商要声明训练AI的数据的版权,违规行为或将面临高额罚款...

摘要&#xff1a;据澎湃新闻报道&#xff0c;当地时间6月14日&#xff0c;欧洲议会投票通过了《人工智能法案&#xff08;AI Act&#xff09;》&#xff0c;禁止实时面部识别&#xff0c;并对ChatGPT等生成式人工智能工具提出了新的透明度要求。例如&#xff0c;基础模型的供应…

HTTP文件断点续传原理解析(源码)

生活中&#xff0c;有许多事物&#xff0c;在没有被揭开面纱之前&#xff0c;我们往往会觉得很神秘很高深&#xff0c;认为它一定很难&#xff0c;进而望而却步&#xff0c;失去了解它的机会。然而&#xff0c;很多事&#xff0c;只要我们自己能沉下心来&#xff0c;细细研究&a…

Android断点续传

最近看了一些大佬去面试的时候都提到了断点续传&#xff0c;所以自己也写一个记录下来&#xff0c;断点续传的原理就是通过数据库实时的去保存当前下载的长度&#xff0c;然后下次再次下载的时候通过setRequestProperty告诉服务端我需要这个文件从什么地方开始下载&#xff0c;…

Android笔记--断点续传

断点续传就是在下载资源过程中&#xff0c;网络出现中断后&#xff0c;下一次下载的时候能够接着上一次下载的地方继续下载&#xff0c;以达到节省流量及时间的效果。在Http1.1协议中默认支持获取文件的部分内容&#xff0c;这其中主要是通过头部的两个参数:Range和Content Ran…

Linux断点续传

Linux断点续传 之前使用cp命令拷数据很慢&#xff0c;中途有一次服务器突然关机导致数据拷盘中断&#xff0c;后台发现了rsync命令后速度&#xff0c;工作效率大大提升了。rsync支持断点续传 断点续传测试&#xff1a; rsync -avzP --progress --rshssh /nfs1/public1 root1…