前言
??本篇博文介紹的是用51單片機的最終項目《智能語音小車》【中】,包含循跡小車基本原理和方案,根據循跡原理實現循跡功能代碼編寫,解決沖出賽道不轉彎問題,優(yōu)化轉彎平滑。加入電機調速,跟隨小車,搖頭測距小車01_舵機和超聲波封裝,搖頭測距小車02_實現瘋狂搖頭,搖頭測距小車03_測距搖頭,搖頭測距小車04_搖頭測距和行駛bug調試。看到這篇博文的朋友,可以先贊再看嗎?
預備知識
??一、需要我之前寫的所有博文的知識,如果還沒看我之前的的博文,可以去看看后再看本篇博文
??二、C變量
??三、基本輸入輸出
??四、流程控制
??五、函數
??六、指針
??七、字符串
??如果以上知識不清楚,請自行學習后再來瀏覽。如果我有沒例出的,請在評論區(qū)寫一下。謝謝啦!
1.循跡小車基本原理和方案
1.1循跡模塊簡介
??循跡模塊
也叫TCRT5000傳感器
,他的紅外發(fā)射二極管不斷發(fā)射紅外線
,當發(fā)射出的紅外線沒有被反射回來
或被反射回來但強度不夠大
時, 紅外接收管一直處于關斷狀態(tài)
,此時模塊的輸出端為高電平
,指示二極管一直處于熄滅狀態(tài)
。被檢測物體出現在檢測范圍內
時,紅外線被反射回來且強度足夠大
,紅外接收管飽和
,此時模塊的輸出端為低電平
,指示二極管被點亮
??總結:沒反射回來,D0輸出高電平,滅燈
1.2循跡模塊的接線方式
??接線方式
??VCC:
接電源正極(3-5V
)
??GND:
接電源負極
??DO
:TTL開關信號輸出0、1
??AO:
模擬信號輸出(不同距離輸出不同的電壓,此腳一般可以不接
)
1.3循跡小車原理
??由于黑色具有較強的吸收能力,當循跡模塊發(fā)射的紅外線照射到黑線時,紅外線將會被黑線吸收,導致循跡模塊上光敏三極管處于關閉狀態(tài),此時模塊上一個LED熄滅。在沒有檢測到黑線時,模塊上兩個LED常亮
??總結:有感應到黑線,D0輸出高電平 ,滅燈
??循跡模塊安裝在小車車頭兩側
??下方小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
??上方小車左模塊遇到黑線,紅外被吸收,左模塊輸出高電平,右模塊輸出低電平,左轉,反之右轉
2.根據循跡原理實現循跡功能代碼編寫
2.1根據循跡原理實現循跡功能代碼編寫核心思路
-
在主C文件中聲明循跡模塊所需引腳
-
在主C文件while(1)死循環(huán)內進行循跡模塊返回數據判斷,并執(zhí)行相應代碼
-
通過智能小車賽道驗證代碼可信性
??注:此程序基于電機相關代碼封裝_分文件工程
開發(fā)
2.2在主C文件中聲明循跡模塊所需引腳
- 左輪循跡模塊接單片機
P2.7
口,右輪循跡模塊接單片機P2.6
口。 - 代碼體現
sbit leftTracking = P2^7; //左邊輪子的循跡模塊接單片機P2.7口
sbit rightTracking = P2^6; //右邊輪子的循跡模塊接單片機P2.6口
2.3在主C文件while(1)死循環(huán)內進行循跡模塊返回數據判斷,并執(zhí)行相應代碼
- 根據1.3的結論進行對循跡模塊的判斷。
- 代碼體現
f(leftTracking==0 && rightTracking==0)
{
goFront();
}
//上方小車左模塊遇到黑線,紅外被吸收,左模塊輸出高電平,右模塊輸出低電平,左轉,反之右轉
if(leftTracking==1 && rightTracking==0)
{
goLeft();
}
if(leftTracking==0 && rightTracking==1)
{
goRight();
}
if(leftTracking==1 && rightTracking==1)
{
stop();
}
- 在motor.c文件中封裝停止函數
??封裝思路:將左右輪變量賦0即可停止
??代碼體現:
void stop()
{
RightControA = 0;
RightControB = 0;
LeftControA = 0;
LeftControB = 0;
}
- 在motor.h文件中聲明stop函數
void goLeft();
void goRight();
void goBack();
void goFront();
void stop();
- 主C文件代碼為
#include "motor.h"
#include "delay.h"
#include "reg52.h3"
sbit leftTracking = P2^7; //左邊輪子的循跡模塊接單片機P2.7口
sbit rightTracking = P2^6; //右邊輪子的循跡模塊接單片機P2.6口
void main()
{
while(1)
{
//下方小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
if(leftTracking==0 && rightTracking==0)
{
goFront();
}
//上方小車左模塊遇到黑線,紅外被吸收,左模塊輸出高電平,右模塊輸出低電平,左轉,反之右轉
if(leftTracking==1 && rightTracking==0)
{
goLeft();
}
if(leftTracking==0 && rightTracking==1)
{
goRight();
}
if(leftTracking==1 && rightTracking==1)
{
stop();
}
}
}
2.4通過智能小車賽道驗證代碼可信性
- 賽道建設建議
??材料可以準備A4紙(可用作業(yè)本沒寫過的背面替代),黑色電工膠布,白色紙膠布或者白色電工膠布。
??將A4紙縱向拼接在一起,紙與紙之間用白色紙腳布或者白色電工膠布粘住。最后構成一個矩形即可。
??在構成的矩形邊中間位置貼黑色電工膠布,拐彎處注意圓角處理。這樣賽道就完工了。
??使用時找重物按住即可
- 智能小車賽道驗證結果
??當把小車放在賽道上時,小車能走直線,但拐彎會跑出賽道。原因有兩個:
??一、小車速度過快
??二、循跡模塊太靈敏,很容易接收地面反光。
??解決辦法:
??一、使用PWM調速使小車減速通過彎道
??二、通過調節(jié)循跡模塊上的十字電位器,調低靈敏度
3.解決沖出賽道不轉彎問題,優(yōu)化轉彎平滑。加入電機調速
3.1解決沖出賽道不轉彎問題,優(yōu)化轉彎平滑。加入電機調速核心思路
- 在主C文件中添加左右輪循跡模塊聲明
- 在主C文件主函數內添加判斷左右循跡模塊返回參數判斷并設置左右輪轉速。
- 調試優(yōu)化,使小車循跡
??注:此程序基于左右電機的各自調速管理工程
開發(fā)
3.2在主C文件中添加左右輪循跡模塊聲明
- 代碼聲明
sbit leftTracking = P2^7; //左邊輪子的循跡模塊接單片機P2.7口
sbit rightTracking = P2^6; //右邊輪子的循跡模塊接單片機P2.6口
3.3在主C文件主函數內添加判斷左右循跡模塊返回參數判斷并設置左右輪轉速。
- 判斷循跡模塊返回參數思路和1.3一樣
- 代碼體現
while(1)
{
//下方小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
if(leftTracking==0 && rightTracking==0)
{
speedRight = 25;
speedLeft = 25;
}
//上方小車左模塊遇到黑線,紅外被吸收,左模塊輸出高電平,右模塊輸出低電平,左轉,反之右轉
if(leftTracking==1 && rightTracking==0)
{
speedLeft = 10;
speedRight = 40;
}
if(leftTracking==0 && rightTracking==1)
{
speedLeft = 40;
speedRight = 10;
}
if(leftTracking==1 && rightTracking==1)
{
speedLeft = 0;
speedRight = 0;
}
}
- 主C文件代碼
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time0.h"
#include "time1.h"
#include "reg52.h"
extern char speedRight;
extern char speedLeft;
sbit leftTracking = P2^7; //左邊輪子的循跡模塊接單片機P2.7口
sbit rightTracking = P2^6; //右邊輪子的循跡模塊接單片機P2.6口
void main()
{
initTime0();
initTime1();
UartInit();
while(1)
{
//下方小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
if(leftTracking==0 && rightTracking==0)
{
speedRight = 25;
speedLeft = 25;
}
//上方小車左模塊遇到黑線,紅外被吸收,左模塊輸出高電平,右模塊輸出低電平,左轉,反之右轉
if(leftTracking==1 && rightTracking==0)
{
speedLeft = 10;
speedRight = 40;
}
if(leftTracking==0 && rightTracking==1)
{
speedLeft = 40;
speedRight = 10;
}
if(leftTracking==1 && rightTracking==1)
{
speedLeft = 0;
speedRight = 0;
}
}
}
3.4調試優(yōu)化,使小車循跡
- 調試思路
??沖出地圖可以通過增大左右輪轉向差數來解決,直線走不直可以通過調劑走直線左右輪速度變量控制左右輪速。
- 調試結果
??一、地圖長這樣,和2.4的賽道有所區(qū)別,這版賽道我采用紙板,上面用毛筆蘸墨水畫出賽道即可。
??二、調試結果為設置小車直線行駛時左右輪速為35,拐彎輪速差為30。即可完美實現循跡。
??三、調試后的代碼
#include "motor.h"
#include "delay.h"
#include "uart.h"
#include "time0.h"
#include "time1.h"
#include "reg52.h"
extern char speedRight;
extern char speedLeft;
sbit leftTracking = P2^7; //左邊輪子的循跡模塊接單片機P2.7口
sbit rightTracking = P2^6; //右邊輪子的循跡模塊接單片機P2.6口
void main()
{
initTime0();
initTime1();
UartInit();
while(1)
{
//下方小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
if(leftTracking==0 && rightTracking==0)
{
speedRight = 35;
speedLeft = 35;
}
//上方小車左模塊遇到黑線,紅外被吸收,左模塊輸出高電平,右模塊輸出低電平,左轉,反之右轉
if(leftTracking==1 && rightTracking==0)
{
speedLeft = 10;
speedRight = 40;
}
if(leftTracking==0 && rightTracking==1)
{
speedLeft = 40;
speedRight = 10;
}
if(leftTracking==1 && rightTracking==1)
{
speedLeft = 0;
speedRight = 0;
}
}
}
4.跟隨小車
4.1跟隨小車實現原理
- 跟隨小車實現原理和1.1一樣,只不過傳感器探頭朝外。
-
跟隨小車跟隨原理:
左邊跟隨模塊能返回紅外,輸出低電平,右邊不能返回,輸出高電平,說明物體在左邊,需要左轉
;右邊跟隨模塊能返回紅外,輸出低電平,左邊不能返回,輸出高電平,說明物體在右邊,需要右轉
。
4.2跟隨小車代碼實現
- 基于
根據循跡原理實現循跡功能代碼編寫工程
開發(fā) - 跟隨算法實現代碼
while(1)
{
//小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
if(leftFollow==0 && rightFollow==0)
{
goFront();
}
//右邊跟隨模塊能返回紅外,輸出低電平,左邊不能返回,輸出高電平,說明物體在右邊,需要右轉
if(leftFollow==1 && rightFollow==0)
{
goRight();`
}
//左邊跟隨模塊能返回紅外,輸出低電平,右邊不能返回,輸出高電平,說明物體在左邊,需要左轉
if(leftFollow==0 && rightFollow==1)
{
goLeft();
}
if(leftFollow==1 && rightFollow==1)
{
stop();
}
}
- 主C文件代碼
#include "motor.h"
#include "delay.h"
#include "reg52.h"
//sbit leftTracking = P2^7; //左邊輪子的循跡模塊接單片機P2.7口
//sbit rightTracking = P2^6; //右邊輪子的循跡模塊接單片機P2.6口
sbit leftFollow = P2^5; //左邊輪子的跟隨模塊接單片機P2.5口
sbit rightFollow = P2^4; //右邊輪子的跟隨模塊接單片機P2.4口
void main()
{
while(1)
{
//小車兩個模塊都能反射回來紅外,輸出低電平,燈亮,直走
if(leftFollow==0 && rightFollow==0)
{
goFront();
}
//右邊跟隨模塊能返回紅外,輸出低電平,左邊不能返回,輸出高電平,說明物體在右邊,需要右轉
if(leftFollow==1 && rightFollow==0)
{
goRight();`
}
//左邊跟隨模塊能返回紅外,輸出低電平,右邊不能返回,輸出高電平,說明物體在左邊,需要左轉
if(leftFollow==0 && rightFollow==1)
{
goLeft();
}
if(leftFollow==1 && rightFollow==1)
{
stop();
}
}
}
4.3跟隨紅外模塊使用注意事項
在關閉窗簾的室內使用,因為陽光中有部分紅外線,會導致模塊異常,實驗結果出錯。
5.搖頭測距小車01_舵機和超聲波封裝
5.1搖頭測距小車01_舵機和超聲波封裝核心思路
- 分別建立
hc04.c
,hc04.h
,delay.c
,delay.h
,sg90.c
,sg90.h
文件 - 拷貝以上相應代碼去相應文件
- 在主C文件和其他文件中調用相應的.h文件。
??注:此程序基于感應開關蓋垃圾桶項目_實現距離感應開蓋工程
開發(fā)
5.2分別建立hc04.c,hc04.h,delay.c,delay.h,sg90.c,sg90.h文件
- 建立的文件如下:
5.3拷貝以上相應代碼去相應文件
- hc04.c對應代碼為
#include "reg52.h"
#include "delay.h"
sbit Trig = P2^3; //超聲波測距的控制Trig接單片機2.3口
sbit Echo = P2^2; //超聲波測距的控制Echo接單片機2.2口
void startHC() //給超聲波模塊控制為Trig一個10us的觸發(fā)信息
{
Trig = 0;
Trig = 1;
Delay10us();
Trig = 0;
}
void initTime1() //設置定時器T0為16位模式,從0開始數數,不忙啟動定時器
{
TMOD &= 0x0F;
TMOD |= 0x10;
TL1 = 0;
TH1 = 0;
}
double getDistance()
{
double time;
//重新給初值,重新計時
TL1 = 0;
TH1 = 0;
//1.Trig ,給Trig端口至少10us的高電平
startHC();
//2.Echo信號,由低電平跳轉到高電平,表示開始發(fā)送波
while(Echo == 0);
// 波發(fā)出去的那一下,開始啟動定時器
TR1 = 1; //啟動定時器T0
//3.Echo,由高電平跳轉回低電平,表示波回來了
while(Echo == 1);
// 波回來的那一下,我們開始停止定時器,計算出中間經過多少時間
TR1 = 0; //關閉定時器
time = ((TH1 * 256) + TL1)*1.085; //單位為us。
/*
256的含義:
對于十進制數2向左移一位位20,相當于乘以10
那么對于二進制數2向左移移一位,相當于乘以2。移動8位,乘以2的8次方256
*/
//4.距離 = 速度 (340m/s)* 時間/2
//dis = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us
//dis = 0.034 * time/2; <==> 0.017*time;
return (0.017 * time);
}
- hc04.h對應代碼為
void initTime1();
double getDistance();
- delay.c對應代碼為
void Delay10us() //@11.0592MHz 軟件延時10us
{
unsigned char i;
i = 2;
while (--i);
}
void Delay2000ms() //@11.0592MHz 軟件延時2秒
{
unsigned char i, j, k;
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 軟件延時300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
- delay.h對應代碼為
void Delay10us();
void Delay2000ms();
void Delay150ms();
void Delay300ms();
- sg90.c對應代碼為
#include "reg52.h"
#include "delay.h"
sbit D5 = P3^7; //根據原理圖D5 led燈接單片機3.7口
sbit D6 = P3^6; //根據原理圖D6 led燈接單片機3.6口
sbit sg90_con = P1^1; //sg90舵機PWM控制線接單片機P1.1口,用于模擬PWM波形。
char cnt = 0; //記錄爆表次數
char angle; //記錄舵機角度變量
void initTime0() //初始化定時器T0
{
//1.設置定時器為T0,16位模式
TMOD &= 0xF0;
TMOD |= 0x01;
//2.設置初值,定時0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//3.啟動定時器,開始計時
TR0 = 1; //TR0為啟動定時器標志,值為1啟動定時器
TF0 = 0;
//4.打開定時器0的中斷 賦1打開
ET0 = 1;
//5.打開總中斷EA 賦1打開
EA = 1;
}
void initSG90_0() //SG90舵機初始化函數。
{
sg90_con = 1; //單片機上電,給sg90舵機控制線一個高電平。
angle = 1; //給角度控制變量初始化為0度,因為0.5毫秒的高電平PWM波為0度,angle = 1;時定時器剛好定時0.5毫秒
cnt = 0; //初始化爆表變量
}
void openCoverLight() //開蓋燈的狀態(tài)
{
D5 = 0;
D6 = 1;
}
void closeCoverLight() //關蓋垃圾桶的狀態(tài)
{
D5 = 1;
D6 = 0;
}
void openCoverDustbin() //垃圾桶開蓋函數
{
angle = 3; //舵機開蓋
cnt = 0;
Delay2000ms();
}
void closeCoverDustbin()//垃圾桶關蓋函數
{
angle = 1; //舵機關蓋
cnt = 0;
Delay150ms();
}
void Time0Handler() interrupt 1 //定時器T0中斷函數,中斷號為interrupt 1
{
cnt++;
//重新給定時器賦初值,定時0.5毫秒
TL0 = 0x33;
TH0 = 0xFE;
//判讀記錄爆表變量cnt的值是否小于角度變量的值,小于繼續(xù)給sg90舵機控制線高電平,大于等于則給低電平
if(cnt < angle)
{
sg90_con = 1;
}
else
{
sg90_con = 0;
}
//判斷cnt是否加到40,定時是否20毫秒PWM波形周期
if(cnt == 40)
{
cnt = 0; //定時到20豪秒,cnt從0開始加
sg90_con = 1;//定時到20豪秒,重新給舵機控制線一個高電平
}
}
- sg90.h對應代碼為
void initTime0(); //初始化定時器T0
void initSG90_0(); //SG90舵機初始化函數。
void openCoverLight(); //開蓋燈的狀態(tài)
void closeCoverLight(); //關蓋垃圾桶的狀態(tài)
void openCoverDustbin(); //垃圾桶開蓋函數
void closeCoverDustbin();//垃圾桶關蓋函數
5.4在主C文件和其他文件中調用相應的.h文件。
- 主C文件中調用的.h文件
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
- hc04.c文件中調用的.h文件
#include "reg52.h"
#include "delay.h"
- sg90.c文件中調用的.h文件
#include "reg52.h"
#include "delay.h"
- 主C文件代碼
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
/*
時間: 2023年10月4日14:00:24
程序功能:垃圾桶03實現距離感應開蓋
注意:一定要在魔術手中Output內勾選輸出Hex文件,不然代碼無效,執(zhí)行其他代碼。
*/
void main()
{
double dis;
Delay300ms();
initTime0();
initTime1();
initSG90_0();
while(1)
{
dis = getDistance(); //超聲波測距
if(dis < 10)
{
openCoverLight(); //開蓋,D5亮
openCoverDustbin();
}
else
{
closeCoverLight(); //關蓋,D5滅
closeCoverDustbin();
}
}
}
6.搖頭測距小車02_實現瘋狂搖頭
6.1搖頭測距小車02_實現瘋狂搖頭核心思路
- 修改關蓋函數
closeCoverDustbin();
為sg90Right()
。修改開蓋函數openCoverDustbin();
為sg90Middle();
- 增加
sg90Left();
函數 - 主C文件修改初識位置為
中間
;while(1)死循環(huán)中給予適度延時
調用右
、中
、左
、中
、sg90函數。
6.2修改關蓋函數closeCoverDustbin();為sg90Right()。修改開蓋函數openCoverDustbin();為sg90Middle();
- 修改關蓋函數
closeCoverDustbin();
為sg90Right();
修改前
void closeCoverDustbin()//垃圾桶關蓋函數
{
angle = 1; //舵機關蓋
cnt = 0;
Delay150ms();
}
修改后(去掉延時,不然在最終呈現時會影響結果)
void sg90Right()//垃圾桶關蓋函數
{
angle = 1; //舵機關蓋
cnt = 0;
}
- 修改開蓋函數
openCoverDustbin();
為sg90Middle();
修改前
void openCoverDustbin() //垃圾桶開蓋函數
{
angle = 3; //舵機開蓋
cnt = 0;
Delay2000ms();
}
修改后(去掉延時,不然在最終呈現時會影響結果)
void sg90Middle() //垃圾桶開蓋函數
{
angle = 3; //舵機開蓋
cnt = 0;
}
6.3增加sg90Left();函數
- 角度變量設置成5,sg90舵機轉動180度。
- 代碼體現
void sg90Left()//
{
angle = 5; //旋轉180度
cnt = 0;
}
- 在sg90.h文件中添加sg90左、右、中函數聲明
void sg90Middle(); //垃圾桶開蓋函數
void sg90Right();//垃圾桶關蓋函數
void sg90Left();
- sg90.h文件代碼。
void initTime0(); //初始化定時器T0
void initSG90_0(); //SG90舵機初始化函數。
void openCoverLight(); //開蓋燈的狀態(tài)
void closeCoverLight(); //關蓋垃圾桶的狀態(tài)
void sg90Middle(); //垃圾桶開蓋函數
void sg90Right();//垃圾桶關蓋函數
void sg90Left();
6.4主C文件修改初識位置為中間;while(1)死循環(huán)中給予適度延時調用右、中、左、中、sg90函數。
- 初始化位置為中間后延時1秒。
sg90Middle();
Delay1000ms();
- while(1)死循環(huán)中給予
600ms
延時調用右、中、左、中、sg90函數最為適合。
while(1)
{
sg90Right();
Delay600ms();
sg90Middle();
Delay600ms();
sg90Left();
Delay600ms();
sg90Middle();
Delay600ms();
}
- 主C文件代碼
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
/*
時間: 2023年10月4日14:00:24
程序功能:垃圾桶03實現距離感應開蓋
注意:一定要在魔術手中Output內勾選輸出Hex文件,不然代碼無效,執(zhí)行其他代碼。
*/
void main()
{
Delay300ms();
initTime0();
initTime1();
sg90Middle();
Delay1000ms();
while(1)
{
sg90Right();
Delay600ms();
sg90Middle();
Delay600ms();
sg90Left();
Delay600ms();
sg90Middle();
Delay600ms();
}
}
- delay.c和delay.h文件代碼
#include "intrins.h"
void Delay10us() //@11.0592MHz 軟件延時10us
{
unsigned char i;
i = 2;
while (--i);
}
void Delay2000ms() //@11.0592MHz 軟件延時2秒
{
unsigned char i, j, k;
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay150ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 2;
j = 13;
k = 237;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay300ms() //@11.0592MHz 軟件延時300毫秒
{
unsigned char i, j, k;
i = 3;
j = 26;
k = 223;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay600ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 5;
j = 52;
k = 195;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10us();
void Delay2000ms();
void Delay150ms();
void Delay300ms();
void Delay600ms();
void Delay1000ms();
7.搖頭測距小車03_測距搖頭
7.1搖頭測距小車03_測距搖頭核心思路
??在主C文件中設計算法,前方距離小于35厘米就左右兩邊都測一下距離。距離大于35厘米就前進。
7.2算法設計思路
- 在主C文件的主函數中一上電就讓測距模塊在中間位置,在
while(1)
死循環(huán)中先測正前面的距離,距離大于35厘米
就直走,距離小于35厘米
就左邊測,然后右邊測,最后回中。具體請看程序代碼。
sg90Middle();
Delay1000ms();
while(1)
{
disMiddle = getDistance(); //先測中間
if(disMiddle > 35) //如果中間距離大于35厘米就前進
{
//前進
}
else //否則就搖頭
{
sg90Left(); //轉左邊
disLeft = getDistance(); //測左邊
Delay600ms(); //等待600毫秒
sg90Middle(); //轉中間
Delay600ms(); //等待600毫秒
sg90Right(); //轉右邊
disRight = getDistance(); //測右邊
Delay600ms(); //等待600毫秒
}
sg90Middle(); //回到中間
Delay600ms(); //等待600毫秒
}
??這樣的代碼驗證后,sg90Middle();//回到中間 Delay600ms();//等待600毫秒;
這兩句會出現舵機在中間抽搐。原因是當距離大于35厘米時會一直調用轉向中間函數,但此時處于中間位置,所以會出現抽搐。
??解決辦法為定義標志位來控制
- 建立轉向位置位置變量算法思路:定義轉向位置變量宏,當初始化為中間的時候記錄中間位置,在
while(1)
死循環(huán)內進行位置判斷,如果位置不是中間位置,就回到中間,在中間位置就不做任何操作。
#define MIDDLE 0 //定義中間位置宏
#define RIGHT 1 //定義右邊位置宏
#define LEFT 2 //定義左邊位置宏
sg90Middle();
dir = MIDDLE; //記錄中間位置
Delay1000ms();
disMiddle = getDistance(); //先測中間
if(dir != MIDDLE) //方向不在中間會中
{
sg90Middle(); //回中
Delay600ms();
dir = MIDDLE; //軟件初始化
}
if(disMiddle > 35) //如果中間距離大于35厘米就前進
{
//前進
}
else //否則就搖頭
{
sg90Left(); //轉左邊
disLeft = getDistance(); //測左邊
Delay600ms(); //等待600毫秒
sg90Middle(); //轉中間
Delay600ms(); //等待600毫秒
sg90Right(); //轉右邊
disRight = getDistance(); //測右邊
dir = RIGHT; //記錄末位置
Delay600ms(); //等待600毫秒
}
7.3完整主C文件代碼
#include "reg52.h"
#include "hc04.h"
#include "delay.h"
#include "sg90.h"
#define MIDDLE 0 //定義中間位置宏
#define RIGHT 1 //定義右邊位置宏
#define LEFT 2 //定義左邊位置宏
/*
時間: 2023年10月4日14:00:24
程序功能:垃圾桶03實現距離感應開蓋
注意:一定要在魔術手中Output內勾選輸出Hex文件,不然代碼無效,執(zhí)行其他代碼。
*/
void main()
{
double disMiddle; //中間距離變量
double disLeft; //左邊距離變量
double disRight; //右邊距離變量
char dir; //轉頭標志位變量
Delay300ms();
initTime0();
initTime1();
sg90Middle();
dir = MIDDLE; //記錄中間位置
Delay1000ms();
//Delay600ms();
while(1)
{
disMiddle = getDistance(); //先測中間
if(dir != MIDDLE) //方向不在中間會中
{
sg90Middle(); //回中
Delay600ms();
dir = MIDDLE; //軟件初始化
}
if(disMiddle > 35) //如果中間距離大于35厘米就前進
{
//前進
}
else //否則就搖頭
{
sg90Left(); //轉左邊
disLeft = getDistance(); //測左邊
Delay600ms(); //等待600毫秒
sg90Middle(); //轉中間
Delay600ms(); //等待600毫秒
sg90Right(); //轉右邊
disRight = getDistance(); //測右邊
dir = RIGHT; //記錄末位置
Delay600ms(); //等待600毫秒
}
/*
驗證后,這兩句會出現舵機在中間抽搐。
原因是當距離大于35厘米時會一直調用轉向中間函數,但此時處于中間位置,所以會出現抽搐。
解決辦法為定義標志位來控制
sg90Middle(); //回到中間
Delay600ms(); //等待600毫秒
*/
}
}
8.搖頭測距小車04_搖頭測距和行駛bug調試
8.1搖頭測距小車04_搖頭測距和行駛核心思路
- 在7.3代碼中添加判斷轉向代碼
- 在轉向代碼中操控LED燈已驗證是否進入判斷執(zhí)行方便調試
8.2在7.3代碼中添加判斷轉向代碼
轉向思路:當左邊的距離小于右邊的距離時,右轉一段距離,使用延時函數,延時300毫秒適合我的地圖。當右邊的距離小于左邊的距離時,左轉一段距離,也延時300毫秒。
- 轉向代碼
if(disLeft < disRight) //左邊小于右邊,向右轉
{
goRight();
Delay300ms();
stop();
}
if(disRight < disLeft ) //左邊大于右邊,向左轉
{
goLeft();
Delay300ms();
stop();
}
- 地圖照片
8.3在轉向代碼中操控LED燈已驗證是否進入判斷執(zhí)行方便調試
- 聲明LED燈地址
右轉指示燈
sbit D1 = P3^7;
左轉指示燈
sbit D2 = P3^6;
- 主C文件主函數一開始就初識化指示燈
初始化熄滅
D1 = 1;
D2 = 1;
- 左右轉功能中使用LED燈
if(disLeft < disRight) //左邊小于右邊,向右轉
{
D1 = 0;
goRight();
Delay300ms();
//Delay200ms();
stop();
D1 = 1;
}
if(disRight < disLeft ) //左邊大于右邊,向左轉
{
D2 = 0;
goLeft();
Delay300ms();
//Delay200ms();
stop();
D2 = 1;
}
8.4 Bug調試
Bug1:
小車直沖撞墻,不左右轉也不后退。
??解決辦法:添加后退代碼,距離小于10厘米就后退一定距離,指導距離大于10厘米。
if(disMiddle > 30) //如果中間距離大于30厘米就前進
{
//前進
goFront();
}
else if(disMiddle < 10)
{
goBack();
}
else
Bug2
:小車待在原地轉頭
??解決辦法:我開始以為是超聲波測距沒有測到數據,于是對美測到距離的情況做判斷,可是實驗后并沒有解決待在原地不動轉頭。也沒有進入代碼程序,我想是不是左右距離一樣導致無法判斷,可是相應代碼后還未解決。于是我試了很久很久,浪費了很多時間。終于我看到電機轉動開始不怎么轉了,想到可能是電池沒電了。于是我用充電寶供電,一下子就又可以使用了。而且算法沒一點矛盾。
??所以在調試小車時一定要記得檢測電源是否電量充足。
文章來源:http://www.zghlxwxcb.cn/news/detail-834466.html
結束語
??很高興您能看到這里,點個贊再走唄。謝謝您啦!??!文章來源地址http://www.zghlxwxcb.cn/news/detail-834466.html
到了這里,關于“無限交互,全新駕駛體驗!智能語音小車,與您共同開創(chuàng)未來出行?!?51單片機最終項目《智能語音小車》【中】的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!