資料介紹
描述
什么是自治如此酷?
在這個(gè)項(xiàng)目中,我計(jì)劃更好地了解如何實(shí)現(xiàn)不同的傳感器以及獲得路徑規(guī)劃的經(jīng)驗(yàn)。自學(xué)期開(kāi)始以來(lái),我一直在做這方面的大部分工作,我很高興能有一個(gè)工作的結(jié)果。
自主機(jī)器人技術(shù)每年都在增長(zhǎng),我們?cè)谌魏蔚胤蕉寄芸吹阶灾餍灾皇菚r(shí)間問(wèn)題!特斯拉的汽車是簡(jiǎn)單自動(dòng)駕駛的一個(gè)很好的例子,因?yàn)樗鼈兛梢暂p松規(guī)劃路徑、繪制環(huán)境地圖并做出決策,但對(duì)于處理人類生活和不確定性的完全自動(dòng)駕駛來(lái)說(shuō)不夠可靠或道德。在像自動(dòng)化倉(cāng)庫(kù)這樣的受控環(huán)境中,這些復(fù)雜的決策是不存在的,自主性可以完全冒險(xiǎn)。
在這個(gè)項(xiàng)目中,我將使用激光雷達(dá)作為障礙物檢測(cè)的主要手段。A* 將用于精確的基于節(jié)點(diǎn)的路徑規(guī)劃,Optitrack Motive 軟件將用于基于運(yùn)動(dòng)捕捉的航位推算。
如果您只想查看最終項(xiàng)目,請(qǐng)?jiān)诘撞坎榭?/font>結(jié)果。
什么是路徑規(guī)劃?
你如何從一個(gè)地方到另一個(gè)地方?好吧,你可以隨意走,直到你到達(dá)目的地,或者你可以計(jì)劃。規(guī)劃路徑允許布置從一個(gè)點(diǎn)開(kāi)始并在另一個(gè)點(diǎn)結(jié)束的最佳或功能性路徑。想想解決一個(gè)迷宮。當(dāng)然,您可以沿著左墻或右墻一直走到盡頭,但這有可能需要很長(zhǎng)時(shí)間,而且如果沒(méi)有出口,您肯定有機(jī)會(huì)永遠(yuǎn)循環(huán)。路徑計(jì)劃可以讓您知道是否有通往您想要的位置的方法以及那里更直接的路徑。
有許多不同類型的路徑規(guī)劃算法,一些示例包括 Dijkstra's、A* 和廣度優(yōu)先搜索。該項(xiàng)目將專注于路徑規(guī)劃的 A* 算法,因?yàn)樗巧鲜鋈齻€(gè)中單個(gè)端點(diǎn)最直接的形式。
- 廣度優(yōu)先搜索將同時(shí)搜索每個(gè)方向的最短路徑。這是一個(gè)非常有用的算法,但對(duì)于路徑規(guī)劃并不理想。
- 使用 Dijkstra 算法而不是廣度,因?yàn)樗欣诔杀咀畹偷穆窂健?/font>使您更接近最終目標(biāo)的節(jié)點(diǎn)或路徑被優(yōu)先考慮。
- A* 算法是對(duì)一個(gè)端點(diǎn)的 Dikstra 的修改和優(yōu)化版本。
激光雷達(dá)有什么作用?
激光雷達(dá)只是用于距離測(cè)量的傳感器。激光從激光雷達(dá)中射出,返回所需的時(shí)間決定了與傳感器的距離。許多 2D 激光雷達(dá),包括我在這個(gè)項(xiàng)目中使用的激光雷達(dá),都會(huì)在整個(gè)傳感器周圍為您提供許多點(diǎn)和距離,如上圖所示。
?
以上是激光雷達(dá)可以做什么的一個(gè)例子。
動(dòng)作捕捉?
簡(jiǎn)單地說(shuō),我不需要使用動(dòng)作捕捉,因?yàn)槲铱梢允褂?a target='_blank' class='arckwlink_none'>電機(jī)的測(cè)量值來(lái)推算機(jī)器人汽車;但是,機(jī)電一體化室設(shè)置了動(dòng)作捕捉系統(tǒng)。這使得機(jī)器人小車的位置非常容易定位;因此,使精確的動(dòng)作易于執(zhí)行。我將一個(gè) Orange PI(一種便宜的 Raspberry PI)連接到動(dòng)作捕捉軟件的網(wǎng)絡(luò)并檢索數(shù)據(jù)。然后,這會(huì)將數(shù)據(jù)發(fā)送到微控制器。
機(jī)器人汽車電機(jī)控制
為了開(kāi)始這個(gè)項(xiàng)目的編碼部分,我將回顧控制直流電機(jī)的代碼
// Read the motor rotation
RightWheel = readEncRight();
LeftWheel = -readEncLeft();
// distance ft
XLeftK = 1/(radftL/LeftWheel);
XRightK = 1/(radftR/RightWheel);
// vel ft/s
VLeftK = (XLeftK - XLeftK1)/0.004;
VRightK = (XRightK - XRightK1)/0.004;
下面的代碼讀取相應(yīng)電機(jī)的旋轉(zhuǎn)角度,并使用已知的車輪半徑,我可以計(jì)算出車輪的行駛距離和速度。
float readEncLeft(void) {
int32_t raw = 0;
uint32_t QEP_maxvalue = 0xFFFFFFFFU; //4294967295U
raw = EQep1Regs.QPOSCNT;
if (raw >= QEP_maxvalue/2) raw -= QEP_maxvalue; // I don't think this is needed an d never true
// 5 North South magnet poles in the encoder disk so 5 square waves per one revolution of the
// DC motor's back shaft. Then Quadrature Decoder mode multiplies this by 4 so 20 counts per one rev
// of the DC motor's back shaft. Then the gear motor's gear ratio is 30:1.
return (raw*(1/(20*30/(2*PI))));
}
一旦每 1ms 計(jì)算一次速度和距離,我就實(shí)現(xiàn)了一個(gè) PI 控制器,以通過(guò)確定的 Vref 和 Turn 平滑地控制電機(jī)。
// PI
eturn = turn + (VLeftK - VRightK);
ekLeft = Vref - VLeftK - (Kturn*eturn);
IkLeft = IkLeft1 + 0.004*((ekLeft + ekLeft1)/2);
uLeft = (Kp*ekLeft) + (Ki*IkLeft);
ekRight = Vref - VRightK + (Kturn*eturn);
IkRight = IkRight1 + 0.004*((ekRight + ekRight1)/2);
uRight = (Kp+ekRight) + (Ki*IkRight);
在 PI 控制器計(jì)算之后,我只需將電機(jī)設(shè)置為確定的 uLeft 和 uRight 值。我還必須使 uLeft 和 uRight 飽和,以防積分結(jié)束是 PID 控制的常見(jiàn)問(wèn)題。我確保將當(dāng)前狀態(tài)與過(guò)去狀態(tài)相同。
//integral wind up
if(fabs(uLeft) >= 10) {
IkLeft = IkLeft1;
}
if(fabs(uRight) >= 10){
IkRight = IkRight1;
}
setEPWM2A(uRight);
setEPWM2B(-uLeft);
//states
XLeftK1 = XLeftK;
XRightK1 = XRightK;
IkLeft1 = IkLeft;
IkRight1 = IkRight;
ekLeft1 = ekLeft;
ekRight1 = ekRight;
激光雷達(dá)數(shù)據(jù)設(shè)置
要使用激光雷達(dá),我們必須找出我們從傳感器獲得的數(shù)據(jù)以及如何組織它。數(shù)據(jù)通過(guò) SPIRXD 從激光雷達(dá)發(fā)送到微控制器。為與激光雷達(dá)通信而編寫的代碼使用狀態(tài)來(lái)檢查和讀取傳感器的初始化和數(shù)據(jù)。
來(lái)自 LIDAR 的數(shù)據(jù)以數(shù)據(jù)包的形式發(fā)送,所有數(shù)據(jù)包都以數(shù)據(jù)包頭 0xAA 開(kāi)頭。這是我們首先檢查的內(nèi)容,如果找到 0x55AA,我們可以進(jìn)入狀態(tài) 2,否則我們繼續(xù)尋找。
if(state == 0) { //check 0xaa
if(data == 0xAA) {
state = 1;
} else {
state = 0;
}
} else if (state == 1) {//check 0x55
if(data == 0x55) {
state = 2;
} else {
state = 0;
}
接下來(lái),我們查看發(fā)送的數(shù)據(jù)包是起始數(shù)據(jù)包還是點(diǎn)云數(shù)據(jù)包,0x00。如果是我們推進(jìn)的點(diǎn)云包。
} else if (state == 2) {//check 0x0
if (data == 0x0) {
state = 3;
// packetcount+=1;
} else {
state = 0;
}
然后我們讀取數(shù)據(jù)包中的樣本數(shù)量并記錄下來(lái)。
} else if (state == 3){ //read sample size
sampleSize = data;
state = 4;
}
接下來(lái),是讀取??并記錄開(kāi)始和結(jié)束角度。
} else if (state == 4) {//read starting angle lsb
startangleLSB = data;
state = 5;
} else if (state == 5) {//record starting angle
start_angle = ((((data<<8)| startangleLSB)>>1)&0x7FFF)/64.0;
state = 6;
} else if (state == 6) { //read end angle
endLSB = data;
state = 7;
} else if (state == 7) {//record end angle
end_angle = ((((data<<8)| endLSB)>>1)&0x7FFF)/64.0;
if (end_angle < start_angle) {
cor_end = end_angle + 360;
} else {
cor_end = end_angle;
}
delta_angle = cor_end-start_angle;
state = 8;
}
最后,我們可以記錄 LIDAR 數(shù)據(jù)點(diǎn)并告訴微控制器忽略檢查,因?yàn)槲覀兗僭O(shè)只要 LIDAR 運(yùn)行它就會(huì)保持不變。我們確保使用乒乓緩沖區(qū)來(lái)確保我們有足夠的時(shí)間來(lái)記錄數(shù)據(jù)并且不會(huì)遺漏任何數(shù)據(jù)。
} else if (state == 8) {//record samples and ignore the check code
if(position > 1) {
if (dis_state == 0){
dLSB = data;
dis_state = 1;
} else if (dis_state == 1){
float raw_angle = (delta_angle)/(sampleSize - 1) * (sampleindex) +start_angle;
sampleindex = sampleindex+1;
if(sampleindex == sampleSize) {
sampleindex = 0;
}
pts[arrayIndex].rawAngle = raw_angle;
if(dist == 0){
cal_angle = raw_angle;
} else {
cal_angle = raw_angle + atan(21.8*(155.3-dist)/(155.3*dist))*57.296;
}
pts[arrayIndex].cor_angle = cal_angle;
if (pingpongflag == 1) {
pingpts[((int16_t)(cal_angle + 0.5))%360].distance = dist;
pingpts[((int16_t)(cal_angle + 0.5))%360].timestamp = numTimer0calls;
} else {
pongpts[((int16_t)(cal_angle + 0.5))%360].distance = dist;
pongpts[((int16_t)(cal_angle + 0.5))%360].timestamp = numTimer0calls;
}
dis_count += 1;
dis_state = 0;
if (arrayIndex < 599) {
arrayIndex += 1;
}
}
}
現(xiàn)在我們有數(shù)據(jù)了!我們還確保獲取數(shù)據(jù)并將其組織成一個(gè)很好的結(jié)構(gòu),說(shuō)明角度、距離和時(shí)間戳。我還包括了為我的機(jī)器人創(chuàng)建的自定義 3D 零件。
A* 算法
由于我們有激光雷達(dá)工作,是時(shí)候讓 A* 算法為機(jī)器人的路徑規(guī)劃工作了。如前所述,A* 是 Dijkstra 算法的修改版本。
A* 和 Dijkstra 算法都使用優(yōu)先級(jí)隊(duì)列來(lái)優(yōu)先考慮成本較低或較高的路徑。優(yōu)先級(jí)隊(duì)列與普通隊(duì)列不同,它基于先進(jìn)先出,而優(yōu)先級(jí)隊(duì)列按“最高優(yōu)先級(jí)”、最低成本組織其隊(duì)列。有關(guān)優(yōu)先級(jí)隊(duì)列背后的代碼的更多信息,請(qǐng)?jiān)L問(wèn)下面的鏈接。
http://pages.cs.wisc.edu/~vernon/cs367/notes/11.PRIORITY-Q.html
解釋 A* 算法的最簡(jiǎn)單方法是,它既需要從起點(diǎn)的實(shí)際距離,又需要估計(jì)到目標(biāo)的距離。
f=g+h
上面的等式是 A* 的基礎(chǔ),因?yàn)?F 是節(jié)點(diǎn)的總成本,G 是當(dāng)前節(jié)點(diǎn)和起始節(jié)點(diǎn)之間的距離,H 是啟發(fā)式距離,即從當(dāng)前節(jié)點(diǎn)到結(jié)束節(jié)點(diǎn)的估計(jì)距離。完整的 A* 算法函數(shù)可以在下面的源代碼中找到。我將分享幫助我為我的地圖創(chuàng)建算法的偽代碼。
// A*
Function A*(start,goal)
// Initialize the closed list, the set of nodes already evaluated Closedset = the empty set
//Initialize the open list, the set of tentative nodes to be evaluated //initially containing the start node
Start g score = 0 Start
f score = g score plus h “Manhattan distance from start to goal”
Openset = {start} came_from = empty
// The map of the navigated nodes
while the open list is not empty
Find the node with the least f on the open list, call it "q"
Pop q off the open list
Generate q's 4 neighbors
For each neighbor If neighbor is the goal, stop the search
neighbor.g = q.g + distance between neighbor and q
// h distance is the “Manhattan” distance on a square grid
neighbor.h = distance from goal to neighbor
neighbor.f = neighbor.g + neighbor.h
If a node with the same position as neighbor is in the OPEN list \ which has a lower f than neighbor, skip adding this neighbor
if a node with the same position as neighbor is in the CLOSED list \ which has a lower f than neighbor, skip adding this neighbor
otherwise, add the node to the open list and came_from[neighbor] = q //set neighbor’s parent equal to q
end
push q on the closed list
end
運(yùn)行 A* 算法
完成我的 A* 代碼后,我現(xiàn)在可以將地圖設(shè)置為我想要的任何大小,我選擇了 16X11,因?yàn)檫@是我將要駕駛的網(wǎng)格的大小。
int startRow = 4;
int startCol = 5;
int endRow = 15;
int endCol = 1;
char mapCourseStart[176] = //16x11
{ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'x', 'x', 'x', 'x', '0', '0', '0', 'x', 'x', 'x', 'x', //start row
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' };
if (PathFunction == 1){ // 1 for A* path
// create the map
mapRowSize = 16;
mapColSize = 11;
//reset Search flag
obsSearch = 0;
if(astarC == 0){ //Starting position
startRow = 4;
startCol = 5;
}else{
//floor the astar start point
startRow = floorf(ROBOTps.y);
startCol = floorf(ROBOTps.x);
}
astarC++;
int i = 0;
for(i = 0; i//*mapcolsize;>copy m1 into map for solving
map[i] = mapCourseStart[i];
}
上面的代碼創(chuàng)建了一個(gè) 16X11 的地圖,并設(shè)置了一個(gè)起始行和起始列,并復(fù)制了一個(gè)沒(méi)有障礙物的預(yù)定地圖,這些地圖將在添加時(shí)更新。
astar(startRow,startCol,endRow,endCol); // solve path
然后,我們使用指定的端點(diǎn)運(yùn)行 A* 函數(shù)。這應(yīng)該導(dǎo)致路徑。經(jīng)過(guò)幾次檢查以確保起點(diǎn)和終點(diǎn)在界限內(nèi)并且它們不在障礙物上。A* 函數(shù)可以返回 3 個(gè)值 1、2 或 3 中的 1 個(gè)。
retvalue = astar(startRow,startCol,endRow,endCol);
if (retvalue == 1) {
serial_printf(&SerialA," pathLength %d\r\n", pathLen);
int i = 0;
for(i = 0; i< pathLen; i++) //put solution on map
{
int mapIdx = pathRow[i]*mapColSize + pathCol[i];
map[mapIdx] = '-';
}
//put path nodes into structure node_path
int p = 0;
for(p = 0; p < pathLen; p++)
{
path[p].row = pathRow[(pathLen-1)-p];
path[p].col = pathCol[(pathLen-1)-p];
}
//print map with solution
i = 0;
int j = 0;
for(i=0; i {
for(j = 0; j serial_printf(&SerialA," %c ", map[i*mapColSize+j]);
serial_printf(&SerialA,"\r\n");
};>;>
如果它返回 1,我們有一個(gè)路徑!然后我們采用這條路徑并將其添加到解決方案地圖并打印解決方案。這條路徑從結(jié)尾開(kāi)始,一直到開(kāi)頭,所以我確保創(chuàng)建一個(gè)路徑數(shù)組,以便將來(lái)更容易使用。
如果函數(shù)返回 2,那么它已經(jīng)在這一點(diǎn)上,我們打印一個(gè) ERROR。
} else if (retvalue == 2) {
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"!!!!!!!!!!!!!!!!Error!!!!!!!!!!!!!!!\r\n");
serial_printf(&SerialA,"Already at this point. No Astar needed.\r\n");
serial_printf(&SerialA,"!!!!!!!!!!!!!!!!Error!!!!!!!!!!!!!!!\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
如果未找到機(jī)器人的有效路徑,該函數(shù)將返回 3。
} else {
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"!!!!!!!!!!!!!!!!Error!!!!!!!!!!!!!!!\r\n");
serial_printf(&SerialA,"No Path Found Obstacle in the path.\r\n");
serial_printf(&SerialA,"!!!!!!!!!!!!!!!!Error!!!!!!!!!!!!!!!\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
serial_printf(&SerialA,"\r\n");
}
XY 控制和運(yùn)動(dòng)捕捉
我們的機(jī)器人有一條路徑,我們可以運(yùn)行輪子,但我們?nèi)绾巫寵C(jī)器人順利地跟隨軌道?首先,我們確保我們始終知道我們的機(jī)器人汽車在哪里。OptiTrack Motive 軟件允許我用我打印的 3D 打印將一些反光球綁在我的機(jī)器人車的頂部,它會(huì)跟蹤這些球的中心。然后我可以將它用作我的機(jī)器人汽車的中心,這樣我就可以始終準(zhǔn)確地知道它在網(wǎng)格中的位置。
我們使用下面的代碼讀取將通過(guò) SPIRXC 使用的數(shù)據(jù)。
障礙物檢測(cè)
現(xiàn)在,困難的部分來(lái)了。機(jī)器人如何知道有什么東西擋住了它,我們?nèi)绾螄@它進(jìn)行計(jì)劃?我所做的是給機(jī)器人一些規(guī)則。“障礙只能在這些地方,如果你看到那個(gè)區(qū)域周圍的東西就是那個(gè)地方的障礙”。聽(tīng)起來(lái)很容易,對(duì)吧?我繼續(xù)為可能成為障礙的 48 條邊制定規(guī)則。
obs[46].x = 5; //ROBOTps
obs[46].y = 6;
obs[46].tally = 0;
obs[46].found = 0;
obs[46].idx1 = 72;
obs[46].idx2 = 71;
obs[46].idx3 = 70;
obs[47].x = 3; //ROBOTps
obs[47].y = 6;
obs[47].tally = 0;
obs[47].found = 0;
obs[47].idx1 = 70;
obs[47].idx2 = 69;
obs[47].idx3 = 68;
obs[48].x = 1; //ROBOTps
obs[48].y = 6;
obs[48].tally = 0;
obs[48].found = 0;
obs[48].idx1 = 68;
obs[48].idx2 = 67;
obs[48].idx3 = 66;
然后,我確保找到每個(gè)障礙物的中心及其對(duì)應(yīng)的路線圖索引。如果發(fā)現(xiàn)障礙物,我會(huì)計(jì)算出來(lái)。如果它達(dá)到 4 個(gè)或更多計(jì)數(shù),我將地圖中的那些“0”更改為“X”,然后再次運(yùn)行 A* 并獲得一條新路徑。
為此,我首先必須知道我的激光雷達(dá)讀數(shù)在全球范圍內(nèi)的距離。由于 LIDAR 和 OptiTrack 系統(tǒng)有不同的基礎(chǔ),我必須確保它們是相同的,代碼如下。
if (UseLIDARping == 1) {
UseLIDARping = 0;
int i = 0;
// change of basis
for (i = 0; i < 360; i++) {
//if the data is not available, set all of them to 0 to avoid messing things up
if (pingpts[i].distance ==0) {
x_f[i].distance = 0;
y_f[i].distance = 0;
x_f[i].timestamp = pingpts[i].timestamp;
y_f[i].timestamp = pingpts[i].timestamp;
} else {
x_ori[i] = pingpts[i].distance*cos(i*0.01745329)/304;//0.017453292519943 is pi/180
y_ori[i] = pingpts[i].distance*sin(i*0.01745329)/304;
x_f[i].distance = (x_ori[i])*sin(ROBOTps.theta)+(y_ori[i])*cos(ROBOTps.theta)+(ROBOTps.x); //change basis
y_f[i].distance = (x_ori[i])*cos(ROBOTps.theta)+(y_ori[i])*sin(ROBOTps.theta)+(ROBOTps.y); //change basis
// x_f[i].distance = (x_ori[i]+pose_x)*cos(pose_rad)-(y_ori[i]+pose_y)*sin(pose_rad); //change basis
// y_f[i].distance = (x_ori[i]+pose_x)*sin(pose_rad)+(y_ori[i]+pose_y)*cos(pose_rad); //change basis
}
}
if (PathFunction == 2){
searchObs();
}
這也是搜索并查看我是否有障礙的好時(shí)機(jī)。為了搜索障礙物,我必須對(duì)每個(gè)障礙物進(jìn)行 FOR 循環(huán),看看 LIDAR 讀數(shù)與其對(duì)應(yīng)的 x 和 y 位置之間的差異是否小于 0.35 英尺。
void searchObs(){
int i = 0;
for(i = 0; i < 49; i++){
// search lidar angles
// }
if(x_ori[90] < 1.5 && x_ori[90] > 0){
if(y_ori[90] < 1.5 && y_ori[90] > 0){
obsDisx = (x_f[90].distance - obs[i].x);
obsDisy = (y_f[90].distance - obs[i].y);
obsDist = sqrtf((obsDisx*obsDisx)*(obsDisy*obsDisy));
if(obsDist < 0.35){
obs[i].tally++;
}
}
}
我又做了 4 個(gè)角度,45、135、170 和 10 度。如果計(jì)數(shù)達(dá)到 4,則它們正式成為障礙并標(biāo)記為已找到。然后,該函數(shù)給出一個(gè)標(biāo)志 obsSearch,表示發(fā)現(xiàn)了一個(gè)障礙物,告訴機(jī)器人停止并尋找新路徑。
if(obs[i].tally > 3){
if (obs[i].found == 0){
mapCourseStart[obs[i].idx1] = 'x';
mapCourseStart[obs[i].idx2] = 'x';
mapCourseStart[obs[i].idx3] = 'x';
//Flag that an obs has been found
obsSearch = 1;
obs[i].found = 1;
}
}
把它們放在一起
把它們放在一起!首先,我制作了一個(gè)“PathFunction”標(biāo)志,它會(huì)告訴機(jī)器人它處于什么狀態(tài)。它可以是“1”,即 A*,“2”,即跟隨路徑并尋找障礙物,或“3”,即 STANDBYE . 機(jī)器人由一個(gè)按鈕啟動(dòng)。
void ReadSwitches(void) {
if(GpioDataRegs.GPADAT.bit.GPIO4 == 0){
PathFunction = 1;
}
if(GpioDataRegs.GPADAT.bit.GPIO5 == 0){
PathFunction = 2;
}
if(GpioDataRegs.GPADAT.bit.GPIO6 == 0){
PathFunction = 0;
}
if(GpioDataRegs.GPADAT.bit.GPIO7 == 0){
PathFunction = 3;
}
}
要開(kāi)始按下按鈕運(yùn)行 A*,這將在空白地圖上提供到端點(diǎn)的路徑,并將“PathFunction”推到 2。
if(PathFunction == 2){ // DRIVE THE PATH AFTER A* !!USE Lidar and obstacle indentification to interrupt PATHFUCTION = 2
//Run xycontrol for first path node changing desired x and y after each iteration until PathLen amount of times.
//This should end at the end of the path !!MUST WATCH FOR SLIPPING OF WHEELS!!
if(target_near == 1){
nodenumber++; //progress in path
target_near = 0;
}
//A*
if(obsSearch == 1){
if(astarC < 50){
PathFunction = 1;
nodenumber = 0;
}
// PathFunction = 1;
// nodenumber = 0;
}
一旦“PathFunction = 2”,我們首先檢查我們是否靠近目標(biāo)。如果我們是,我們說(shuō)要在道路上進(jìn)步。如果沒(méi)有,我們?cè)诶^續(xù)前進(jìn)之前檢查是否發(fā)現(xiàn)了障礙物。如果我們找到一個(gè),obsSearch = 1,我們回到 A*。如果沒(méi)有,我們可以自由地轉(zhuǎn)到所需的節(jié)點(diǎn)。
x_desired = (path[nodenumber+1].col);
y_desired = (path[nodenumber+1].row);
x_pos = ROBOTps.x;
y_pos = ROBOTps.y;
thetaabs = ROBOTps.theta;
xy_control(&vref_forxy, &turn_forxy,turn_thres,x_pos,y_pos,x_desired,y_desired,
thetaabs,target_radius,target_radius_near);
Vref = vref_forxy;
turn = turn_forxy;
if(nodenumber == pathLen-1){ //end of path!
PathFunction = 3;
Vref = 0;
turn = 0;
}
我們計(jì)算所需的 x 和 y 并使用動(dòng)作捕捉更新機(jī)器人的位置。然后我們運(yùn)行 xy_control 來(lái)更新 Vref 和 Turn。最后,我們檢查我們是否到達(dá)了路徑的盡頭。如果是這樣,我們將等待進(jìn)一步指示。
項(xiàng)目成果!
在我了解結(jié)果之前,我想說(shuō)我在這個(gè)項(xiàng)目上玩得很開(kāi)心,我在這個(gè)項(xiàng)目中學(xué)到了比以前更多的機(jī)器人技術(shù)。如果您覺(jué)得這很有趣,請(qǐng)嘗試一下。
A* 路徑規(guī)劃結(jié)果!
A* 的結(jié)果非常棒,因?yàn)闄C(jī)器人在軌道上縮放,精確地避開(kāi)了我在地圖上手動(dòng)放置的每一個(gè)障礙物。
以上是項(xiàng)目的A*路徑規(guī)劃、xy_control、動(dòng)作捕捉組合的結(jié)果。機(jī)器人很容易跟隨給它的路徑,輕松地躲避障礙物。
障礙物檢測(cè)結(jié)果!
到目前為止,障礙物檢測(cè)是該項(xiàng)目中最難的部分。機(jī)器人汽車在靜止時(shí)能夠可靠地看到和映射障礙物,但在轉(zhuǎn)彎和移動(dòng)時(shí)會(huì)遇到一些麻煩。
以上是自主機(jī)器人汽車的成功運(yùn)行之一。
在這里,您可以看到機(jī)器人清楚地發(fā)現(xiàn)了兩個(gè)障礙物并改變了路線以繞過(guò)它們。
上面你可以看到機(jī)器人嘗試 A* 離開(kāi)然后找到一個(gè)幻影障礙物并撞到另一個(gè)障礙物。
總的來(lái)說(shuō),這個(gè)項(xiàng)目是一個(gè)巨大的成功!這顯然可以調(diào)整和改進(jìn),但該項(xiàng)目的理論和代碼使一個(gè)現(xiàn)實(shí)生活中的自主機(jī)器人。
謝謝你
如果沒(méi)有 Dan Block 教授的幫助,我不可能做到這一點(diǎn),因?yàn)樗粌H提供了材料,而且還以他力所能及的方式提供了幫助!謝謝,丹!
我希望你喜歡我的項(xiàng)目,并在此過(guò)程中學(xué)到了一些東西。感謝您的時(shí)間!
- 帶有運(yùn)動(dòng)跟蹤和激光雷達(dá)的機(jī)器人汽車路徑規(guī)劃
- 【虹科】HKCubeRange1激光雷達(dá)產(chǎn)品規(guī)格_中文簡(jiǎn)體
- 【虹科】HKCube1激光雷達(dá)產(chǎn)品規(guī)格_中文簡(jiǎn)體
- 【虹科】HKCube激光雷達(dá)介紹_中文簡(jiǎn)體
- 激光雷達(dá)技術(shù)及其發(fā)展動(dòng)向.pdf 145次下載
- 基于單線激光雷達(dá)的數(shù)字重構(gòu)系統(tǒng)綜述 75次下載
- 基于拉曼激光雷達(dá)的大氣水汽監(jiān)測(cè)系統(tǒng) 27次下載
- 水下航行器自主巡航的路徑規(guī)劃算法實(shí)現(xiàn) 8次下載
- 小米2D激光雷達(dá)拆解資源下載 0次下載
- 激光雷達(dá)原理的PDF電子書(shū)免費(fèi)下載 267次下載
- 小米的2D激光雷達(dá)拆解圖和講解 116次下載
- 自主泊車路徑規(guī)劃方法 16次下載
- 基于梯形棋盤格標(biāo)定板對(duì)激光雷達(dá)和攝像機(jī)聯(lián)合標(biāo)定方法 7次下載
- LNM-v1.0 激光導(dǎo)航定位模塊 24次下載
- 激光雷達(dá)距離像背景抑制算法研究
- 激光雷達(dá)LIDAR基本工作原理 3776次閱讀
- 闡述基于激光三角測(cè)距法的激光雷達(dá)原理 1213次閱讀
- 激光雷達(dá)測(cè)距能力的測(cè)試原理簡(jiǎn)析 1031次閱讀
- 什么是激光雷達(dá)?激光雷達(dá)的構(gòu)成與分類 7655次閱讀
- 一文詳解激光雷達(dá) 2106次閱讀
- TOF激光雷達(dá)的類別 1446次閱讀
- 淺談激光雷達(dá)的盲區(qū) 3738次閱讀
- 使用OpticStudio進(jìn)行閃光激光雷達(dá)系統(tǒng)建模(中) 1735次閱讀
- 使用OpticStudio進(jìn)行閃光激光雷達(dá)系統(tǒng)建模(上) 1781次閱讀
- 激光雷達(dá)的7大分類 7995次閱讀
- 關(guān)于FMCW激光雷達(dá)核心技術(shù)及量產(chǎn)難點(diǎn) 9862次閱讀
- 什么才是衡量激光雷達(dá)實(shí)用和可靠的指標(biāo) 3073次閱讀
- XenomatiX激光雷達(dá)技術(shù)推動(dòng)自動(dòng)駕駛革命 4685次閱讀
- 激光雷達(dá)和毫米波雷達(dá)的區(qū)別介紹 4.3w次閱讀
- 激光雷達(dá)技術(shù) 1.1w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數(shù)據(jù)手冊(cè)
- 1.06 MB | 532次下載 | 免費(fèi)
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費(fèi)
- 3TC358743XBG評(píng)估板參考手冊(cè)
- 1.36 MB | 330次下載 | 免費(fèi)
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費(fèi)
- 5元宇宙深度解析—未來(lái)的未來(lái)-風(fēng)口還是泡沫
- 6.40 MB | 227次下載 | 免費(fèi)
- 6迪文DGUS開(kāi)發(fā)指南
- 31.67 MB | 194次下載 | 免費(fèi)
- 7元宇宙底層硬件系列報(bào)告
- 13.42 MB | 182次下載 | 免費(fèi)
- 8FP5207XR-G1中文應(yīng)用手冊(cè)
- 1.09 MB | 178次下載 | 免費(fèi)
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費(fèi)
- 2555集成電路應(yīng)用800例(新編版)
- 0.00 MB | 33566次下載 | 免費(fèi)
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費(fèi)
- 4開(kāi)關(guān)電源設(shè)計(jì)實(shí)例指南
- 未知 | 21549次下載 | 免費(fèi)
- 5電氣工程師手冊(cè)免費(fèi)下載(新編第二版pdf電子書(shū))
- 0.00 MB | 15349次下載 | 免費(fèi)
- 6數(shù)字電路基礎(chǔ)pdf(下載)
- 未知 | 13750次下載 | 免費(fèi)
- 7電子制作實(shí)例集錦 下載
- 未知 | 8113次下載 | 免費(fèi)
- 8《LED驅(qū)動(dòng)電路設(shè)計(jì)》 溫德?tīng)栔?/a>
- 0.00 MB | 6656次下載 | 免費(fèi)
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費(fèi)
- 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
- 78.1 MB | 537798次下載 | 免費(fèi)
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費(fèi)
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費(fèi)
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費(fèi)
- 6電路仿真軟件multisim 10.0免費(fèi)下載
- 340992 | 191187次下載 | 免費(fèi)
- 7十天學(xué)會(huì)AVR單片機(jī)與C語(yǔ)言視頻教程 下載
- 158M | 183279次下載 | 免費(fèi)
- 8proe5.0野火版下載(中文版免費(fèi)下載)
- 未知 | 138040次下載 | 免費(fèi)
評(píng)論
查看更多