溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SLAM Noob的同時本地化和映射方法是什么

發(fā)布時間:2021-12-27 13:51:09 來源:億速云 閱讀:126 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“SLAM Noob的同時本地化和映射方法是什么”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“SLAM Noob的同時本地化和映射方法是什么”吧!

什么是SLAM?

即時定位與地圖構(gòu)建(simultaneous localization and mapping,簡寫成SLAM),用于環(huán)境模型(map)的并行構(gòu)建,以及在其中移動的機器人的狀態(tài)估算。換句話說,SLAM為你提供了一種實時跟蹤機器人在世界上的位置、并識別地標(例如建筑物,樹木,巖石和其他世界特征)的位置的方法。除了本地化之外,我們還希望建立機器人環(huán)境的模型,這樣我們就有了一個物體的概念,以及圍繞機器人的地標,以便我們可以使用此地圖數(shù)據(jù)來確保機器人在世界各地移動時走在正確的道路上。因此,構(gòu)建地圖的關(guān)鍵是機器人本身可能會由于其運動不確定性而失去對其位置的跟蹤,因為不存在現(xiàn)有的地圖,并且我們正在用機器人并行構(gòu)建地圖。而這就是SLAM發(fā)揮作用的地方。

SLAM的工作:

同時定位和地圖繪制(SLAM)的基礎(chǔ)是從機器人的傳感器和隨時間推移的運動中收集信息,然后使用有關(guān)測量和運動的信息來重建世界地圖。在這種情況下,我們將機器人定位在2D網(wǎng)格世界中,因此,基于圖的SLAM方法通過提取原始傳感器測量值來構(gòu)造簡化的估計問題。這些原始測量值將替換為圖中的邊緣,然后可以將其視為虛擬測量值。 假設(shè)我們有一個機器人和初始位置 x0 = 0y0 = 0 。對于此示例,為了保持簡單,我們并不關(guān)心方向。讓我們假設(shè)機器人在X方向上向右移動了10。所以,在理想世界中,你會了解到 x1,運動后的位置與x0 + 10相同,即x1 = x0 + 10,同理,y1y0相同。

如圖,機器人在x方向上的位移為10:

SLAM Noob的同時本地化和映射方法是什么

但是根據(jù)卡爾曼濾波器和其他各種機器人技術(shù),我們已經(jīng)知道位置實際上是不確定的。因此,與其假設(shè)我們的XY坐標系中的機器人精確地向右移動了10個位置,不如理解成它在x1 = x0 + 10運動更新后的實際位置是以(10,0)為中心的高斯分布,但是機器人也可能在其他地方。

如圖:運動更新后,高斯以機器人的位置為中心

SLAM Noob的同時本地化和映射方法是什么

這是x變量的高斯的數(shù)學公式: 當這兩個條件相同時,與其將x1設(shè)置為x0+10,不如用高斯函數(shù)來表示,此時高斯函數(shù)達到峰值。。因此,如果你減去x1-x0-10,把它變成一個正方形,然后將其轉(zhuǎn)換為高斯,我們將得到與x1和x0相關(guān)的概率分布。我們可以對y做同樣的轉(zhuǎn)換。根據(jù)我們的運動y不變,因此y1和y0盡可能靠近。

SLAM Noob的同時本地化和映射方法是什么

這兩個高斯的乘積現(xiàn)在是我們的約束條件。目標是在位置x0為(0,0)的情況下最大化位置x1的可能性。因此,Graph SLAM所做的是,它使用一系列此類約束條件來定義概率。 假設(shè)我們有一個在某個空間中移動的機器人,GRAPH SLAM會收集其初始位置(0,0),最初也稱為“初始約束”,然后收集許多相對約束,這些相對約束會將每個機器人姿態(tài)與之前的機器人姿態(tài)相關(guān)聯(lián)作為相對運動約束。例如,讓我們使用機器人可以在各個位置看到的地標,這是每次機器人看到地標時的相對測量約束。因此,Graph SLAM收集這些約束,以便找到最可能的機器人路徑配置以及地標位置,即映射過程。

SLAM Noob的同時本地化和映射方法是什么

實作

生成環(huán)境:

我們將生成一個帶有地標的2D世界網(wǎng)格,然后通過將機器人放置在該世界中,并在一定數(shù)量的時間步長上移動和感應(yīng)來生成數(shù)據(jù)。實例化的機器人在世界中移動和感知時,將收集數(shù)據(jù)。我們的SLAM函數(shù)將把這些數(shù)據(jù)作為輸入。因此,讓我們首先創(chuàng)建此數(shù)據(jù),并探索它如何代表我們的機器人進行運動和傳感器測量。

SLAM輸入:

除了數(shù)據(jù)之外,我們的slam函數(shù)還具有:

  • N:機器人將要移動和感應(yīng)的時間步數(shù)。

  • num_landmarks:世界上的地標數(shù)量。

  • world_size:你的世界的大?。╳ / h)。

  • motion_noise:與運動相關(guān)的噪聲;運動的更新置信度應(yīng)為1.0/motion_noise.

  • measurement_noise:與測量/傳感相關(guān)的噪聲;測量的更新權(quán)重應(yīng)為1.0/measurement_noise.

