Advertisement
Guest User

Untitled

a guest
Jan 18th, 2018
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.00 KB | None | 0 0
  1. # class ParticleFilterPoseEstimator
  2. # O. Bittel; 31.10.2014
  3.  
  4. from math import *
  5. import numpy.matlib as ml
  6. import numpy as np
  7. import random as rd
  8. import matplotlib.pyplot as plt
  9.  
  10. class ParticleFilterPoseEstimator:
  11.  
  12.     # --------
  13.     # initializes particle filter.
  14.     #
  15.     def __init__(self):
  16.         self.nPart = 100 # number of particles
  17.         self.chi = [[0.0,0.0,0.0] for i in range(self.nPart)] # particle set
  18.         self.mean = [0.0,0.0,0.0]
  19.         self.covariance = ml.zeros((3,3))
  20.         self.T = 0.01 # time step
  21.         self.room = None # room for particles
  22.         self.measuringDiversity = False # If true the number of different particles are counted
  23.  
  24.     # --------
  25.     # print robot attributes.
  26.     #
  27.     def __repr__(self):
  28.         return 'Particle filter pose: [x=%6.4f y=%6.4f orient=%6.4f]' % (self.x, self.y, self.orientation)
  29.  
  30.     # --------
  31.     # set time step.
  32.     #
  33.     def setTimestep(self, T):
  34.         self.T = float(T)
  35.  
  36.     def setRoom(self, testroom):
  37.         self.room = testroom
  38.  
  39.  
  40.     # --------
  41.     # initialize the particle filter with n particles following
  42.     # an uniform distribution in the interval [poseFrom, poseTo].
  43.     #
  44.     def initialize(self, poseFrom, poseTo, n = 100):
  45.         self.chi = [[0.0,0.0,0.0] for i in range(n)]
  46.         for i in range(n):
  47.             self.chi[i][0] = poseFrom[0] + (poseTo[0]-poseFrom[0])*rd.random()
  48.             self.chi[i][1] = poseFrom[1] + (poseTo[1]-poseFrom[1])*rd.random()
  49.             self.chi[i][2] = poseFrom[2] + (poseTo[2]-poseFrom[2])*rd.random()
  50.         self.nPart = n
  51.         self.__updateMeanCov()
  52.         return
  53.  
  54.  
  55.     def __updateMeanCov(self):
  56.         #print '__updateMeanCov: ', self.mean
  57.         x = [0.0 for i in range(len(self.chi))]
  58.         y = [0.0 for i in range(len(self.chi))]
  59.         theta = [0.0 for i in range(len(self.chi))]
  60.         i = 0
  61.         for p in self.chi:
  62.             x[i] = p[0]
  63.             y[i] = p[1]
  64.             theta[i] = p[2]
  65.             i += 1
  66.         mean_theta = self.__mean_orientation(theta)
  67.         self.mean = [np.mean(x),np.mean(y),mean_theta]
  68.         self.covariance = ml.zeros((3,3))
  69.         self.covariance[0:2,0:2] =  np.cov([x,y])
  70.         self.covariance[2,2] = self.__variance_orientation(mean_theta,theta)
  71.         #print '__updateMeanCov: ', self.mean
  72.         #print "x:     ", self.mean[0], self.covariance[0,0], x
  73.         #print "y:     ", self.mean[1], self.covariance[1,1], y
  74.         #print 'theta_mean: %20.18f theta_sigma: %20.18f' % (self.mean[2]*180/pi, sqrt(self.covariance[2,2])*180/pi)
  75.         #print "theta: ", theta
  76.         return
  77.  
  78.  
  79.     # returns mean of orientations.
  80.     # mean can be ambigious (e.g. theta = [0, pi/2, pi, 3*pi/2].
  81.     # We use a heuristic: the mean never lies between two consecutive orientation with the largest angular difference.
  82.     # In some few cases the heuristic leads to a wrong mean.
  83.     def __mean_orientation(self, theta):
  84.         n = len(theta)
  85.         if n == 1:
  86.             return theta[0]
  87.         theta.sort()
  88.         #print theta
  89.         d = theta[0] - theta[n-1] + 2*pi
  90.         min = n-1
  91.         max = 0
  92.         for i in range(0,n-1):
  93.             if theta[i+1] - theta[i] > d:
  94.                 d = theta[i+1] - theta[i]
  95.                 min = i
  96.                 max = i+1
  97.         # print min, max
  98.         # print theta[min], theta[max]
  99.         # Mittelwert liegt zwischen theta[max] und theta[min]:
  100.         sum = 0.0
  101.         for i in range(n):
  102.             sum += (theta[i] - theta[max])
  103.         mean = (sum/n + theta[max]) % (2*pi)
  104.         return mean
  105.  
  106.  
  107.     def __variance_orientation(self, mean, theta):
  108.         n = len(theta)
  109.         if n == 1:
  110.             return 0.0
  111.         sum = 0.0
  112.         for i in range(n):
  113.             diff = (theta[i] - mean + pi) % (2*pi) - pi # orientation difference from [-pi, pi)
  114.             sum += diff**2
  115.         return sum/n
  116.  
  117.  
  118.     # --------
  119.     # get the current robot position estimate.
  120.     #
  121.     def getPose(self):
  122.         return self.mean
  123.  
  124.  
  125.     # --------
  126.     # get the current position covariance.
  127.     #
  128.     def getCovariance(self):
  129.         return self.covariance
  130.  
  131.  
  132.     # --------
  133.     # get particles.
  134.     #
  135.     def getParticles(self):
  136.         return self.chi
  137.  
  138.  
  139.     # --------
  140.     # integrate motion = [v, omega] and covariance sigma_motion for the next time step
  141.     #
  142.     def integrateMovement(self, motion, sigma_motion):
  143.  
  144.         for i in range(len(self.chi)):
  145.             # Sample noisy motion:
  146.             v = rd.gauss(motion[0],sqrt(sigma_motion[0,0]))
  147.             omega = rd.gauss(motion[1],sqrt(sigma_motion[1,1]))
  148.             # Apply noisy motion to particle chi[i]:
  149.             theta = self.chi[i][2]
  150.             self.chi[i][0] += v*self.T*cos(theta) # x
  151.             self.chi[i][1] += v*self.T*sin(theta) # y
  152.             self.chi[i][2] = (self.chi[i][2] + omega*self.T) % (2*pi) # orientation
  153.  
  154.         self.__updateMeanCov()
  155.         return
  156.  
  157.  
  158.     # --------
  159.     # integrate motion = [v, omega] and covariance sigma_movement for the next time step
  160.     #
  161.     def integrateMeasurement(self, z, sigma_z):
  162.         # z = number of measurements || should be same as the number of landmarks'
  163.  
  164.         # Weighting:
  165.         nPart = len(self.chi)
  166.         w = [0.0] * nPart
  167.         wsum = [0.0] * nPart
  168.         for i in range(nPart):
  169.             w[i] = self.getWeight(self.chi[i], z, sigma_z)
  170.             if i == 0:
  171.                 wsum[i] = w[i]
  172.             else:
  173.                 wsum[i] = wsum[i-1] + w[i]
  174.  
  175.         # Resampling:
  176.         chi_old = self.chi
  177.         self.chi = [[0.0,0.0,0.0] for i in range(nPart)]
  178.  
  179.         if self.measuringDiversity:
  180.             hist = [0 for i in range(nPart)]
  181.             ndiff = 0;
  182.  
  183.         for i in range(nPart):
  184.             r = rd.random()*wsum[nPart-1]
  185.             # roulette method with binary search:
  186.             li = 0;
  187.             re = nPart-1;
  188.             while li <= re:
  189.                 m = int((li + re)/2)
  190.                 if r < wsum[m]:
  191.                     re = m-1
  192.                 elif r > wsum[m]:
  193.                     li = m+1
  194.                 else:
  195.                     break
  196.             # Vorsicht!!!!
  197.             # Referenzzuweisung waere falsch:
  198.             # self.chi[i] = chi_old[m]
  199.             self.chi[i][0] = chi_old[m][0]
  200.             self.chi[i][1] = chi_old[m][1]
  201.             self.chi[i][2] = chi_old[m][2]
  202.  
  203.             if self.measuringDiversity:
  204.                 hist[m] += 1
  205.                 if hist[m] == 1:
  206.                     ndiff += 1
  207.  
  208.         if self.measuringDiversity:
  209.             print('Anz. unterschiedl. Partikel: ', ndiff, ' Gewichtssumme: ', wsum[nPart-1])
  210.  
  211.         self.__updateMeanCov()
  212.         return
  213.  
  214.  
  215.     def getWeight(self,particle, z, sigma_z):
  216.         prob = self.room.sense((particle[0], particle[1]), particle[2], False)
  217.         return prob
  218.  
  219.  
  220.     # --------
  221.     # 1-dimensional normal distribution N(mu,sigma2)
  222.     #
  223.     def __ndf(self,x,mu,sigma2):
  224.         c = 1/(sqrt(2*sigma2*pi))
  225.         return c*np.exp(-0.5 * (x-mu)**2/sigma2)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement