0 前言
?? 這兩年開始畢業(yè)設計和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設題目缺少創(chuàng)新和亮點,往往達不到畢業(yè)答辯的要求,這兩年不斷有學弟學妹告訴學長自己做的項目系統(tǒng)達不到老師的要求。
為了大家能夠順利以及最少的精力通過畢設,學長分享優(yōu)質畢業(yè)設計項目,今天要分享的是
?? 畢業(yè)設計 基于STM32的自動跟隨小車
??學長這里給一個題目綜合評分(每項滿分5分)
- 難度系數(shù):3分
- 工作量:3分
- 創(chuàng)新點:4分
?? 選題指導, 項目分享:
https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%E6%AF%95%E8%AE%BE%E6%8C%87%E5%AF%BC/README.md
1 簡介
自動跟隨小車系統(tǒng)由兩部分組成:跟隨小車和移動目標攜帶裝置。
工作原理:跟隨小車系統(tǒng)通過無線通信模塊發(fā)送尋找信號,同時超聲波接收器開始計時,如果移動目標接收到無線尋找信號,則立即發(fā)送超聲波信號。這樣小車的三角超聲波接收器陸續(xù)收到超聲波信號,CPU通過每個超聲波模塊接收到的時間,計算出移動目標到3個超聲波接收點的距離,通過三邊定位算法即可確定移動目標的位置。如果計算出來的距離大于設定距離,則控制電機向目標方向移動,如果計算出來的距離小于設定距離,則控制電機停止,從而實現(xiàn)小車的自動跟隨功能。
2 主要器件
-
STM32F103RCT6主控單片機
-
NRF2401無線收發(fā)模塊
-
TL852超聲波接收模塊
-
L298N電源模塊
-
電機及電機驅動模塊
-
報警模塊
3 實現(xiàn)效果
4 設計原理
4.1 硬件設計
小車硬件設計:
自動跟隨小車硬件模塊包括控制器模塊、無線收發(fā)模塊、超聲波接收模塊、電機及電機驅動模塊、報警模塊、電源模塊組成,下面對每個模塊做具體介紹。
由于跟隨小車需要進行實時目標位置定位計算、無線信號收發(fā)處理、電機管理、電源管理等任務 ,采用普通單片機其資源及速度難以滿足使用要求,需要高性能DSP處理器才能夠完成,因此選擇STM32F103RCT6作為控制器。
引腳圖
無線收發(fā)是用來實現(xiàn)同步,當小車發(fā)射無線信號,同時人手攜帶裝置接收到無線信號時,人手攜帶裝置發(fā)射超聲波。所以本次設計選用NRF2401做為無線收發(fā)模塊。
NRF2401各引腳功能為:
(1)CSN:芯片的片選線,CSN為低電平工作。
(2)SCK:芯片控制的時鐘線(SPI時鐘)。
(3)MISO:芯片控制數(shù)據(jù)線 。
(4)IRQ:中斷信號,無線通信過程中MCU主要是通過IRQ與NRF2401通信。
(5)CE:芯片的模式控制線。
(6)MOSI:芯片控制數(shù)據(jù)線。
NRF的數(shù)據(jù)收發(fā),是一包一包進行的,一包(幀)數(shù)據(jù):包括了前導碼、目標地址、包控制域、有效數(shù)據(jù)、CRC, 但我們只管有效數(shù)據(jù),其它的不用我們負責,NRF發(fā)送時自動打包,接收到數(shù)據(jù)時自動拆包。
每一包的有效數(shù)據(jù)最大為32個字節(jié)。當然,也可以只發(fā)一個字節(jié)的數(shù)據(jù)。
要發(fā)送的數(shù)據(jù)大于32字節(jié),就要分包進行,自行手動分包處理。
因為在配置部分時,已配置好了頻道,速率,重發(fā)次數(shù)等各種參數(shù),在需要發(fā)送數(shù)據(jù)時,只要往芯片寫入要發(fā)送的數(shù)據(jù)和地址,然后切換為發(fā)送狀態(tài),芯片就會自動發(fā)送。
發(fā)送成功(收到ack),會產生TX_DS中斷。
發(fā)送失敗了(達到最大重發(fā)次數(shù)), 也會產生MAR_RT中斷。
在中斷函數(shù)里,根據(jù)情況作處理就好。
void vNrf24l01_TxPacket(u8 *txbuf)
{
CE_LOW;
Nrf24l01_WriteBuf(W_TX_PAYLOAD, txbuf, 32); // 寫數(shù)據(jù)到TX_BUFF
Nrf24l01_WriteBuf(W_REGISTER+TX_ADDR, (u8*)TX_ADDRESS, 5); // 寫入要發(fā)送的目標地址
Nrf24l01_WriteBuf(W_REGISTER+RX_ADDR_P0, (u8*)TX_ADDRESS, 5); // 通道0的地址設為和目標地址一致,以接收自動回復auto_ack信號
Nrf24l01_WriteReg(W_REGISTER+CONFIG, 0x0E); // 設置為發(fā)送模式,開啟所有中斷
CE_HIGH;
}
TL852超聲波接收模塊
超聲波接收模塊是采用具有單獨接收功能的模塊,如圖所示。其中接收模塊核心部分是由專用超聲波接收集成電路TL852構成的超聲波信號檢測電路,這部分主要完成的是回波的檢測和放大。
直流電機的控制很簡單,性能出眾,直流電源也容易實現(xiàn)。這種直流電機的驅動及控制需要電機驅動模塊進行驅動,采用L298N電源模塊。
系統(tǒng)電源
系統(tǒng)電源采用7.4V可充電鋰電池。7.4V鋰電池組屬于多串并鋰電池組。
目標攜帶裝置硬件設計:
由于跟隨小車需要進行實時目標位置定位計算、無線信號收發(fā)處理、電機管理、電源管理等任務 ,采用普通單片機其資源及速度難以滿足使用要求,需要高性能DSP處理器才能夠完成,因此選擇STM32F103RCT6作為控制器。
無線收發(fā)是用來實現(xiàn)同步,當小車發(fā)射無線信號,同時人手攜帶裝置接收到無線信號時,人手攜帶裝置發(fā)射超聲波。所以本次設計選用NRF2401做為無線收發(fā)模塊。
超聲波發(fā)射模塊是采用具有單獨發(fā)射功能的模塊,如圖所示。其中發(fā)射模塊中的P1 、R4、R5。因為利用了變壓器和發(fā)射頭的諧振,好處是能得到近似正弦波。但附帶的問題是:在驅動信號停止后,由于諧振的原因,發(fā)射頭還會持續(xù)較長時間發(fā)射,直至能量在變壓器的次級線包直流電阻上消耗完,這樣就導致在近距離測量時,回波都到了,余波還未結束,導致測量失敗。所以設計了一個余波抑制電路,將變壓器初級構成回路,利用初級較小的電阻快速消耗掉次級的能量。為此,要多占一個MCU的I/O口。而且,由于驅動電壓的原因,必須使用OC(或者開漏)驅動,否則會無法可靠關斷P1,導致正常發(fā)射不正常。如果測量的距離較遠,或者覺得余波不影響測量,則不必接這個信號。如若使用,一定要注意和發(fā)射驅動信號的配合,不要兩個同時有效,導致發(fā)射效率大減。從原理圖上看,如果要提高驅動能量,可以適當提高驅動電壓,但要要注意MOS管的耐壓只有20V,發(fā)射頭的最高電壓是80V。
文章來源:http://www.zghlxwxcb.cn/news/detail-448965.html
4.2 軟件設計
小車控制流程圖
目標攜帶裝置控制流程圖文章來源地址http://www.zghlxwxcb.cn/news/detail-448965.html
5 部分核心代碼
#define DEBUG 0 // set to 1 to print to serial monitor, 0 to disable
#include <Servo.h>
Servo headservo; //
// Constants
const int EchoPin = 2; //
const int TrigPin = 3; //
const int leftmotorpin1 = 4; //
const int leftmotorpin2 = 5;
const int rightmotorpin1 = 6;
const int rightmotorpin2 = 7 const int HeadServopin = 9; //
const int Sharppin = 11; //
const int maxStart = 800; // run dec time
// Variables
int isStart = maxStart; //
int currDist = 0; //
boolean running = false;
void setup()
{
Serial.begin(9600); //
pinMode(EchoPin, INPUT);
pinMode(Sharppin, INPUT);
for (int pinindex = 3; pinindex < 11; pinindex++)
{
pinMode(pinindex, OUTPUT); // set pins 3 to 10 as outputs
}
//
headservo.attach(HeadServopin);
//
headservo.write(70);
delay(2000);
headservo.write(20);
delay(2000);
}
void loop()
{
if (DEBUG)
{
Serial.print("running:");
if (running)
{
Serial.println("true");
}
else
{
Serial.println("false");
}
}
if (isStart <= 0)
{
if (running)
{
totalhalt(); //
}
int findsomebody = digitalRead(Sharppin);
if (DEBUG)
{
Serial.print("findsomebody:");
Serial.println(findsomebody);
}
if (findsomebody > 0)
{
isStart = maxStart;
}
delay(4000);
return;
}
isStart--;
delay(100);
if (DEBUG)
{
Serial.print("isStart: ");
Serial.println(isStart);
}
currDist = MeasuringDistance(); //
if (DEBUG)
{
Serial.print("Current Distance: ");
Serial.println(currDist);
}
if (currDist > 30)
{
nodanger();
}
else if (currDist < 15)
{
backup();
randTrun();
}
else
{
// whichway();
randTrun();
}
}
/
long MeasuringDistance()
{
long duration;
// pinMode(TrigPin, OUTPUT);
digitalWrite(TrigPin, LOW);
delayMicroseconds(2);
digitalWrite(TrigPin, HIGH);
delayMicroseconds(5);
digitalWrite(TrigPin, LOW);
// pinMode(EchoPin, INPUT);
duration = pulseIn(EchoPin, HIGH) return duration / 29 / 2;
}
//
void nodanger()
{
running = true;
digitalWrite(leftmotorpin1, LOW);
digitalWrite(leftmotorpin2, HIGH);
digitalWrite(rightmotorpin1, LOW);
digitalWrite(rightmotorpin2, HIGH);
return;
}
//
void backup()
{
running = true;
digitalWrite(leftmotorpin1, HIGH);
digitalWrite(leftmotorpin2, LOW);
digitalWrite(rightmotorpin1, HIGH);
digitalWrite(rightmotorpin2, LOW);
delay(1000);
}
//
void whichway()
{
running = true;
totalhalt(); // first stop!
headservo.write(20);
delay(1000);
int lDist = MeasuringDistance(); // check left distance
totalhalt(); //
headservo.write(120); // turn the servo right
delay(1000);
int rDist = MeasuringDistance(); // check right distance
totalhalt(); //
if (lDist < rDist)
{
body_lturn();
}
else
{
body_rturn();
}
return;
}
//
void totalhalt()
{
digitalWrite(leftmotorpin1, HIGH);
digitalWrite(leftmotorpin2, HIGH);
digitalWrite(rightmotorpin1, HIGH);
digitalWrite(rightmotorpin2, HIGH);
headservo.write(70); // set servo to face forward
running = false;
return;
delay(1000);
}
//
void body_lturn()
{
running = true;
digitalWrite(leftmotorpin1, LOW);
digitalWrite(leftmotorpin2, HIGH);
digitalWrite(rightmotorpin1, HIGH);
digitalWrite(rightmotorpin2, LOW);
delay(1500);
totalhalt();
}
//
void body_rturn()
{
running = true;
digitalWrite(leftmotorpin1, HIGH);
digitalWrite(leftmotorpin2, LOW);
digitalWrite(rightmotorpin1, LOW);
digitalWrite(rightmotorpin2, HIGH);
delay(1500);
totalhalt();
}
void randTrun()
{
long randNumber;
randomSeed(analogRead(0));
randNumber = random(0, 10);
if (randNumber > 5)
{
body_rturn();
}
else
{
body_lturn();
}
}
最后
到了這里,關于畢業(yè)設計 基于STM32的自動跟隨小車的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!