import numpy as np
from helpers import make_data

#slam的實現(xiàn)應(yīng)該使用以下輸入

#請隨意更改這些輸入值并查看其響應(yīng)方式!

# 世界參數(shù)
num_landmarks      = 5        # number of landmarks
N                  = 20       # time steps
world_size         = 100.0    # size of world (square)

# 機器人參數(shù)
measurement_range  = 50.0     # range at which we can sense landmarks
motion_noise       = 2.0      # noise in robot motion
measurement_noise  = 2.0      # noise in the measurements
distance           = 20.0     # distance by which robot (intends to) move each iteratation 


# make_data實例化一個機器人,并為給定的世界大小和給定數(shù)量的地標生成隨機地標
data = make_data(N, num_landmarks, world_size, measurement_range, motion_noise, measurement_noise, distance)

讓我們編寫兩個主要功能,這些功能可以使機器人四處移動,幫助定位地標并在2D地圖上測量它們之間的距離:

  • Move:嘗試按dx,dy移動機器人。

  • Sense:返回可見范圍內(nèi)地標的x和y距離。

class robot:
    
    #move function
    def move(self, dx, dy):
        
        x = self.x + dx + self.rand() * self.motion_noise
        y = self.y + dy + self.rand() * self.motion_noise
        
        if x < 0.0 or x > self.world_size or y < 0.0 or y > self.world_size:
            return False
        else:
            self.x = x
            self.y = y
            return True
    
    
    #sense function
    def sense(self):
        measurements = []

        for landmark_index, landmark in enumerate(self.landmarks):
            landmark_distance_x = landmark[0]
            landmark_distance_y = landmark[1]
            random_noise = self.rand()
            cal_dx = self.x - landmark_distance_x + random_noise * self.measurement_noise
            cal_dy = self.y - landmark_distance_y + random_noise * self.measurement_noise
            is_not_in_measurement_range = self.measurement_range == -1
            if(is_not_in_measurement_range) or ((abs(cal_dx) <= self.measurement_range) and (abs(cal_dy) <= self.measurement_range)):
                measurements.append([landmark_index, cal_dx, cal_dy])
        return measurements
Omega 和 Xi:

為了實現(xiàn)Graph SLAM,引入了一個矩陣和一個向量(分別為ω和xi)。矩陣是正方形的,標有所有機器人姿勢(xi)和所有地標。例如,每次進行觀察時,當你在兩個姿勢之間移動某個距離dx,并可以關(guān)聯(lián)這兩個位置時,可以將其表示為這些矩陣中的數(shù)值關(guān)系。 讓我們編寫函數(shù),以便它為機器人的起始位置返回omega和xi約束。我們尚不知道的所有值都應(yīng)使用0進行初始化。我們可以假設(shè)我們的機器人以100%的置信度在世界的正中間開始。

def initialize_constraints(N, num_landmarks, world_size):
    ''' This function takes in a number of time steps N, number of landmarks, and a world_size,
        and returns initialized constraint matrices, omega and xi.'''
    
    middle_of_the_world = world_size / 2
    
    ## 建議:在變量中定義和存儲約束矩陣的大小(行/列)
    rows, cols = 2*(N + num_landmarks), 2*(N + num_landmarks)
    ## TODO: 用兩個初始“strength”值定義約束矩陣Omega
    omega = np.zeros(shape = (rows, cols))
    ## 我們機器人最初的x,y位置
    #omega = [0]
    
    omega[0][0], omega[1][1] = 1,1
    
    ## TODO: Define the constraint *vector*, xi
    ## 假設(shè)機器人以100%的置信度在世界的正中間開始。
    #xi = [0]
    xi = np.zeros(shape = (rows, 1))
    xi[0][0] = middle_of_the_world
    xi[1][0] = middle_of_the_world
    
    return omega, xi
