PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/EPuckSim.cc

https://github.com/jennyhasahat/EPuckAPI
C++ | 599 lines | 336 code | 132 blank | 131 comment | 32 complexity | 62f9d873ea3cde84771179f1d72def18 MD5 | raw file
  1. #include "EPuckSim.h"
  2. /*====================================================================
  3. CONSTRUCTOR/DESTRUCTOR
  4. ====================================================================*/
  5. /**
  6. * Creates an instance of the EPuck class.
  7. * Calls {@link EPuck#EPuck(int robotPort, char* robotName, int simulationPort) EPuck(int robotPort, char* robotName, int simulationPort)}
  8. * using default simulation port 6664 and default robot port 6665.
  9. * @param robotName the name of the robot model in the simulation eg robot1, robot2 etc. Maximum 64 chars.
  10. * @author Jennifer Owen
  11. * */
  12. EPuckSim::EPuckSim(char* robotName)
  13. {
  14. initialise(6665, robotName, 6664);
  15. }
  16. /**
  17. * Creates an instance of the EPuck class.
  18. * Calls {@link EPuck#EPuck(int robotPort, char* robotName, int simulationPort) EPuck(int robotPort, char* robotName, int simulationPort)}
  19. * using default simulation port 6664.
  20. * @param robotPort the number of the EPuck in the simulation. Eg 6665, 6666, 6667 etc.
  21. * @param robotName the name of the robot model in the simulation eg robot1, robot2 etc. Maximum 64 chars.
  22. * @author Jennifer Owen
  23. * */
  24. EPuckSim::EPuckSim(char* robotName, int robotPort)
  25. {
  26. initialise(robotPort, robotName, 6664);
  27. }
  28. /**
  29. Creates and instance of the EPuck class.
  30. @param robotPort the number of the EPuck in the simulation. Eg 6665, 6666, 6667 etc.
  31. @param robotName the name of the robot model in the simulation eg robot1, robot2 etc. Maximum 64 chars.
  32. @param simulationPort the port on which the simulation is running. Get this from the .cfg file of your simulation.
  33. @author Jennifer Owen
  34. */
  35. EPuckSim::EPuckSim(char* robotName, int robotPort, int simulationPort)
  36. {
  37. initialise(robotPort, robotName, simulationPort);
  38. return;
  39. }
  40. /**
  41. Epuck destructor. Closes threads and stops the robot nicely (ish).
  42. */
  43. EPuckSim::~EPuckSim(void)
  44. {
  45. //close threads
  46. readSensorsThread.interrupt();
  47. readSensorsThread.join();
  48. stopFlashLEDs(); //stops the flashing LEDs and closes the thread
  49. //free the items in memory
  50. //this is probably unnecessary
  51. delete p2dProxy; //motors
  52. delete rangerProxy; //rangers
  53. delete blobProxy; //camera
  54. delete simProxy; //leds
  55. delete epuck;
  56. delete simulation;
  57. if(audioInitialised) delete handler;
  58. return;
  59. }
  60. bool EPuckSim::operator==(const EPuckSim& other)
  61. {
  62. int comparison = strcmp(other.name, name);
  63. return (comparison == 0);
  64. }
  65. /*====================================================================
  66. PUBLIC FUNCTIONS
  67. ====================================================================*/
  68. /*
  69. READ SENSORS
  70. */
  71. void EPuckSim::readSensors(void)
  72. {
  73. epuck->Read();
  74. return;
  75. }
  76. double EPuckSim::getTime(void)
  77. {
  78. uint64_t data;
  79. double time;
  80. char flag[] = "time";
  81. simProxy->GetProperty(name, flag, &data, sizeof(data));
  82. //printf("read value %f\n", (double)data);
  83. time = (double)data;
  84. time = time / 1000000;
  85. return time;
  86. }
  87. void EPuckSim::waitMilliseconds(int timeMs)
  88. {
  89. boost::posix_time::milliseconds wait(10);
  90. double endTime = getTime() + (double)timeMs/1000;
  91. while(getTime() < endTime)
  92. {
  93. boost::this_thread::sleep(wait);
  94. }
  95. return;
  96. }
  97. double EPuckSim::getBatteryVolts(void)
  98. {
  99. return EPuck::MAXIMUM_BATTERY_VOLTAGE;
  100. }
  101. void EPuckSim::getPosition(double& x, double& y, double& yaw)
  102. {
  103. simProxy->GetPose2d(name, x, y, yaw);
  104. return;
  105. }
  106. void EPuckSim::setPosition(double x, double y, double yaw)
  107. {
  108. simProxy->SetPose2d(name, x, y, yaw);
  109. return;
  110. }
  111. //************INFRA-RED SENSORS*******************
  112. double* EPuckSim::getIRReadings(void)
  113. {
  114. int i;
  115. for(i=0; i<getNumberOfIRs(); i++)
  116. {
  117. irReadings[i] = rangerProxy->GetRange(i);
  118. }
  119. return irReadings;
  120. }
  121. double EPuckSim::getIRReading(int index)
  122. {
  123. return rangerProxy->GetRange(index);
  124. }
  125. /**
  126. Tells you how many IR sensors there are on the robot.
  127. @return The number of IR sensors as an int.
  128. */
  129. int EPuckSim::getNumberOfIRs(void)
  130. {
  131. return 8;
  132. }
  133. //************BLOBFINDER SENSORS*******************
  134. int EPuckSim::getCameraWidth(void)
  135. {
  136. uint32_t w;
  137. int width;
  138. w = blobProxy->GetWidth();
  139. width = (int)w;
  140. if(width <= 0) return -1;
  141. else return width;
  142. }
  143. int EPuckSim::getCameraHeight(void)
  144. {
  145. uint32_t h;
  146. int height;
  147. h = blobProxy->GetHeight();
  148. height = (int)h;
  149. if(height <= 0) return -1;
  150. else return height;
  151. }
  152. int EPuckSim::getNumberBlobs(void)
  153. {
  154. uint32_t noBlobs;
  155. noBlobs = blobProxy->GetCount();
  156. return (int)noBlobs;
  157. }
  158. EPuck::Blob EPuckSim::getBlob(int index)
  159. {
  160. player_blobfinder_blob_t oldBlob;
  161. EPuck::Blob newBlob;
  162. oldBlob = blobProxy->GetBlob(index);
  163. newBlob.id = (int)oldBlob.id;
  164. newBlob.colour = oldBlob.color;
  165. newBlob.area = (int)oldBlob.area;
  166. newBlob.x = (int)oldBlob.x;
  167. newBlob.y = (int)oldBlob.y;
  168. newBlob.left = (int)oldBlob.left;
  169. newBlob.right = (int)oldBlob.right;
  170. newBlob.top = (int)oldBlob.top;
  171. newBlob.bottom = (int)oldBlob.bottom;
  172. return newBlob;
  173. }
  174. /*
  175. USE ACTUATORS
  176. */
  177. //*************************** MOTORS *****************************
  178. void EPuckSim::setMotors(double forward, double turnrate)
  179. {
  180. if(forward > EPuck::MAX_WHEEL_SPEED) forward = EPuck::MAX_WHEEL_SPEED;
  181. if(forward < (-1)*EPuck::MAX_WHEEL_SPEED) forward = (-1)*EPuck::MAX_WHEEL_SPEED;
  182. p2dProxy->SetSpeed(forward, turnrate);
  183. return;
  184. }
  185. void EPuckSim::setDifferentialMotors(double left, double right)
  186. {
  187. /* conversion of differential drive values to
  188. forward and turn speeds from
  189. http://www.physicsforums.com/showthread.php?t=263149 */
  190. //the inside wheel will have to turn at x/R radians per second while outside wheel turns at (x+ yL)/R radians per second.
  191. // L is distance between wheels, R is radius of wheels, x is forward speed y is turnrate in rads/sec.
  192. //const double radius = 40*0.001; //40 millimetres
  193. const double separation = 52*0.001; //52 millimetres
  194. double newspeed, newturnrate;
  195. //limit wheel speeds to+/- maximum
  196. if(left > EPuck::MAX_WHEEL_SPEED) left = EPuck::MAX_WHEEL_SPEED;
  197. if(left < (-1)*EPuck::MAX_WHEEL_SPEED) left = (-1)*EPuck::MAX_WHEEL_SPEED;
  198. if(right > EPuck::MAX_WHEEL_SPEED) right = EPuck::MAX_WHEEL_SPEED;
  199. if(right < (-1)*EPuck::MAX_WHEEL_SPEED) right = (-1)*EPuck::MAX_WHEEL_SPEED;
  200. /*inside wheel should turn at newspeed/radius radians per sec.
  201. inner(rads) * radius = newspeed
  202. we know wheel turn rate in metres/sec. Must convert to rads/sec.
  203. no wheel turns per sec is = inner(m)/2piRadius
  204. inner(rads) = no wheel turns * 2pi
  205. inner(rads) = inner(m)/Radius
  206. inner(m)/Radius * radius = newspeed
  207. */
  208. /* outer wheel turns at (newspeed+ newturnrate(rads)*separation)/Radius rads per second
  209. from before: outer(rads) = outer(m)/Radius
  210. outer(rads) = (newspeed+ newturnrate(rads)*separation)/Radius
  211. outer(m)/Radius = (newspeed+ newturnrate(rads)*separation)/Radius
  212. outer(m) = newspeed+ newturnrate(rads)*separation
  213. newturnrate(rads) = (outer(m) - newspeed)/separation
  214. */
  215. //which is the outer wheel and which is the inner?
  216. //outer wheel moves further so will be faster.
  217. if(left > right) //if left is outer wheel
  218. {
  219. //newspeed is inner wheel speed
  220. newspeed = right;
  221. //newturnrate = (outer(m) - newspeed)/separation
  222. newturnrate = (left - newspeed)/separation;
  223. newturnrate *= -1;
  224. }
  225. else if(right > left) //right is outer wheel
  226. {
  227. //newspeed is inner wheel speed
  228. newspeed = left;
  229. //newturnrate = (outer(m) - newspeed)/separation
  230. newturnrate = (right - newspeed)/separation;
  231. }
  232. else //going straight ahead
  233. {
  234. newspeed = left;
  235. newturnrate = 0;
  236. }
  237. //p2dProxy->SetSpeed(newspeed, newturnrate);
  238. setMotors(newspeed, newturnrate);
  239. return;
  240. }
  241. //******************************* LED FLASHING *************************************
  242. void EPuckSim::setAllLEDsOn(void)
  243. {
  244. float red[]={1, 0, 0, 1};
  245. char colour[]="color";
  246. simProxy->SetProperty(name, colour, &red, sizeof(red));
  247. allLEDsOn = true;
  248. return;
  249. }
  250. void EPuckSim::setAllLEDsOff(void)
  251. {
  252. float darkGreen[]={0.67, 0.88, 0.43, 1};
  253. char colour[]="color";
  254. simProxy->SetProperty(name, colour, &darkGreen, sizeof(darkGreen));
  255. allLEDsOn = false;
  256. return;
  257. }
  258. void EPuckSim::toggleAllLEDs(void)
  259. {
  260. if(allLEDsOn) setAllLEDsOff();
  261. else setAllLEDsOn();
  262. return;
  263. }
  264. void EPuckSim::setLED(int index, int state)
  265. {
  266. if(state == 1) setAllLEDsOn();
  267. else setAllLEDsOff();
  268. return;
  269. }
  270. void EPuckSim::flashLEDs(double frequency)
  271. {
  272. //user can also stop flashing LEDs with this function.
  273. if(frequency <= 0)
  274. {
  275. stopFlashLEDs();
  276. return;
  277. }
  278. flashLEDsThread = boost::thread(&EPuckSim::flashLEDsThreaded, this, frequency);
  279. //pthread_create(&flashLEDsThread, 0, EPuckSim::startFlashLEDsThread, this);
  280. return;
  281. }
  282. void EPuckSim::stopFlashLEDs(void)
  283. {
  284. flashLEDsThread.interrupt();
  285. flashLEDsThread.join();
  286. return;
  287. }
  288. //******************************* AUDIO *************************************
  289. int EPuckSim::initaliseAudio(void)
  290. {
  291. if(!audioInitialised)
  292. {
  293. handler = AudioHandler::GetAudioHandler(simulation, simProxy, name);
  294. //allocate space so that the first time the robot must listen there is somethign to delete.
  295. //toneArray = new Tone[1];
  296. audioInitialised = TRUE;
  297. return 0;
  298. }
  299. return -1;
  300. }
  301. AudioHandler* EPuckSim::getAudioHandler(void)
  302. {
  303. return handler;
  304. }
  305. int EPuckSim::playTone(int frequency, double duration)
  306. {
  307. if(audioInitialised)
  308. {
  309. handler->playTone(frequency, duration, name);
  310. return 0;
  311. }
  312. printf("Unsuccessful epuck %s playTone() request. Audio not initialised.\n", name);
  313. return -1;
  314. }
  315. std::vector<EPuck::Tone> EPuckSim::listenForTones(void)
  316. {
  317. std::vector<EPuck::Tone> out;
  318. out.clear();
  319. if(audioInitialised)
  320. {
  321. int success;
  322. int numberOfTones;
  323. AudioHandler::audio_message_t *message;
  324. //lock this function so that deleting and creating these arrays doesn't cause
  325. //memory leaks and segfaults.
  326. boost::mutex::scoped_lock lock(listeningMutex);
  327. do
  328. {
  329. //reserve space for new tone data
  330. numberOfTones = handler->getNumberOfTones();
  331. message = new AudioHandler::audio_message_t[numberOfTones];
  332. success = handler->getTones(name, message, numberOfTones);
  333. if(success == -1) delete[] message;
  334. }while(success == -1); //if unsuccessful try again
  335. for(int i=0; i<numberOfTones; i++)
  336. {
  337. EPuck::Tone t;
  338. t.distance = message[i].distance;
  339. t.bearing = message[i].direction;
  340. t.frequency = message[i].frequency;
  341. out.push_back(t);
  342. }
  343. delete[] message;
  344. }
  345. else
  346. printf("Unsuccessful epuck %s listenToTones() request. Audio not initialised.\n", name);
  347. return out;
  348. }
  349. /*
  350. int EPuckSim::listenForTones(void)
  351. {
  352. int i;
  353. AudioHandler::audio_message_t *message;
  354. if(audioInitialised)
  355. {
  356. int success;
  357. //lock this function so that deleting and creating these arrays doesn't cause
  358. //memory leaks and segfaults.
  359. boost::mutex::scoped_lock lock(listeningMutex);
  360. do
  361. {
  362. //need to remember how many tones were allocated last time and free that memory
  363. if(numberOfTones > 0) delete[] toneArray;
  364. //reserve space for new tone data
  365. numberOfTones = handler->getNumberOfTones();
  366. toneArray = new Tone[numberOfTones];
  367. message = new AudioHandler::audio_message_t[numberOfTones];
  368. success = handler->getTones(name, message, sizeof(AudioHandler::audio_message_t)*numberOfTones);
  369. if(success == -1) delete[] message;
  370. }while(success == -1);
  371. for(i=0; i<numberOfTones; i++)
  372. {
  373. toneArray[i].distance = message[i].distance;
  374. toneArray[i].bearing = message[i].direction;
  375. toneArray[i].frequency = message[i].frequency;
  376. }
  377. return numberOfTones;
  378. }
  379. printf("Unsuccessful epuck %s listenToTones() request. Audio not initialised.\n", name);
  380. return -1;
  381. }*/
  382. #if DEBUGGING == 1
  383. void EPuckSim::printLocation_TEST(void)
  384. {
  385. double x, y, yaw;
  386. simProxy->GetPose2d(name, x, y, yaw);
  387. printf("%s is at location: (%f, %f) and yaw %f radians\n", name, x, y, yaw);
  388. return;
  389. }
  390. void EPuckSim::printTimes_TEST(void)
  391. {
  392. printf("current time(NULL) is %f\n", (double)time(NULL));
  393. printf("current data time is %f\n", simProxy->GetDataTime());
  394. return;
  395. }
  396. void EPuckSim::dumpAudio_TEST(void)
  397. {
  398. handler->dumpData_TEST();
  399. return;
  400. }
  401. void EPuckSim::dumpToneData_TEST(AudioHandler::audio_message_t *store, size_t storesize)
  402. {
  403. int i;
  404. int numberAllocatedSlots = storesize/sizeof(AudioHandler::audio_message_t);
  405. printf("Dumping tone data as recieved from AudioHandler:\n");
  406. for(i=0; i<numberAllocatedSlots; i++)
  407. {
  408. printf("\tbin number %d\n", i);
  409. printf("\tfrequency %f\n\tvolume %f\n\tdirection %d\n", store[i].frequency, store[i].volume, store[i].direction);
  410. }
  411. }
  412. #endif
  413. /*====================================================================
  414. PRIVATE FUNCTIONS
  415. ====================================================================*/
  416. void EPuckSim::initialise(int robotPort, char* robotName, int simulationPort)
  417. {
  418. //initialise member variables
  419. strcpy(name, robotName);
  420. port = robotPort;
  421. allLEDsOn = false;
  422. audioInitialised = false;
  423. //toneArray = NULL;
  424. try
  425. {
  426. epuck = new PlayerCc::PlayerClient("localhost", port);
  427. simulation = new PlayerCc::PlayerClient("localhost", simulationPort);
  428. p2dProxy = new PlayerCc::Position2dProxy(epuck, 0);
  429. // rangerProxy = new PlayerCc::RangerProxy(epuck, 0);
  430. // blobProxy = new PlayerCc::BlobfinderProxy(epuck, 0);
  431. simProxy = new PlayerCc::SimulationProxy(simulation, 0);
  432. }
  433. catch (PlayerCc::PlayerError e)
  434. {
  435. std::cerr << e << std::endl;
  436. return;
  437. }
  438. // readSensorsThread = boost::thread(&EPuckSim::readSensorsThreaded, this);
  439. // pthread_create(&readSensorsThread, 0, EPuckSim::startReadSensorThread, this);
  440. }
  441. void EPuckSim::readSensorsThreaded(void)
  442. {
  443. printf("%s is threaded\n", name);
  444. boost::posix_time::milliseconds wait(10);
  445. while(true)
  446. {
  447. epuck->Read();
  448. boost::this_thread::sleep(wait);
  449. }
  450. return;
  451. }
  452. void EPuckSim::flashLEDsThreaded(int ledFlashFrequency)
  453. {
  454. double period = 1/ledFlashFrequency; //flash period in seconds
  455. period = period*1000; //now in milliseconds
  456. period = period/2; //will toggle LEDs each half period
  457. boost::posix_time::milliseconds wait(period);
  458. while(true)
  459. {
  460. toggleAllLEDs();
  461. boost::this_thread::sleep(wait);
  462. }
  463. return;
  464. }