資料介紹
描述
什么是自治如此酷?
在這個項目中,我計劃更好地了解如何實現不同的傳感器以及獲得路徑規劃的經驗。自學期開始以來,我一直在做這方面的大部分工作,我很高興能有一個工作的結果。
自主機器人技術每年都在增長,我們在任何地方都能看到自主性只是時間問題!特斯拉的汽車是簡單自動駕駛的一個很好的例子,因為它們可以輕松規劃路徑、繪制環境地圖并做出決策,但對于處理人類生活和不確定性的完全自動駕駛來說不夠可靠或道德。在像自動化倉庫這樣的受控環境中,這些復雜的決策是不存在的,自主性可以完全冒險。
在這個項目中,我將使用激光雷達作為障礙物檢測的主要手段。A* 將用于精確的基于節點的路徑規劃,Optitrack Motive 軟件將用于基于運動捕捉的航位推算。
如果您只想查看最終項目,請在底部查看結果。
什么是路徑規劃?
你如何從一個地方到另一個地方?好吧,你可以隨意走,直到你到達目的地,或者你可以計劃。規劃路徑允許布置從一個點開始并在另一個點結束的最佳或功能性路徑。想想解決一個迷宮。當然,您可以沿著左墻或右墻一直走到盡頭,但這有可能需要很長時間,而且如果沒有出口,您肯定有機會永遠循環。路徑計劃可以讓您知道是否有通往您想要的位置的方法以及那里更直接的路徑。
有許多不同類型的路徑規劃算法,一些示例包括 Dijkstra's、A* 和廣度優先搜索。該項目將專注于路徑規劃的 A* 算法,因為它是上述三個中單個端點最直接的形式。
- 廣度優先搜索將同時搜索每個方向的最短路徑。這是一個非常有用的算法,但對于路徑規劃并不理想。
- 使用 Dijkstra 算法而不是廣度,因為它有利于成本最低的路徑。使您更接近最終目標的節點或路徑被優先考慮。
- A* 算法是對一個端點的 Dikstra 的修改和優化版本。
激光雷達有什么作用?
激光雷達只是用于距離測量的傳感器。激光從激光雷達中射出,返回所需的時間決定了與傳感器的距離。許多 2D 激光雷達,包括我在這個項目中使用的激光雷達,都會在整個傳感器周圍為您提供許多點和距離,如上圖所示。
?
以上是激光雷達可以做什么的一個例子。
動作捕捉?
簡單地說,我不需要使用動作捕捉,因為我可以使用電機的測量值來推算機器人汽車;但是,機電一體化室設置了動作捕捉系統。這使得機器人小車的位置非常容易定位;因此,使精確的動作易于執行。我將一個 Orange PI(一種便宜的 Raspberry PI)連接到動作捕捉軟件的網絡并檢索數據。然后,這會將數據發送到微控制器。
機器人汽車電機控制
為了開始這個項目的編碼部分,我將回顧控制直流電機的代碼
// 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;
下面的代碼讀取相應電機的旋轉角度,并使用已知的車輪半徑,我可以計算出車輪的行駛距離和速度。
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 計算一次速度和距離,我就實現了一個 PI 控制器,以通過確定的 Vref 和 Turn 平滑地控制電機。
// 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 控制器計算之后,我只需將電機設置為確定的 uLeft 和 uRight 值。我還必須使 uLeft 和 uRight 飽和,以防積分結束是 PID 控制的常見問題。我確保將當前狀態與過去狀態相同。
//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;
激光雷達數據設置
要使用激光雷達,我們必須找出我們從傳感器獲得的數據以及如何組織它。數據通過 SPIRXD 從激光雷達發送到微控制器。為與激光雷達通信而編寫的代碼使用狀態來檢查和讀取傳感器的初始化和數據。
來自 LIDAR 的數據以數據包的形式發送,所有數據包都以數據包頭 0xAA 開頭。這是我們首先檢查的內容,如果找到 0x55AA,我們可以進入狀態 2,否則我們繼續尋找。
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;
}
接下來,我們查看發送的數據包是起始數據包還是點云數據包,0x00。如果是我們推進的點云包。
} else if (state == 2) {//check 0x0
if (data == 0x0) {
state = 3;
// packetcount+=1;
} else {
state = 0;
}
然后我們讀取數據包中的樣本數量并記錄下來。
} else if (state == 3){ //read sample size
sampleSize = data;
state = 4;
}
接下來,是讀取??并記錄開始和結束角度。
} 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 數據點并告訴微控制器忽略檢查,因為我們假設只要 LIDAR 運行它就會保持不變。我們確保使用乒乓緩沖區來確保我們有足夠的時間來記錄數據并且不會遺漏任何數據。
} 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;
}
}
}
現在我們有數據了!我們還確保獲取數據并將其組織成一個很好的結構,說明角度、距離和時間戳。我還包括了為我的機器人創建的自定義 3D 零件。
A* 算法
由于我們有激光雷達工作,是時候讓 A* 算法為機器人的路徑規劃工作了。如前所述,A* 是 Dijkstra 算法的修改版本。
A* 和 Dijkstra 算法都使用優先級隊列來優先考慮成本較低或較高的路徑。優先級隊列與普通隊列不同,它基于先進先出,而優先級隊列按“最高優先級”、最低成本組織其隊列。有關優先級隊列背后的代碼的更多信息,請訪問下面的鏈接。
http://pages.cs.wisc.edu/~vernon/cs367/notes/11.PRIORITY-Q.html
解釋 A* 算法的最簡單方法是,它既需要從起點的實際距離,又需要估計到目標的距離。
f=g+h
上面的等式是 A* 的基礎,因為 F 是節點的總成本,G 是當前節點和起始節點之間的距離,H 是啟發式距離,即從當前節點到結束節點的估計距離。完整的 A* 算法函數可以在下面的源代碼中找到。我將分享幫助我為我的地圖創建算法的偽代碼。
// 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
運行 A* 算法
完成我的 A* 代碼后,我現在可以將地圖設置為我想要的任何大小,我選擇了 16X11,因為這是我將要駕駛的網格的大小。
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];
}
上面的代碼創建了一個 16X11 的地圖,并設置了一個起始行和起始列,并復制了一個沒有障礙物的預定地圖,這些地圖將在添加時更新。
astar(startRow,startCol,endRow,endCol); // solve path
然后,我們使用指定的端點運行 A* 函數。這應該導致路徑。經過幾次檢查以確保起點和終點在界限內并且它們不在障礙物上。A* 函數可以返回 3 個值 1、2 或 3 中的 1 個。
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,我們有一個路徑!然后我們采用這條路徑并將其添加到解決方案地圖并打印解決方案。這條路徑從結尾開始,一直到開頭,所以我確保創建一個路徑數組,以便將來更容易使用。
如果函數返回 2,那么它已經在這一點上,我們打印一個 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");
如果未找到機器人的有效路徑,該函數將返回 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 控制和運動捕捉
我們的機器人有一條路徑,我們可以運行輪子,但我們如何讓機器人順利地跟隨軌道?首先,我們確保我們始終知道我們的機器人汽車在哪里。OptiTrack Motive 軟件允許我用我打印的 3D 打印將一些反光球綁在我的機器人車的頂部,它會跟蹤這些球的中心。然后我可以將它用作我的機器人汽車的中心,這樣我就可以始終準確地知道它在網格中的位置。
我們使用下面的代碼讀取將通過 SPIRXC 使用的數據。
障礙物檢測
現在,困難的部分來了。機器人如何知道有什么東西擋住了它,我們如何圍繞它進行計劃?我所做的是給機器人一些規則。“障礙只能在這些地方,如果你看到那個區域周圍的東西就是那個地方的障礙”。聽起來很容易,對吧?我繼續為可能成為障礙的 48 條邊制定規則。
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;
然后,我確保找到每個障礙物的中心及其對應的路線圖索引。如果發現障礙物,我會計算出來。如果它達到 4 個或更多計數,我將地圖中的那些“0”更改為“X”,然后再次運行 A* 并獲得一條新路徑。
為此,我首先必須知道我的激光雷達讀數在全球范圍內的距離。由于 LIDAR 和 OptiTrack 系統有不同的基礎,我必須確保它們是相同的,代碼如下。
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();
}
這也是搜索并查看我是否有障礙的好時機。為了搜索障礙物,我必須對每個障礙物進行 FOR 循環,看看 LIDAR 讀數與其對應的 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 個角度,45、135、170 和 10 度。如果計數達到 4,則它們正式成為障礙并標記為已找到。然后,該函數給出一個標志 obsSearch,表示發現了一個障礙物,告訴機器人停止并尋找新路徑。
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;
}
}
把它們放在一起
把它們放在一起!首先,我制作了一個“PathFunction”標志,它會告訴機器人它處于什么狀態。它可以是“1”,即 A*,“2”,即跟隨路徑并尋找障礙物,或“3”,即 STANDBYE . 機器人由一個按鈕啟動。
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;
}
}
要開始按下按鈕運行 A*,這將在空白地圖上提供到端點的路徑,并將“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”,我們首先檢查我們是否靠近目標。如果我們是,我們說要在道路上進步。如果沒有,我們在繼續前進之前檢查是否發現了障礙物。如果我們找到一個,obsSearch = 1,我們回到 A*。如果沒有,我們可以自由地轉到所需的節點。
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;
}
我們計算所需的 x 和 y 并使用動作捕捉更新機器人的位置。然后我們運行 xy_control 來更新 Vref 和 Turn。最后,我們檢查我們是否到達了路徑的盡頭。如果是這樣,我們將等待進一步指示。
項目成果!
在我了解結果之前,我想說我在這個項目上玩得很開心,我在這個項目中學到了比以前更多的機器人技術。如果您覺得這很有趣,請嘗試一下。
A* 路徑規劃結果!
A* 的結果非常棒,因為機器人在軌道上縮放,精確地避開了我在地圖上手動放置的每一個障礙物。
以上是項目的A*路徑規劃、xy_control、動作捕捉組合的結果。機器人很容易跟隨給它的路徑,輕松地躲避障礙物。
障礙物檢測結果!
到目前為止,障礙物檢測是該項目中最難的部分。機器人汽車在靜止時能夠可靠地看到和映射障礙物,但在轉彎和移動時會遇到一些麻煩。
以上是自主機器人汽車的成功運行之一。
在這里,您可以看到機器人清楚地發現了兩個障礙物并改變了路線以繞過它們。
上面你可以看到機器人嘗試 A* 離開然后找到一個幻影障礙物并撞到另一個障礙物。
總的來說,這個項目是一個巨大的成功!這顯然可以調整和改進,但該項目的理論和代碼使一個現實生活中的自主機器人。
謝謝你
如果沒有 Dan Block 教授的幫助,我不可能做到這一點,因為他不僅提供了材料,而且還以他力所能及的方式提供了幫助!謝謝,丹!
我希望你喜歡我的項目,并在此過程中學到了一些東西。感謝您的時間!
- 帶有運動跟蹤和激光雷達的機器人汽車路徑規劃
- 【虹科】HKCubeRange1激光雷達產品規格_中文簡體
- 【虹科】HKCube1激光雷達產品規格_中文簡體
- 【虹科】HKCube激光雷達介紹_中文簡體
- 激光雷達技術及其發展動向.pdf 145次下載
- 基于單線激光雷達的數字重構系統綜述 75次下載
- 基于拉曼激光雷達的大氣水汽監測系統 27次下載
- 水下航行器自主巡航的路徑規劃算法實現 8次下載
- 小米2D激光雷達拆解資源下載 0次下載
- 激光雷達原理的PDF電子書免費下載 267次下載
- 小米的2D激光雷達拆解圖和講解 116次下載
- 自主泊車路徑規劃方法 16次下載
- 基于梯形棋盤格標定板對激光雷達和攝像機聯合標定方法 7次下載
- LNM-v1.0 激光導航定位模塊 24次下載
- 激光雷達距離像背景抑制算法研究
- 激光雷達LIDAR基本工作原理 3776次閱讀
- 闡述基于激光三角測距法的激光雷達原理 1213次閱讀
- 激光雷達測距能力的測試原理簡析 1031次閱讀
- 什么是激光雷達?激光雷達的構成與分類 7655次閱讀
- 一文詳解激光雷達 2106次閱讀
- TOF激光雷達的類別 1446次閱讀
- 淺談激光雷達的盲區 3738次閱讀
- 使用OpticStudio進行閃光激光雷達系統建模(中) 1735次閱讀
- 使用OpticStudio進行閃光激光雷達系統建模(上) 1781次閱讀
- 激光雷達的7大分類 7995次閱讀
- 關于FMCW激光雷達核心技術及量產難點 9862次閱讀
- 什么才是衡量激光雷達實用和可靠的指標 3073次閱讀
- XenomatiX激光雷達技術推動自動駕駛革命 4685次閱讀
- 激光雷達和毫米波雷達的區別介紹 4.3w次閱讀
- 激光雷達技術 1.1w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數據手冊
- 1.06 MB | 532次下載 | 免費
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費
- 3TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費
- 5元宇宙深度解析—未來的未來-風口還是泡沫
- 6.40 MB | 227次下載 | 免費
- 6迪文DGUS開發指南
- 31.67 MB | 194次下載 | 免費
- 7元宇宙底層硬件系列報告
- 13.42 MB | 182次下載 | 免費
- 8FP5207XR-G1中文應用手冊
- 1.09 MB | 178次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應用800例(新編版)
- 0.00 MB | 33566次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關電源設計實例指南
- 未知 | 21549次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數字電路基礎pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅動電路設計》 溫德爾著
- 0.00 MB | 6656次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉中文版)
- 78.1 MB | 537798次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191187次下載 | 免費
- 7十天學會AVR單片機與C語言視頻教程 下載
- 158M | 183279次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論
查看更多