Ein Roboter mit bürstenlosem Antrieb, differenzial und NRF24L01 Funk. Großflächig gebaut um ein großes Solarpanel aufzunehmen. https://gitlab.informatik.hs-fulda.de/fdai5253/roboter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
10 KiB

  1. /*
  2. Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. version 2 as published by the Free Software Foundation.
  6. */
  7. /**
  8. * Full test on single RF pair
  9. *
  10. * This sketches uses as many RF24 methods as possible in a single test.
  11. *
  12. * To operate:
  13. * Upload this sketch on two nodes, each with IRQ -> pin 2
  14. * One node needs pin 7 -> GND, the other NC. That's the receiving node
  15. * Monitor the sending node's serial output
  16. * Look for "+OK PASS" or "+OK FAIL"
  17. */
  18. #include <SPI.h>
  19. #include "nRF24L01.h"
  20. #include "RF24.h"
  21. #include "printf.h"
  22. //
  23. // Hardware configuration
  24. //
  25. // Set up nRF24L01 radio on SPI bus plus pins 8 & 9
  26. RF24 radio(7,8);
  27. // sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
  28. // Leave open to be the 'ping' transmitter
  29. const short role_pin = 5;
  30. //
  31. // Topology
  32. //
  33. // Single radio pipe address for the 2 nodes to communicate.
  34. const uint64_t pipe = 0xE8E8F0F0E1LL;
  35. //
  36. // Role management
  37. //
  38. // Set up role. This sketch uses the same software for all the nodes in this
  39. // system. Doing so greatly simplifies testing. The hardware itself specifies
  40. // which node it is.
  41. //
  42. // This is done through the role_pin
  43. //
  44. // The various roles supported by this sketch
  45. typedef enum { role_sender = 1, role_receiver } role_e;
  46. // The debug-friendly names of those roles
  47. const char* role_friendly_name[] = { "invalid", "Sender", "Receiver"};
  48. // The role of the current running sketch
  49. role_e role;
  50. // Interrupt handler, check the radio because we got an IRQ
  51. void check_radio(void);
  52. //
  53. // Payload
  54. //
  55. const int min_payload_size = 4;
  56. const int max_payload_size = 32;
  57. int payload_size_increments_by = 2;
  58. int next_payload_size = min_payload_size;
  59. char receive_payload[max_payload_size+1]; // +1 to allow room for a terminating NULL char
  60. //
  61. // Test state
  62. //
  63. bool done; //*< Are we done with the test? */
  64. bool passed; //*< Have we passed the test? */
  65. bool notified; //*< Have we notified the user we're done? */
  66. const int num_needed = 10; //*< How many success/failures until we're done? */
  67. int receives_remaining = num_needed; //*< How many ack packets until we declare victory? */
  68. int failures_remaining = num_needed; //*< How many more failed sends until we declare failure? */
  69. const int interval = 100; //*< ms to wait between sends */
  70. char configuration = '1'; //*< Configuration key, one char sent in by the test framework to tell us how to configure, this is the default */
  71. uint8_t pipe_number = 1; // Which pipe to send on.
  72. void one_ok(void)
  73. {
  74. // Have we received enough yet?
  75. if ( ! --receives_remaining )
  76. {
  77. done = true;
  78. passed = true;
  79. }
  80. }
  81. void one_failed(void)
  82. {
  83. // Have we failed enough yet?
  84. if ( ! --failures_remaining )
  85. {
  86. done = true;
  87. passed = false;
  88. }
  89. }
  90. //
  91. // Setup
  92. //
  93. void setup(void)
  94. {
  95. //
  96. // Role
  97. //
  98. // set up the role pin
  99. pinMode(role_pin, INPUT);
  100. digitalWrite(role_pin,HIGH);
  101. delay(20); // Just to get a solid reading on the role pin
  102. // read the address pin, establish our role
  103. if ( digitalRead(role_pin) )
  104. role = role_sender;
  105. else
  106. role = role_receiver;
  107. //
  108. // Print preamble
  109. //
  110. Serial.begin(115200);
  111. printf_begin();
  112. printf("\n\rRF24/tests/pingpair_test/\n\r");
  113. printf("ROLE: %s\n\r",role_friendly_name[role]);
  114. //
  115. // Read configuration from serial
  116. //
  117. // It would be a much better test if this program could accept configuration
  118. // from the serial port. Then it would be possible to run the same test under
  119. // lots of different circumstances.
  120. //
  121. // The idea is that we will print "+READY" at this point. The python script
  122. // will wait for it, and then send down a configuration script that we
  123. // execute here and then run with.
  124. //
  125. // The test controller will need to configure the receiver first, then go run
  126. // the test on the sender.
  127. //
  128. printf("+READY press any key to start\n\r\n\r");
  129. while (! Serial.available() ) {}
  130. configuration = Serial.read();
  131. printf("Configuration\t = %c\n\r",configuration);
  132. //
  133. // Setup and configure rf radio
  134. //
  135. radio.begin();
  136. // We will be using the Ack Payload feature, so please enable it
  137. radio.enableAckPayload();
  138. // Config 2 is special radio config
  139. if (configuration=='2')
  140. {
  141. radio.setCRCLength(RF24_CRC_8);
  142. radio.setDataRate(RF24_250KBPS);
  143. radio.setChannel(10);
  144. }
  145. else
  146. {
  147. //Otherwise, default radio config
  148. // Optional: Increase CRC length for improved reliability
  149. radio.setCRCLength(RF24_CRC_16);
  150. // Optional: Decrease data rate for improved reliability
  151. radio.setDataRate(RF24_1MBPS);
  152. // Optional: Pick a high channel
  153. radio.setChannel(90);
  154. }
  155. // Config 3 is static payloads only
  156. if (configuration == '3')
  157. {
  158. next_payload_size = 16;
  159. payload_size_increments_by = 0;
  160. radio.setPayloadSize(next_payload_size);
  161. }
  162. else
  163. {
  164. // enable dynamic payloads
  165. radio.enableDynamicPayloads();
  166. }
  167. // Config 4 tests out a higher pipe ##
  168. if (configuration == '4' && role == role_sender)
  169. {
  170. // Set top 4 bytes of the address in pipe 1
  171. radio.openReadingPipe(1,pipe & 0xFFFFFFFF00ULL);
  172. // indicate the pipe to use
  173. pipe_number = 5;
  174. }
  175. else if ( role == role_sender )
  176. {
  177. radio.openReadingPipe(5,0);
  178. }
  179. //
  180. // Open pipes to other nodes for communication
  181. //
  182. // This simple sketch opens a single pipe for these two nodes to communicate
  183. // back and forth. One listens on it, the other talks to it.
  184. if ( role == role_sender )
  185. {
  186. radio.openWritingPipe(pipe);
  187. }
  188. else
  189. {
  190. radio.openReadingPipe(pipe_number,pipe);
  191. }
  192. //
  193. // Start listening
  194. //
  195. if ( role == role_receiver )
  196. radio.startListening();
  197. //
  198. // Dump the configuration of the rf unit for debugging
  199. //
  200. radio.printDetails();
  201. //
  202. // Attach interrupt handler to interrupt #0 (using pin 2)
  203. // on BOTH the sender and receiver
  204. //
  205. attachInterrupt(0, check_radio, FALLING);
  206. delay(50);
  207. if ( role == role_receiver )
  208. printf("\n\r+OK ");
  209. }
  210. //
  211. // Print buffer
  212. //
  213. // Printing from the interrupt handler is a bad idea, so we print from there
  214. // to this intermediate buffer
  215. //
  216. char prbuf[1000];
  217. char *prbuf_end = prbuf + sizeof(prbuf);
  218. char *prbuf_in = prbuf;
  219. char *prbuf_out = prbuf;
  220. //
  221. // Loop
  222. //
  223. static uint32_t message_count = 0;
  224. static uint32_t last_message_count = 0;
  225. void loop(void)
  226. {
  227. //
  228. // Sender role. Repeatedly send the current time
  229. //
  230. if (role == role_sender && !done)
  231. {
  232. // The payload will always be the same, what will change is how much of it we send.
  233. static char send_payload[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ789012";
  234. // First, stop listening so we can talk.
  235. radio.stopListening();
  236. // Send it. This will block until complete
  237. printf("\n\rNow sending length %i...",next_payload_size);
  238. radio.startWrite( send_payload, next_payload_size,0 );
  239. // Update size for next time.
  240. next_payload_size += payload_size_increments_by;
  241. if ( next_payload_size > max_payload_size )
  242. next_payload_size = min_payload_size;
  243. // Try again soon
  244. delay(interval);
  245. // Timeout if we have not received anything back ever
  246. if ( ! last_message_count && millis() > interval * 100 )
  247. {
  248. printf("No responses received. Are interrupts connected??\n\r");
  249. done = true;
  250. }
  251. }
  252. //
  253. // Receiver role: Does nothing! All the work is in IRQ
  254. //
  255. //
  256. // Spew print buffer
  257. //
  258. size_t write_length = prbuf_in - prbuf_out;
  259. if ( write_length )
  260. {
  261. Serial.write(reinterpret_cast<uint8_t*>(prbuf_out),write_length);
  262. prbuf_out += write_length;
  263. }
  264. //
  265. // Stop the test if we're done and report results
  266. //
  267. if ( done && ! notified )
  268. {
  269. notified = true;
  270. printf("\n\r+OK ");
  271. if ( passed )
  272. printf("PASS\n\r\n\r");
  273. else
  274. printf("FAIL\n\r\n\r");
  275. }
  276. }
  277. void check_radio(void)
  278. {
  279. // What happened?
  280. bool tx,fail,rx;
  281. radio.whatHappened(tx,fail,rx);
  282. // Have we successfully transmitted?
  283. if ( tx )
  284. {
  285. if ( role == role_sender )
  286. prbuf_in += sprintf(prbuf_in,"Send:OK ");
  287. if ( role == role_receiver )
  288. prbuf_in += sprintf(prbuf_in,"Ack Payload:Sent\n\r");
  289. }
  290. // Have we failed to transmit?
  291. if ( fail )
  292. {
  293. if ( role == role_sender )
  294. {
  295. prbuf_in += sprintf(prbuf_in,"Send:Failed ");
  296. // log status of this line
  297. one_failed();
  298. }
  299. if ( role == role_receiver )
  300. prbuf_in += sprintf(prbuf_in,"Ack Payload:Failed\n\r");
  301. }
  302. // Not powering down since radio is in standby mode
  303. //if ( ( tx || fail ) && ( role == role_sender ) )
  304. //radio.powerDown();
  305. // Did we receive a message?
  306. if ( rx )
  307. {
  308. // If we're the sender, we've received an ack payload
  309. if ( role == role_sender )
  310. {
  311. radio.read(&message_count,sizeof(message_count));
  312. prbuf_in += sprintf(prbuf_in,"Ack:%lu ",message_count);
  313. // is this ack what we were expecting? to account
  314. // for failures, we simply want to make sure we get a
  315. // DIFFERENT ack every time.
  316. if ( ( message_count != last_message_count ) || ( configuration=='3' && message_count == 16 ) )
  317. {
  318. prbuf_in += sprintf(prbuf_in,"OK ");
  319. one_ok();
  320. }
  321. else
  322. {
  323. prbuf_in += sprintf(prbuf_in,"FAILED ");
  324. one_failed();
  325. }
  326. last_message_count = message_count;
  327. }
  328. // If we're the receiver, we've received a time message
  329. if ( role == role_receiver )
  330. {
  331. // Get this payload and dump it
  332. size_t len = max_payload_size;
  333. memset(receive_payload,0,max_payload_size);
  334. if ( configuration == '3' ){
  335. len = next_payload_size;
  336. }else{
  337. len = radio.getDynamicPayloadSize();
  338. }
  339. radio.read( receive_payload, len );
  340. // Put a zero at the end for easy printing
  341. receive_payload[len] = 0;
  342. // Spew it
  343. prbuf_in += sprintf(prbuf_in,"Recv size=%i val=%s len=%u\n\r",len,receive_payload,strlen(receive_payload));
  344. // Add an ack packet for the next time around.
  345. // Here we will report back how many bytes we got this time.
  346. radio.writeAckPayload( pipe_number, &len, sizeof(len) );
  347. ++message_count;
  348. }
  349. }
  350. }