通過運動和測量值進行更新:
## slam接受6個參數(shù)并返回mu,
## mu是機器人穿過的整個路徑(所有x,y姿勢)和所有地標位置
def slam(data, N, num_landmarks, world_size, motion_noise, measurement_noise):
    
    ## TODO: 使用你的初始化創(chuàng)建約束矩陣
    omega, xi = initialize_constraints(N, num_landmarks, world_size)
    ## TODO:遍歷數(shù)據(jù)中的每個時間步驟
    for time_step in range(len(data)):
        
        ## 每次迭代時獲取所有的運動和測量數(shù)據(jù)
        measurement = data[time_step][0]
        motion = data[time_step][1]
        x
        dx = motion[0]         # 本次沿x移動的距離
        dy = motion[1]         # 本次沿y移動的距離
        
        #假設(shè)機器人在這個時間從(x0,y0)移動到(x1,y1)
        
        #omega的偶數(shù)列對應(yīng)于x值
        x0 = (time_step * 2)   #x0 = 0,2,4,...
        x1 = x0 + 2            #x1 = 2,4,6,...
        
        # omega 的奇數(shù)列對應(yīng)于y值
        y0 = x0 + 1            #y0 = 1,3,5,...
        y1 = y0 + 2            #y1 = 3,5,7,...
        
        actual_m_noise = 1.0/measurement_noise
        actual_n_noise = 1.0/motion_noise
    ## TODO: 更新約束矩陣/向量(Omega/xi)以解釋所有*measurements*
    ## 這應(yīng)該是一系列考慮測量噪聲的附加值
        for landmark in measurement:
            lM = landmark[0]            # 地標 id
            dx_lM = landmark[1]         # 沿x與當前位置分離
            dy_lM = landmark[2]         # 沿y與當前位置分離
            
            L_x0 = (N*2) + (lM*2)       # 偶數(shù)列有x個地標值
            L_y0 = L_x0 + 1             # 奇數(shù)列有y個地標值

            # 更新對應(yīng)于x0和Lx0之間測量值的omega值
            omega[x0][x0] += actual_m_noise
            omega[L_x0][L_x0] += actual_m_noise
            omega[x0][L_x0] += -actual_m_noise
            omega[L_x0][x0] += -actual_m_noise
            
            # 更新對應(yīng)于y0和Ly0之間測量值的omega值
            omega[y0][y0] += actual_m_noise
            omega[L_y0][L_y0] += actual_m_noise
            omega[y0][L_y0] += -actual_m_noise
            omega[L_y0][y0] += -actual_m_noise
            
            # 更新X0和LX0之間的測量值對應(yīng)的xi值
            xi[x0]  -= dx_lM/measurement_noise
            xi[L_x0]  += dx_lM/measurement_noise
            
            # 更新y0和Ly0之間的測量值對應(yīng)的xi值
            xi[y0]  -= dy_lM/measurement_noise
            xi[L_y0] += dy_lM/measurement_noise
            
            
        ## TODO: 更新約束矩陣/向量(omega/XI),以解釋從(x0,y0)到(x1,y1)和運動噪聲的所有*運動*。
        omega[x0][x0] += actual_n_noise
        omega[x1][x1] += actual_n_noise
        omega[x0][x1] += -actual_n_noise
        omega[x1][x0] += -actual_n_noise
        
        omega[y0][y0] += actual_n_noise
        omega[y1][y1] += actual_n_noise
        omega[y0][y1] += -actual_n_noise
        omega[y1][y0] += -actual_n_noise
        
        xi[x0] -= dx/motion_noise
        xi[y0] -= dy/motion_noise
        
        xi[x1] += dx/motion_noise
        xi[y1] += dy/motion_noise
    
    ## TODO: 在遍歷所有數(shù)據(jù)之后
    ## 計算姿勢和地標位置的最佳估計值
    ##使用公式,omega_inverse * Xi
    inverse_of_omega = np.linalg.inv(np.matrix(omega))
    mu = inverse_of_omega * xi
    
    return mu
機器人的姿勢和地標:

讓我們打印函數(shù)產(chǎn)生的估計姿勢和界標位置。我們定義了一個提取姿勢和地標位置,并將它們作為自己的單獨列表返回。

def get_poses_landmarks(mu, N):
    # 創(chuàng)建一個姿勢列表
    poses = []
    for i in range(N):
        poses.append((mu[2*i].item(), mu[2*i+1].item()))

    # 創(chuàng)建一個地標列表
    landmarks = []
    for i in range(num_landmarks):
        landmarks.append((mu[2*(N+i)].item(), mu[2*(N+i)+1].item()))

    # 返回完成的列表
    return poses, landmarks
  
def print_all(poses, landmarks):
    print('\n')
    print('Estimated Poses:')
    for i in range(len(poses)):
        print('['+', '.join('%.3f'%p for p in poses[i])+']')
    print('\n')
    print('Estimated Landmarks:')
    for i in range(len(landmarks)):
        print('['+', '.join('%.3f'%l for l in landmarks[i])+']')

# 調(diào)用你的slam實現(xiàn),并傳入必要的參數(shù)
mu = slam(data, N, num_landmarks, world_size, motion_noise, measurement_noise)

# 打印出地標和姿勢結(jié)果
if(mu is not None):
    # 獲取姿勢和地標列表
    # 并打印出來
    poses, landmarks = get_poses_landmarks(mu, N)
    print_all(poses, landmarks)

如圖:估計的機器人姿勢和地標 SLAM Noob的同時本地化和映射方法是什么

可視化構(gòu)建的世界:
# 導入函數(shù)
from helpers import display_world

# 顯示最終世界!

# 定義圖形大小
plt.rcParams["figure.figsize"] = (20,20)

# 檢查姿勢是否已創(chuàng)建
if 'poses' in locals():
    # 打印出最后一個姿勢
    print('Last pose: ', poses[-1])
    # 顯示機器人的最后位置和地標位置
    display_world(int(world_size), poses[-1], landmarks)

如圖:輸出量 SLAM Noob的同時本地化和映射方法是什么

感謝各位的閱讀,以上就是“SLAM Noob的同時本地化和映射方法是什么”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對SLAM Noob的同時本地化和映射方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI