Arduino智能避障小車避障程序匯編
首先建立一個名為modulecai.ino的主程序。/ modulecar.iiio,玩轉智能小車主程序*include <Senro.h> /導入舵機庫#iiiclude <NewPmg.h> 導入 NwePmg 庫/對照系統配線方案依次指定各I/Oconst mt ENA = 3 ; /左電機 PWMconst int INI = 4 ; 左電機正const mt IN2 = 5 ; 左電機負const mt ENB = 6 ; 右電機 PWMconst mt IN3 = 7 ”右電機正const mt IN4 = 8 ”右電機負const mt trigger = 9 ; 定義超聲波傳感器發(fā)射腳為D9const int echo = 10 ; /定義傳感器接收腳為D10const int maxead = 300; 設定傳感器最大探測距離。int no_good = 35; /* 設定 35cm 警戒距離。int read_aliead; 實際距離讀數。Seivo sensoiStation; 設定傳感器平臺。NewPmg sensor(tngger, echo, maxead); 設定傳感器弓|腳和最大讀數 系統初始化void setupQ(Senal.begin(9600); 啟用串行監(jiān)視器可以給調試帶來極大便利sensorStation.attach(l 1); /IE Dll 分配給舵機pmMode(ENA, OUTPUT); 依次設定各 I O 屬性puiMode(INl, OUTPUT);puiMode(IN2, OUTPUT);pmMode(ENB, OUTPUT);puiMode(IN3, OUTPUT);puiMode(IN4, OUTPUT);puiMode(Uigger, OUTPUT);puiMode(echo, INPUT);sensorStation.wnte(90); 舵機更位至 90 1delay(6000); 上電等待6s后進入主循環(huán)主程序void loopQ(read_aliead = readDistanceO; 調用 readDistance。函數讀出前方距離Serial.printlii(H AHEAD:");Senal.pnntln(read_ahead); 串行監(jiān)視器顯示機器人前方距離if (read_aliead < no_good) /如果前方距離小于警戒值(fastStopO; 就令機器人緊急剎車waTchO; 然后左右查看,分析得出最佳路線goFofwaidO;"*此處調用看似多余,但可以確保機器人高速運轉下動作的連貫性else goFoiwa】d0; 否則就一直向前行駛主程序用到了兩個庫,Sezo庫是IDE自帶的,NwePing庫是第三方庫,需要下載安裝。接下來建立一個名為move. mo的標簽。/move.iiio,機動模塊。剎車void fastStopQ(SeriaLprintln(“STOP");串行監(jiān)視器顯示機器人狀態(tài)為STOP (停止)左電機急停(注:L298N和L293D均帶有剎車功能,在使能成立的條件下,同時向兩 相寫入高電平可令電機急停,詳見芯片手冊)digitalWrite(ENA, HIGH);digitalWnte(INh HIGH);digitalWnte(IN2, HIGH);右電機急停digitalWrite(ENB, HIGH);digitalWnte(IN3, HIGH);digitalWnte(IN4, HIGH);前進void goFoiwaidQ(Senal.pnntlnCTORWARD) 串行監(jiān)視器顯示機器人狀態(tài)為FORWARD (前進)左電機逆時針旋轉analogWnte(ENA,106); 左電機PWM,可微調這個數值使小車左右兩側車輪轉速相等,右 電機同理digitalWnte(INl, LOW);digitalWnte(IN2, HIGH);右電機順時針旋轉analog Write(ENBJ 18);digitalWnte(IN3, HIGH);digitalWnte(IN4, LOW);原地左轉void mniLeftQ(Senal.pimtln(“LEFT"); 串行監(jiān)視器顯示機器人狀態(tài)為LEFT (向左轉)左電機正轉analogWrite(ENA, 106);digitalWnte(INh HIGH);digitalWnte(IN2, LOW);右電機正轉analogWnte(ENB,59);*微調這個數值,使轉彎時內側車輪起主導作用。相當于讓小車向后 打一把輪再拐彎。右轉同理digitalWrite(IN3, HIGH);digitalWnte(IN4, LOW);delay(205);*延遲,數值以亳秒為單位,調節(jié)此值可使機器人動作連貫 原地右轉void tuniRight() (Senal.pnntln("RIGHT) 串行監(jiān)視器顯示機器人狀態(tài)為RIGHT (向右轉) 左電機反轉analogWrite(ENA,53);digitalWnte(INh LOW);digitalWnte(IN2, HIGH);右電機反轉analog Write(ENB J18);digitalWnte(IN3, LOW);digitalWnte(IN4, HIGH);delay (205); *調節(jié)此值可使機器人動作連貫 原地掉頭(暫時用不到)void tuniAioundQ (Senal.pnnthi(HTURN 180) 串行監(jiān)視器顯示機器人狀態(tài)為TURN 180 (原地順時針旋轉 1800 )左電機反轉analogWrite(ENA, 106);digitalWnte(INh LOW);digitalWnte(IN2, HIGH);右電機反轉analog Write(ENB J18);digitalWnte(IN3, LOW);digitalWnte(IN4, HIGH); delay (500); /*)/pmg.ino,測距模塊 mt readDistanceQdelay(30);聲波發(fā)送間隔30ms,大約每秒探測33次。受系統所限,此值不可小于29msint cm = sensoi.ping0 / US_ROUNDTRIP_CM; 把 Ping 值(Us)轉換為 cmretuin(cm); 1eadDistance()返回的數值是 cm 最后是驅動云臺掃描并分析左右兩側距離的watch.ino模塊。/ watch.ino,查看模塊void waTch()(測量右前方距離。/*注意舵機旋轉方向,SG5010為逆時針旋轉sensoiStation.write(20);*舵機右轉至20。調節(jié)此值會影響傳感器掃描區(qū)域,夾角越小, 機器人轉彎越謹慎delay(1200); 延遲1.2s待舵機穩(wěn)定mt read_right = ieadDistance(); 調用】eadDistance()函數讀出右前方距離Senal.pnnt(”RIGHT);Senal.piintlii(reacl_nglit);sensorStation.write(90); *舵機更位至90度。廉價舵機大角度旋轉會產生抖動,要加上這 兩行以求讀數準確。/delay (500); 延遲 0.5s測量左前方距離sensoiStation.wiite(160); /舵機左轉至 1601delay(1200); /延遲L2s待舵機穩(wěn)定。mt readeft = leadDistanceO; 調用函數讀出距離左前方距離。Senal.pnnt("LEFT:Senal.piintlii(read_left);sensorStation.wnte(90); 這一行確保只要小車處于行駛狀態(tài),傳感器就面向正前方delay (500); /延遲 0.5s。/分析得出最佳行進路線。if (read_right > readeft) 如果右前方距離比較大(nmiRight(); 就向右轉,else tinnLeftO; 否則就向左轉此處也可以加入另一層邏輯:如果左右兩側讀數相等就調用mniAroundO原地掉頭。但 實際上觸發(fā)的幾率不大。/ FC 液晶測試程序,Aiduiiio 版本 L5.6-r2, LiquidCiystal_I2C 庫版本 2.0#mclude <V7ue.h>#mclude "LiquidCrystal_I2C.h" 導入 I2C 液晶庫LiquidCrystal_DC lcd(0x27,16,2); 設定 I2C 地址及液晶屏參數 void setupQIcd.uutQ; /始化液晶屏Icd.backlightQ;lcd.piint("HeUo, world!1); 開始打印信息lcd.setCursor(3,l);設定顯示位置,第3列,第1行 lcd.pnnt(nZANG.HAIBOH);void loop()()前進void goForwaid。Serial.pnndn("FORWARD) 串行監(jiān)視器顯示機器人狀態(tài)為FORWARD (前進) 左電機逆時針旋轉mt vail = analogRead(AO); 手動調整左電機轉速。電位器兩端分別接至+5V和GND, 中心抽頭接至A0mt leftSpeed = map(vallQ1023,0,255); /把讀數映射為 PWM analogWrite(ENA,left Spued); 寫入速度。卜.面的右電機同理 digitalWnte(INl, LOW);digitalWnte(IN2, HIGH);/右電機順時針旋轉mt val2 = analogRead(Al);mt rightSpeed = map(val2.0,1023.0,255);analogWnte(ENB4ightSpeed);digitalWnte(IN3, HIGH);digitalWnte(IN4, LOW);/ping.mo,紅外測距模塊山gge腳沿用D9, echo腳換成A3int readDistanceQdigitalWHte(tngger,HIGH); 點亮紅外發(fā)射管dulayMiciosecondsQOO); 給接收管留出200 u s響應時間IRvalue=analogRead(echo); 讀取自然光和紅外線下反射值的總和 digitalWrite(trigger,LOW); 關閉紅外發(fā)射管以讀取自然光下的反射值 dulayMiciosecondsQOO);留出 200 us 響應時間IRvalue=IRvalue-aiialogRead(echo); /刨除自然光得出實際值(紅外發(fā)射管產生的部 分)return niap(IRvalue, 120.930,30.0); /ffl map()函數把讀數轉換為距離)超聲波模塊SR04與Arduino連接:TRIG接Digital 5口,觸發(fā)測距;ECHO接Digital 4口,接收距離信號。程序代碼:intinputPin=4;"定義超聲波信號接收接口 ECHO接4口 int outputPin=5; /定義超聲波信號發(fā)出接口 TRIG接5口 void setup() (Serial.begin(9600);pinMode(inputPin. INPUT);pinMode(outputPin. OUTPUT);) void loop()(u fdigitalWrite(outputPin, LOW);/便發(fā)出發(fā)命超聲波信號接口低電平2ps , I<*.delayMicroseconds(2);digitalWrite(outputPin. HIGH); 使發(fā)出發(fā)出超聲波信號接口高電平1叩s,這里是至少 delayMicroseconds(10);digitalWrite(outputPin, LOW); /保持發(fā)出超聲波信號接口低電平 int distance = pulseln(inputPin. HIGH); 讀出脈沖時間 distance= distance/58; /將脈沖時間轉化為距離(單位:厘米) Serial .println(dlstance); /隔出距離值 delay(50);代碼1: HC-SR04超聲波傳感器典型代碼digitalWrite(TrigPin, LOW);delayMicroseconds(2);digitalWnte(TngPin. HIGH);發(fā)送10 ms的高電平觸發(fā)信號delayMicroseconds( 10);digitalWrite(TrigPin, LOW);distance - pukeIn(EchoPin, HIGH廣340/60/2; 檢測脈沖寬度即為超聲波往返時間代碼2:簡易超聲波測距代碼const int TrigPin - 2;const int EchoPni - 3; 設定 SR04 連接的 Arduino 引腳 float distance;void setupQ 初始化串口通信及連接SR04的引腳Serial.begin(9600);pmMode(TngPin, OUTPUT);/要檢測引腳上輸入的脈沖寬度,需要先設置為輸入狀態(tài) pinMode(EchoPm. INPUT);Senal.prmtln(uUltrasomc sensor:*);void loop() 產生一個10 us的高脈沖去觸發(fā)TngPmdigitalWrite(TrigPin, LOW);delayMicroseconds(2);digitalWrite(TrigPin, HIGH);delayMicroseconds( 10);digitalWrite(TrigPin, LOW);/檢測脈沖寬度,并計算出距離distance - pulseIn(EchoPin. HIGH) /58.00;Serial.prmt(distance);Serial.prmt(Mcm,r);Senal.printlnO; delay(1000);代碼3:具有溫度補償的超聲波測距代碼ffinclude <OneWire.h>ffinclude <DallasTemperatuie.h>設定SR04連接的Aidumo引腳const int TrigPin - 2;const int EchoPin - 3;float distance;float temperanue_value:ffdefine ONE_WIRE_BUS 4OneWire oneWire(ONE_WIRE_BUS);DallasTempeiature sensors(&oneWue);void setupQ 初始化串口通信及連接SR04的引腳Serial.begin(9600);pmMode(TngPin, OUTPUT);要檢測引腳上輸入的脈沖寬度,需要先設置為輸入狀態(tài) pinMode(EchoPm. INPUT);sensors.beginQ;void loop() 產生一個10 us的高脈沖去觸發(fā)TngPm sensors.iequestTeinpeiatures();teinperature_value - sensois.getTeixipCByliidex(O);Seiial.prmt(Mtemperauue -");Sei ial.priiit(temperatui e_value);Serial.print(HC ”);digitalVrite(TiigPin, LOW);delayMicioseconds(2);digitalVrite(TiigPin, HIGH);delayMici oseconds( 10);digitalVrite(TiigPin, LOW);檢測脈沖寬度,并計算出距離distance - pulseIn(EchoPm. HIGH) *(331.4+0.6*temperatuie_value)/2;Serial.print(Mdistance - );Seiial.priiit(distance);Seiial.pnnt(”cm");Seiial.prmtlnQ;delay(lOOO);代碼4:基于GP2D12的紅外測距系統代碼int i;float val;void setup()Serial.begin(9600);void loop()i=analogRead(A0);val=2547.8/(float)i*0.49-10.41)-0.42;Serial.println(val/2);藍牙遙控小車/Arduino源程序定稿口期:2016-3-16程序功能簡介:程序采用軟件PWM方式,控制兩支直流電機的運行行為,實現直行、后退、左轉和右轉 動作。操作者使用Android 機的藍牙功能發(fā)出指令,操控小車動作。操作者還通過藍牙對小車的動作參數進行調試。使用自定義串口收發(fā)數據使用軟件PWM,輸出引腳可任意制定使用Atmega48芯片/Arduio 版本 1.0.5#include <avr/io.h>#include <avr/interrupt.h>include <EEPROM.h>#include "usart.h"unsigned int counter; /PWM 計數器unsigned char wCnt = 0; 接收字計數unsigned int pwm_LH;左電機高電平計數unsigned int pwm_RH;右電機高電平計數unsigned char IDirect; 左電機運轉方向unsigned char rDirect; 右電機運轉方向unsigned int LP = 0;unsigned int RP = 0;unsigned int LD = 0;unsigned int RD = 0;unsigned int PWM6;存放當前PWM參數的整數型數組,全局變量unsigned char inputString8;/存輸入數據字符串變量boolean stringComplete = false; / 數據串結束標志定時器2初始化函數void timer2Jnit()(cli();TCCR2B = 0x00; /TCNT2 = 0xF6; /TCCR2A = 0x00;TCCR2B = 0x02; /TIMSK2 = 0x01; 定時器2中斷允許sei();)定時器2中斷服務函數/PWM波形產生器ISR(TIMER2_OVF_vect)TCNT2 = 0xF6; / counter+;if(counter = Ox3ff)if (rDirect = 1)bitSet(P0RTDz5);elsebitSet(P0RTD,4);if (IDirect = 1)bitSet(P0RTD,7);elsebitSet(P0RTD,6);counter = 0;if(counter = pwm_RH)bitClearfPORTD);bitClearfPORTD);if(counter = pwm_LH)bitClearfPORTD);bitClearfPORTDJ);)電機運行函數void Move(unsigned int LS,unsigned charLD,unsigned int RS,unsigned char RD) (asm("BCLR7"); 關中斷pwm_LH = LS;pwm_RH = RS;IDirect = LD;rDirect = RD;asm(”BSET7”); 開中斷)獲取EEPROM數據函數功能:從EEPROM里順序讀出六個PWM參數,存入PWM數組void GetData()(unsigned char bytes2; 暫時存放PWM參數的字節(jié)數組,全局變量 unsigned char i;unsigned char j;unsigned char k;for(i = 0;i < 6;i+)/for 循環(huán),讀六個參數for (j = 0;j < 2;j+) 內循環(huán),每次讀兩個字節(jié) k = i*2 + l-j;地址計算bytes。 = EEPROM.read(k); /EEPROM 讀操作PWM = word(bytes0, bytesl);將讀出的兩個字節(jié)合成一個PWM整數數據)數據發(fā)送函數功能:將一個整數拆分成四個ASCH代碼,通過藍牙串口發(fā)出的函數。例如:整數784,將拆分成;二7,8:星四個字符void Numberfint val)(inttmp;中間變量unsigned char i;/循環(huán)計數變量unsigned char buf4;存字符數組tmp= val/1000;bufO = tmp + 0x30; 獲得千位val= val % 1000;tmp= val/100;bufl = tmp + 0x30; 獲得百位val= val % 100;tmp= val/10;buf2 = tmp + 0x30; 獲得十位val= val % 10;buf3 = val + 0x30;獲得個位for(i = 0;i < 4;i+)if (buf = 0x30)從高位整理,如果是3則轉換成空格。buf =0x20;else break;Usart_Transmit(bufO);通過藍牙串11連續(xù)發(fā)出四個字符。Usart_ Transmit(buf 1);Usart_ Transmit(buf2);Usart_Transmit(buf3);void setupf) timer2_init();UsartJnit(9600);sei();PORTD = 0x00;DDRD = OxFO;GetDataf);初始化PWM參數) void loop() unsigned char buf6;存連續(xù)字符的數組unsigned char index = 0;存索引值變量unsigned char i; unsigned char k;unsigned int para;存 PWM 數據變量delay(500);iffstringComplete = true) 分解手機傳過來的參數(格式是:#n%ddddk= 0;其中:n為索引(地址);dddd為數據index = 0;for (i = 0;i <= wCnt ;i+)if (inputString = %) (index = inputstring卜 1 - 0x30; 獲得索引 k = 0; elsebufk = inputstring - 0x30; 獲得數據 k+;para = 0;for(i = 0;i < k-l;i+)para = para * 10 + buf;PWMindex = para;將得到的整數參數立即存入對應的PWM數組單元,修改當前運行參數bufl = lowByte(para); 將整數轉換成兩個字節(jié)。bufO = highByte(para);index = index * 2;計算 EE PROM 地址EEPROM.writefindex, bufl); 寫入 EEPROM 低位在前 index+;EEPROM.writefindex, bufO); 高位在后stringComplete = false; wCnt = 0;)ISR(USART_RX_vect)wCnt = 0;break;case d: 接收到d,右轉LP = PWM4;RP = PWM5;LD = 1;RD = O;wCnt = 0;break;case s:接收到后,停止電機LP = 0;RP = O;LD = 1;RD = 1;wCnt = 0;break;default:LP = 0;RP = O;LD = 1;RD = 1;Move(LRLD,RERD);