particle.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. # pip3 install --user http://bit.ly/csc161graphics
  2. from graphics import *
  3. import time
  4. import numpy as np
  5. import math
  6. from map import *
  7. import random
  8. import colorsys
  9. from robot import VirtualRobot, LejosRobot
  10. # ------------------------------------------------------------------------
  11. class Particle:
  12. def __init__(self, worldmap):
  13. self.weight = 1
  14. self.x = np.random.rand()*worldmap.width
  15. self.y = np.random.rand()*worldmap.height
  16. self.heading = math.pi*2*np.random.rand()
  17. self.worldmap = worldmap
  18. def move(self, rot, distance):
  19. if np.random.rand() < 0.98:
  20. self.translate(distance)
  21. self.rotate(rot)
  22. else:
  23. self.x = np.random.rand()*self.worldmap.width
  24. self.y = np.random.rand()*self.worldmap.height
  25. self.heading = math.pi*2*np.random.rand()
  26. def translate(self, distance):
  27. distance = float(distance) + random.gauss(0.0, 0.4*distance)
  28. self.x = self.x + (math.cos(self.heading) * distance)
  29. self.y = self.y + (math.sin(self.heading) * distance)
  30. def rotate(self, radians):
  31. self.heading += float(radians) + random.gauss(0.0, 0.1*radians+0.02)
  32. self.heading %= 2 * math.pi
  33. def read(self):
  34. return self.worldmap.white(self.x, self.y)
  35. def __repr__(self):
  36. return "(%f, %f)" % (self.x, self.y)
  37. def compute_mean_point(particles):
  38. m_x, m_y, m_count = 0, 0, 0
  39. for p in particles:
  40. m_count += p.weight
  41. m_x += p.x * p.weight
  42. m_y += p.y * p.weight
  43. if m_count == 0:
  44. return -1, -1
  45. m_x /= m_count
  46. m_y /= m_count
  47. return m_x, m_y
  48. def low_variance_sampler (particles, worldmap):
  49. weights = []
  50. # normalize
  51. for p in particles:
  52. weights.append(p.weight)
  53. weights = weights / np.sum(weights)
  54. # print(np.sum(weights))
  55. new_particles = []
  56. M = len(particles)
  57. r = np.random.uniform(0, 1.0/M)
  58. c = weights[0]
  59. i = 0
  60. for m in range (0, M):
  61. # try:
  62. u = r + m * 1.0/M
  63. while u > c:
  64. i = i + 1
  65. c = c + weights[i]
  66. p = Particle(worldmap)
  67. p.x = particles[i].x
  68. p.y = particles[i].y
  69. p.heading = particles[i].heading
  70. new_particles.append(p)
  71. # except IndexError:
  72. # new_particles.append(Particle(worldmap))
  73. return new_particles
  74. def particle_filter(particles, read, move, rot, worldmap):
  75. new_particles = []
  76. M = len(particles)
  77. for p in particles:
  78. p.move(rot, move)
  79. # w = p(z|x) probabilidade de ter lido uma cor estadando em x
  80. if worldmap.inside(p.x, p.y):
  81. if p.read() == read:
  82. p.weight = 0.80
  83. else:
  84. p.weight = 0.20
  85. # p_d = p.read_sensor(world)
  86. # p.w = w_gauss(r_d, p_d)
  87. else:
  88. ptmp = Particle(worldmap)
  89. p.x = ptmp.x
  90. p.y = ptmp.y
  91. p.heading = ptmp.heading
  92. p.weight = 1.e-300
  93. # print(particles)
  94. return low_variance_sampler(particles, worldmap)
  95. # ------------------------------------------------------------------------
  96. def colorFix(floatcolor):
  97. r = int(floatcolor*240)
  98. if r < 0:
  99. r = 0
  100. elif r > 255:
  101. r = 255
  102. return r
  103. def main():
  104. width = 3370.39
  105. height = 2383.94
  106. zoom = 2.5
  107. worldmap = Map(width, height, "../3.txt")
  108. robot = LejosRobot('00:16:53:18:2E:17')
  109. PARTICLE_COUNT = 2000
  110. particles = []
  111. win = GraphWin('Particle', width/zoom, height/zoom, autoflush=False)
  112. win.setBackground('black')
  113. # create particles
  114. for i in range(0, PARTICLE_COUNT):
  115. particles.append(Particle(worldmap))
  116. while True:
  117. worldmap.draw(win, zoom)
  118. rot = 0
  119. move = 50
  120. ## ---------- Estima posicao ----------
  121. m_x, m_y = compute_mean_point(particles)
  122. # Realiza o movimento do robo
  123. # nesse exemplo estamos utilizando uma tecnica muito ruim.
  124. # Ela esta baseada na posicao real, deveria ser na estimativa
  125. if robot.x < width*0.1 or width*0.9 < robot.x:
  126. rot = np.random.uniform(math.pi/2,math.pi/2)
  127. robot.rotate(rot)
  128. if robot.y < height*0.1 or height*0.9 < robot.y:
  129. rot = np.random.uniform(math.pi/2,math.pi/2)
  130. robot.rotate(rot)
  131. robot.move(move)
  132. # Realiza a leitura de um sensor
  133. read = robot.read()
  134. # sabendo o movemento e a leitura, dedistribui as particulas
  135. particles = particle_filter(particles, read, move, rot, worldmap)
  136. # exibe as particulas na tela
  137. for p in particles:
  138. pt = Point(p.x/zoom, p.y/zoom)
  139. h = p.heading/(math.pi*2)
  140. rgb = colorsys.hsv_to_rgb(h, 0.8, 0.8)
  141. rgb = color_rgb(colorFix(rgb[0]), colorFix(rgb[1]), colorFix(rgb[2]))
  142. cir = Circle(pt, 10/zoom)
  143. cir.setWidth(0)
  144. cir.setFill(rgb)
  145. cir.draw(win)
  146. # exibe a posicao estimada na tela
  147. pt = Point(m_x/zoom, m_y/zoom)
  148. cir = Circle(pt, 30/zoom)
  149. cir.setFill('red')
  150. cir.draw(win)
  151. # mostra a posicao real
  152. if type(robot) is VirtualRobot:
  153. h = robot.heading/(math.pi*2)
  154. rgb = colorsys.hsv_to_rgb(h, 0.8, 0.8)
  155. rgb = color_rgb(colorFix(rgb[0]), colorFix(rgb[1]), colorFix(rgb[2]))
  156. pt = Point(robot.x/zoom, robot.y/zoom)
  157. cir = Circle(pt, 30/zoom)
  158. cir.setFill(rgb)
  159. cir.draw(win)
  160. win.update()
  161. win.delete('all')
  162. main()