crazyflie.ino 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // crazyflie.pde
  2. // -*- mode: C++ -*-
  3. //
  4. // This sketch act like a Crazyflie quadcopter http://www.bitcraze.se/
  5. // using the CRTP radiolink protocol:
  6. // http://wiki.bitcraze.se/projects:crazyflie:firmware:comm_protocol
  7. //
  8. // Requires
  9. // - NRF24 radio module such as the sparkfun WRL-00691 http://www.sparkfun.com/products/691
  10. // - Arduino such as Uno
  11. // - A Crazyflie transmitter, such as the Carzyflie PC client+CrazyRadio module
  12. // or
  13. // the NRF24 crazyflie client part of the NRF24 library
  14. //
  15. // Uses NRF24 library to comunicate with the Crazyflie,
  16. // http://www.airspayce.com/mikem/arduino/NRF24
  17. //
  18. // Receives and decodes varion message types from teh Crazyflie transmitter, although
  19. // only the link echo and commander messages are fully implemented
  20. //
  21. // Author: Mike McCauley
  22. // Copyright (C) 2012 Mike McCauley
  23. #include <NRF24.h>
  24. #include <SPI.h>
  25. // Structure of Crazyflie commander messages
  26. #pragma pack(1);
  27. typedef struct
  28. {
  29. float roll;
  30. float pitch;
  31. float yaw;
  32. uint16_t thrust;
  33. } CommanderCrtpValues;
  34. #pragma pack()
  35. // Useful macros for CRTP message contents and formatting
  36. #define CRTP_HEADER(port, channel) (((port & 0x0F) << 4) | (channel & 0x0F))
  37. #define CRTP_HEADER_PORT(h) ((h >> 4) & 0xf)
  38. #define CRTP_HEADER_CHANNEL(h) (h & 0x3)
  39. // Param channels
  40. #define PARAM_TOC_CH 0
  41. #define PARAM_READ_CH 1
  42. #define PARAM_WRITE_CH 2
  43. // Log channels
  44. #define LOG_TOC_CH 0
  45. #define LOG_CONTROL_CH 1
  46. #define LOG_LOG_CH 2
  47. // Log packet parameters storage
  48. #define LOG_MAX_OPS 64
  49. #define LOG_MAX_BLOCKS 8
  50. // Port definitions
  51. typedef enum {
  52. CRTP_PORT_CONSOLE = 0x00,
  53. CRTP_PORT_PARAM = 0x02,
  54. CRTP_PORT_COMMANDER = 0x03,
  55. CRTP_PORT_LOG = 0x05,
  56. CRTP_PORT_LINK = 0x0F,
  57. } CRTPPort;
  58. // Common command numbers
  59. #define CMD_GET_ITEM 0
  60. #define CMD_GET_INFO 1
  61. // Singleton instance of the radio
  62. NRF24 nrf24;
  63. // NRF24 nrf24(8, 7); // use this to be electrically compatible with Mirf
  64. // NRF24 nrf24(8, 10);// For Leonardo, need explicit SS pin
  65. // The address to use for this Crazyflie
  66. uint8_t address[] = { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7 };
  67. void setup()
  68. {
  69. Serial.begin(115200);
  70. while (!Serial)
  71. ; // Wait for serial port, only required for Leonardo
  72. if (!nrf24.init())
  73. Serial.println("NRF24 init failed");
  74. // Be Crazyflie radiolink compatible
  75. // We use the NRF24 library for convenience, but
  76. // we use a different configuration to the default NRF24
  77. if (!nrf24.setChannel(13))
  78. Serial.println("setChannel failed");
  79. // Set data rate to 250k and low power
  80. if (!nrf24.setRF(NRF24::NRF24DataRate250kbps, NRF24::NRF24TransmitPower0dBm))
  81. Serial.println("setRF failed");
  82. if (!nrf24.setPipeAddress(0, address, sizeof(address)))
  83. Serial.println("setPipeAddress failed");
  84. // Be compatible with Crazyflie: No interrupts, 2 bytes CRC
  85. nrf24.setConfiguration(NRF24_MASK_RX_DR | NRF24_MASK_TX_DS | NRF24_MASK_MAX_RT | NRF24_EN_CRC | NRF24_CRCO);
  86. nrf24.spiWriteRegister(NRF24_REG_1D_FEATURE, NRF24_EN_DPL | NRF24_EN_ACK_PAY); // Dynamic size payload + ack
  87. nrf24.spiWriteRegister(NRF24_REG_1C_DYNPD, NRF24_DPL_P0); // Dynamic payload on pipe 0
  88. if (!nrf24.setRetry(6, 3)) // 1500us and 3 retries
  89. Serial.println("setRetry failed");
  90. Serial.println("initialised");
  91. }
  92. // Debugging data dumper
  93. void dump(char* prompt, uint8_t* data, uint8_t len)
  94. {
  95. Serial.print(prompt);
  96. Serial.print(": ");
  97. for (int i = 0; i < len; i++)
  98. {
  99. Serial.print(data[i], HEX);
  100. Serial.print(" ");
  101. }
  102. Serial.println("");
  103. }
  104. // Send an ACK with a payload on pipe 0
  105. void sendAckPayload(uint8_t* data, uint8_t len)
  106. {
  107. nrf24.spiBurstWrite(NRF24_COMMAND_W_ACK_PAYLOAD(0), data, len);
  108. nrf24.waitPacketSent();
  109. }
  110. // ACK with no payload on pipe 0
  111. void sendAck()
  112. {
  113. sendAckPayload(0, 0);
  114. }
  115. void loop()
  116. {
  117. uint8_t buf[100];
  118. uint8_t buflen = sizeof(buf);
  119. static uint32_t last_second = 0;
  120. // enable receiver again, after transmit and wait for a message
  121. nrf24.waitAvailable();
  122. if (nrf24.recv(buf, &buflen))
  123. {
  124. // Decode incoming messages from client based on port number in the header byte
  125. // dump("msg", buf, buflen);
  126. if (CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_LINK) // Link Echo
  127. {
  128. sendAck(); // Just ack, no payload
  129. }
  130. else if (CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_COMMANDER) // Commander
  131. {
  132. // Commander message to set control positions
  133. CommanderCrtpValues *p = (CommanderCrtpValues*)(buf+1);
  134. Serial.println(p->roll); // -30.0 to 30.0
  135. Serial.println(p->pitch); // -28.0 to 32.0
  136. Serial.println(p->yaw); // -200.0 to 200.0
  137. Serial.println(p->thrust); // 0 to 45755
  138. sendAck(); // Just ack, no payload
  139. // dump("commander", buf, buflen);
  140. }
  141. else if (CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_PARAM) // Parameter
  142. {
  143. if (buf[1] == CMD_GET_INFO) // Param GET_INFO
  144. {
  145. // pc client only fetches item data if the CRC changes
  146. // If you change the contents of your TOC, you must change the CRC
  147. // Crazyflie PC client doesnt relaly believe it if you say there are no TOC entries
  148. uint8_t reply[] = { CRTP_HEADER(CRTP_PORT_PARAM, PARAM_TOC_CH), CMD_GET_INFO, 1, 0, 0, 2, 0}; // 1 params in toc
  149. sendAckPayload(reply, sizeof(reply));
  150. }
  151. else if (buf[1] == CMD_GET_ITEM) // Param GET_ITEM
  152. {
  153. // Set up a fax param as item 0
  154. uint8_t reply[] = { CRTP_HEADER(CRTP_PORT_PARAM, PARAM_TOC_CH), CMD_GET_ITEM, 0, 1, 'x', 0, 'y', 0}; // bogus item 0 uint8_t param
  155. sendAckPayload(reply, sizeof(reply));
  156. }
  157. else
  158. {
  159. Serial.print("unknown param type ");
  160. Serial.println(buf[1]);
  161. }
  162. // dump("param", buf, buflen);
  163. }
  164. else if (buf[0] == CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_PARAM) // Log
  165. {
  166. // http://wiki.bitcraze.se/projects:crazyflie:crtp:log
  167. if (buf[1] == CMD_GET_INFO) // Log GET_INFO
  168. {
  169. // pc client only fetches item data if the CRC changes
  170. // If you change the contents of your TOC, you must change the CRC
  171. // Crazyflie PC client doesnt relaly believe it if you say there are no TOC entries
  172. uint8_t reply[] = { CRTP_HEADER(CRTP_PORT_LOG, LOG_TOC_CH), CMD_GET_INFO, 1, 0, 0, 2, 1, 8, 64}; // 1 log item in toc
  173. sendAckPayload(reply, sizeof(reply));
  174. }
  175. else if (buf[1] == CMD_GET_ITEM) // Log GET_ITEM
  176. {
  177. // Set up a fake battery voltage as item 0
  178. uint8_t reply[] = { CRTP_HEADER(CRTP_PORT_LOG, LOG_TOC_CH), CMD_GET_ITEM, 0, 7, 'p', 'm', 0, 'v', 'b', 'a', 't', 0}; // item 0 float pm.vbat
  179. sendAckPayload(reply, sizeof(reply));
  180. }
  181. // dump("log", buf, buflen);
  182. }
  183. else
  184. {
  185. // Sometimes get bogus type 0x93
  186. // dump("unknown", buf, buflen);
  187. }
  188. }
  189. // Do once per second tasks
  190. uint32_t this_second = millis() / 1000;
  191. if (this_second != last_second)
  192. {
  193. // This is how you would send value data for a log block
  194. // with current real-time data
  195. // if a log block has ben set up by the client
  196. // uint8_t msg[] = {CRTP_HEADER(CRTP_PORT_LOG, LOG_LOG_CH), 0, 0, 0, 0, 11, 11, 11, 11};
  197. // sendAckPayload(msg, sizeof(msg));
  198. last_second = this_second;
  199. }
  200. }