/src/man/obstacle/ObstacleModule.cpp

https://github.com/emamanto/nbites · C++ · 466 lines · 328 code · 47 blank · 91 comment · 73 complexity · 69f24a870bb844d3712407aab58fa9bb MD5 · raw file

  1. #include "ObstacleModule.h"
  2. namespace man {
  3. namespace obstacle {
  4. using messages::FieldObstacles;
  5. using messages::ArmContactState;
  6. // Helper method, used to get the average of the sonar value buffers
  7. float average(std::list<float>& buf)
  8. {
  9. float avg = 0.f;
  10. for (std::list<float>::iterator i = buf.begin(); i != buf.end(); i++)
  11. {
  12. avg += *i;
  13. }
  14. avg /= float(buf.size());
  15. return avg;
  16. }
  17. float minimum(std::list<float>& buf)
  18. {
  19. float min = 500.f;
  20. for (std::list<float>::iterator i = buf.begin(); i != buf.end(); i++)
  21. {
  22. if (*i < min)
  23. min = *i;
  24. }
  25. return min;
  26. }
  27. ObstacleModule::ObstacleModule() : obstacleOut(base())
  28. {
  29. memset(obstacleBuffer, 0, sizeof(obstacleBuffer));
  30. memset(obstacleDistances, 0, sizeof(obstacleDistances));
  31. obstaclesList[0] = FieldObstacles::Obstacle::NONE;
  32. obstaclesList[1] = FieldObstacles::Obstacle::NORTH;
  33. obstaclesList[2] = FieldObstacles::Obstacle::NORTHEAST;
  34. obstaclesList[3] = FieldObstacles::Obstacle::EAST;
  35. obstaclesList[4] = FieldObstacles::Obstacle::SOUTHEAST;
  36. obstaclesList[5] = FieldObstacles::Obstacle::SOUTH;
  37. obstaclesList[6] = FieldObstacles::Obstacle::SOUTHWEST;
  38. obstaclesList[7] = FieldObstacles::Obstacle::WEST;
  39. obstaclesList[8] = FieldObstacles::Obstacle::NORTHWEST;
  40. // obstacleBuffer = { 0 };
  41. // obstacleDistances = { 0.f };
  42. // Used when setting the message fields
  43. // obstaclesList = { FieldObstacles::Obstacle::NONE,
  44. // FieldObstacles::Obstacle::NORTH,
  45. // FieldObstacles::Obstacle::NORTHEAST,
  46. // FieldObstacles::Obstacle::EAST,
  47. // FieldObstacles::Obstacle::SOUTHEAST,
  48. // FieldObstacles::Obstacle::SOUTH,
  49. // FieldObstacles::Obstacle::SOUTHWEST,
  50. // FieldObstacles::Obstacle::WEST,
  51. // FieldObstacles::Obstacle::NORTHWEST
  52. // };
  53. }
  54. void ObstacleModule::run_()
  55. {
  56. armContactIn.latch();
  57. visionIn.latch();
  58. sonarIn.latch();
  59. // Decide sonars
  60. // FieldObstacles::Obstacle::ObstaclePosition
  61. // sonars = processSonar(sonarIn.message());
  62. // Process vision in all three sections of frame separately
  63. FieldObstacles::Obstacle::ObstaclePosition
  64. visionL = processVision(visionIn.message().left_dist(),
  65. visionIn.message().left_bearing());
  66. FieldObstacles::Obstacle::ObstaclePosition
  67. visionM = processVision(visionIn.message().mid_dist(),
  68. visionIn.message().mid_bearing());
  69. FieldObstacles::Obstacle::ObstaclePosition
  70. visionR = processVision(visionIn.message().right_dist(),
  71. visionIn.message().right_bearing());
  72. // update obstacle buffer with new information from vision
  73. updateObstacleBuffer(visionL, visionM, visionR);
  74. // Decide arms
  75. FieldObstacles::Obstacle::ObstaclePosition
  76. arms = processArms(armContactIn.message());
  77. // Used to check if there were any obstacles found
  78. bool didReturn = false;
  79. portals::Message<messages::FieldObstacles> current(0);
  80. // std::cout<<"OBSTACLE: ";
  81. // ignore "NONE" direction, start at 1
  82. for (int i = 1; i < NUM_DIRECTIONS; i++)
  83. {
  84. if (obstacleBuffer[i] != 0)
  85. {
  86. FieldObstacles::Obstacle* temp = current.get()->add_obstacle();
  87. temp->set_position(obstaclesList[i]);
  88. temp->set_distance(obstacleDistances[i]);
  89. // std::cout<<obstacleDistances[i]<<", ";
  90. didReturn = true;
  91. }
  92. }
  93. // std::cout<<std::endl;
  94. FieldObstacles::Obstacle*temp = current.get()->add_obstacle();
  95. temp->set_position(arms);
  96. temp->set_distance(1.f);
  97. obstacleOut.setMessage(current);
  98. /*
  99. * This code processes both sonars and arms, then returns where
  100. * a single obstacle is based on information gathered from both inputs.
  101. * It does not use vision at all.
  102. *
  103. #ifdef USE_LAB_FIELD // Walls are too close to field for sonar use
  104. sonars = Obstacle::NONE;
  105. #endif
  106. // How do we combine the two decisions?
  107. // If they agree, easy
  108. if (arms == sonars)
  109. {
  110. current.get()->set_position(arms);
  111. }
  112. // Trust sonars before we get any arm input
  113. else if (arms == Obstacle::NONE)
  114. {
  115. current.get()->set_position(sonars);
  116. }
  117. // If they sort of agree, use the value that gives us better dodging info
  118. else if (sonars == Obstacle::NORTH && (arms == Obstacle::NORTHWEST ||
  119. arms == Obstacle::NORTHEAST))
  120. {
  121. current.get()->set_position(arms);
  122. }
  123. else if (arms == Obstacle::NORTH && (sonars == Obstacle::NORTHWEST ||
  124. sonars == Obstacle::NORTHEAST))
  125. {
  126. current.get()->set_position(sonars);
  127. }
  128. // If they don't agree or get no sonars, trust the arms
  129. else
  130. {
  131. current.get()->set_position(arms);
  132. }
  133. obstacleOut.setMessage(current);
  134. */
  135. }
  136. FieldObstacles::Obstacle::ObstaclePosition
  137. ObstacleModule::processArms(const messages::ArmContactState& input)
  138. {
  139. // Both arms pushed approximately backwards...something is in front
  140. if ((input.right_push_direction() ==
  141. ArmContactState::SOUTH ||
  142. input.right_push_direction() ==
  143. ArmContactState::SOUTHEAST ||
  144. input.right_push_direction() ==
  145. ArmContactState::SOUTHWEST) &&
  146. (input.left_push_direction() ==
  147. ArmContactState::SOUTH ||
  148. input.left_push_direction() ==
  149. ArmContactState::SOUTHWEST ||
  150. input.left_push_direction() ==
  151. ArmContactState::SOUTHEAST))
  152. {
  153. return FieldObstacles::Obstacle::NORTH;
  154. }
  155. // Both arms pushed approximately forward... something is behind
  156. else if ((input.right_push_direction() ==
  157. ArmContactState::NORTH ||
  158. input.right_push_direction() ==
  159. ArmContactState::NORTHEAST ||
  160. input.right_push_direction() ==
  161. ArmContactState::NORTHWEST) &&
  162. (input.left_push_direction() ==
  163. ArmContactState::NORTH ||
  164. input.left_push_direction() ==
  165. ArmContactState::NORTHWEST ||
  166. input.left_push_direction() ==
  167. ArmContactState::NORTHEAST))
  168. {
  169. return FieldObstacles::Obstacle::SOUTH;
  170. }
  171. // Not getting pushed on right arm... decide based on left
  172. else if (input.right_push_direction() ==
  173. ArmContactState::NONE)
  174. {
  175. if (input.left_push_direction() ==
  176. ArmContactState::NORTH ||
  177. input.left_push_direction() ==
  178. ArmContactState::NORTHEAST)
  179. {
  180. return FieldObstacles::Obstacle::SOUTHWEST;
  181. }
  182. else if (input.left_push_direction() ==
  183. ArmContactState::EAST)
  184. {
  185. return FieldObstacles::Obstacle::WEST;
  186. }
  187. else if (input.left_push_direction() ==
  188. ArmContactState::SOUTH ||
  189. input.left_push_direction() ==
  190. ArmContactState::SOUTHEAST)
  191. {
  192. return FieldObstacles::Obstacle::NORTHWEST;
  193. }
  194. else if (input.left_push_direction() ==
  195. ArmContactState::SOUTHWEST)
  196. {
  197. return FieldObstacles::Obstacle::NORTH;
  198. }
  199. else if (input.left_push_direction() ==
  200. ArmContactState::WEST ||
  201. input.left_push_direction() ==
  202. ArmContactState::NORTHWEST)
  203. {
  204. return FieldObstacles::Obstacle::SOUTH;
  205. }
  206. else return FieldObstacles::Obstacle::NONE;
  207. }
  208. // Not getting pushed on left arm... decide based on right
  209. else if (input.left_push_direction() ==
  210. ArmContactState::NONE)
  211. {
  212. if (input.right_push_direction() ==
  213. ArmContactState::NORTH ||
  214. input.right_push_direction() ==
  215. ArmContactState::NORTHWEST)
  216. {
  217. return FieldObstacles::Obstacle::SOUTHEAST;
  218. }
  219. else if (input.right_push_direction() ==
  220. ArmContactState::WEST)
  221. {
  222. return FieldObstacles::Obstacle::EAST;
  223. }
  224. else if (input.right_push_direction() ==
  225. ArmContactState::SOUTH ||
  226. input.right_push_direction() ==
  227. ArmContactState::SOUTHWEST)
  228. {
  229. return FieldObstacles::Obstacle::NORTHEAST;
  230. }
  231. else if (input.right_push_direction() ==
  232. ArmContactState::SOUTHEAST)
  233. {
  234. return FieldObstacles::Obstacle::NORTH;
  235. }
  236. else if (input.right_push_direction() ==
  237. ArmContactState::EAST ||
  238. input.right_push_direction() ==
  239. ArmContactState::NORTHEAST)
  240. {
  241. return FieldObstacles::Obstacle::SOUTH;
  242. }
  243. else return FieldObstacles::Obstacle::NONE;
  244. }
  245. // Potential issue: if both arms are pushed in disagreeing directions,
  246. // we just decide no obstacle.
  247. return FieldObstacles::Obstacle::NONE;
  248. }
  249. FieldObstacles::Obstacle::ObstaclePosition
  250. ObstacleModule::processSonar(const messages::SonarState& input)
  251. {
  252. // Buffer the current sonar values
  253. rightSonars.push_back(input.us_right());
  254. leftSonars.push_back(input.us_left());
  255. // Get rid of old values
  256. if (rightSonars.size() > SONAR_FRAMES_TO_BUFFER)
  257. {
  258. rightSonars.pop_front();
  259. }
  260. if (leftSonars.size() > SONAR_FRAMES_TO_BUFFER)
  261. {
  262. leftSonars.pop_front();
  263. }
  264. // Use the current average for our decision
  265. float right = average(rightSonars);
  266. float left = average(leftSonars);
  267. // Both sonars picking up an obstacle? It's probably in front
  268. if (right < SONAR_THRESH && left < SONAR_THRESH)
  269. {
  270. return FieldObstacles::Obstacle::NORTH;
  271. }
  272. // Otherwise to right side...
  273. else if (right < SONAR_THRESH)
  274. {
  275. return FieldObstacles::Obstacle::NORTHEAST;
  276. }
  277. // ... left side ...
  278. else if (left < SONAR_THRESH)
  279. {
  280. return FieldObstacles::Obstacle::NORTHWEST;
  281. }
  282. // .. or no obstacle
  283. else return FieldObstacles::Obstacle::NONE;
  284. }
  285. FieldObstacles::Obstacle::ObstaclePosition
  286. ObstacleModule::processVision(float distance, float bearing)
  287. {
  288. FieldObstacles::Obstacle::ObstaclePosition dir;
  289. float avg;
  290. // Process what direction it is in: act appropriately
  291. if ( bearing < -5.f*ZONE_WIDTH)
  292. {
  293. // obstacle to the southeast
  294. SEDists.push_back(distance);
  295. if (SEDists.size() > VISION_FRAMES_TO_BUFFER)
  296. {
  297. SEDists.pop_front();
  298. }
  299. dir = FieldObstacles::Obstacle::SOUTHEAST;
  300. avg = average(SEDists);
  301. obstacleDistances[int(dir)] = avg;
  302. return dir;
  303. }
  304. else if ( bearing < -3.f*ZONE_WIDTH )
  305. {
  306. // obstacle to the east
  307. EDists.push_back(distance);
  308. if (EDists.size() > VISION_FRAMES_TO_BUFFER)
  309. {
  310. EDists.pop_front();
  311. }
  312. dir = FieldObstacles::Obstacle::EAST;
  313. avg = average(EDists);
  314. obstacleDistances[int(dir)] = avg;
  315. return dir;
  316. }
  317. else if ( bearing < -ZONE_WIDTH )
  318. {
  319. // obstacle to northeast
  320. NEDists.push_back(distance);
  321. if (NEDists.size() > VISION_FRAMES_TO_BUFFER)
  322. {
  323. NEDists.pop_front();
  324. }
  325. dir = FieldObstacles::Obstacle::NORTHEAST;
  326. avg = average(NEDists);
  327. obstacleDistances[int(dir)] = avg;
  328. return dir;
  329. }
  330. else if ( bearing < ZONE_WIDTH )
  331. {
  332. // obstacle to north
  333. NDists.push_back(distance);
  334. if (NDists.size() > VISION_FRAMES_TO_BUFFER)
  335. {
  336. NDists.pop_front();
  337. }
  338. dir = FieldObstacles::Obstacle::NORTH;
  339. avg = average(NDists);
  340. obstacleDistances[int(dir)] = avg;
  341. return dir;
  342. }
  343. else if ( bearing < 3.f*ZONE_WIDTH )
  344. {
  345. // obstacle to northwest
  346. NWDists.push_back(distance);
  347. if (NWDists.size() > VISION_FRAMES_TO_BUFFER)
  348. {
  349. NWDists.pop_front();
  350. }
  351. dir = FieldObstacles::Obstacle::NORTHWEST;
  352. avg = average(NWDists);
  353. obstacleDistances[int(dir)] = avg;
  354. return dir;
  355. }
  356. else if ( bearing < 5.f*ZONE_WIDTH )
  357. {
  358. // obstacle to west
  359. WDists.push_back(distance);
  360. if (WDists.size() > VISION_FRAMES_TO_BUFFER)
  361. {
  362. WDists.pop_front();
  363. }
  364. dir = FieldObstacles::Obstacle::WEST;
  365. avg = average(WDists);
  366. obstacleDistances[int(dir)] = avg;
  367. return dir;
  368. }
  369. else if ( bearing < 7.f * ZONE_WIDTH )
  370. {
  371. // obstacle to southwest
  372. SWDists.push_back(distance);
  373. if (SWDists.size() > VISION_FRAMES_TO_BUFFER)
  374. {
  375. SWDists.pop_front();
  376. }
  377. dir = FieldObstacles::Obstacle::SOUTHWEST;
  378. avg = average(SWDists);
  379. obstacleDistances[int(dir)] = avg;
  380. return dir;
  381. }
  382. else // south
  383. {
  384. return FieldObstacles::Obstacle::NONE;
  385. }
  386. }
  387. void ObstacleModule::updateObstacleBuffer
  388. (FieldObstacles::Obstacle::ObstaclePosition visionL,
  389. FieldObstacles::Obstacle::ObstaclePosition visionM,
  390. FieldObstacles::Obstacle::ObstaclePosition visionR)
  391. {
  392. // std::cout<<"Obstacle Buffer: ";
  393. // start at 1 to ignore "NONE" direction
  394. for (int i = 1; i < NUM_DIRECTIONS; i++)
  395. {
  396. if ( i == int(visionL) || i == int(visionM) ||
  397. i == int(visionR) )
  398. {
  399. obstacleBuffer[i] = 1;
  400. // std::cout<<obstacleBuffer[i]<<", ";
  401. continue;
  402. }
  403. if (obstacleBuffer[i] == 0 or
  404. obstacleBuffer[i] > VISION_FRAMES_TO_HAVE_OBSTACLE)
  405. {
  406. obstacleBuffer[i] = 0;
  407. obstacleDistances[i] = 0;
  408. // std::cout<<obstacleBuffer[i]<<", ";
  409. continue;
  410. }
  411. obstacleBuffer[i]++;
  412. // std::cout<<obstacleBuffer[i]<<", ";
  413. }
  414. // std::cout<<std::endl;
  415. }
  416. } // namespace obstacle
  417. } // namespace man