crazyflie_client.ino 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // crazyflie_client.pde
  2. // -*- mode: C++ -*-
  3. //
  4. // This sketch act like a Crazyflie client (ie the transmitter) using the CRTP radiolink protocol:
  5. // http://wiki.bitcraze.se/projects:crazyflie:firmware:comm_protocol
  6. // to control a Crazyflie quadcopter http://www.bitcraze.se/
  7. //
  8. // Requires
  9. // - RC Transmitter that can act in trainer mode (eg Spektrum DX6i and others)
  10. // - NRF24 radio module such as the sparkfun WRL-00691 http://www.sparkfun.com/products/691
  11. // - Arduino such as Uno
  12. //
  13. // Uses NRF24 library to comunicate withthe Crazyflie,
  14. // http://www.airspayce.com/mikem/arduino/NRF24
  15. // and uses
  16. // the RcTrainer library to get servo positions from an RC transmitter running as a trainer
  17. // see http://www.airspayce.com/mikem/arduino/RcTrainer
  18. // Transmits the servo posiiotns to the Crazyflie, therefore allowing you to control the Crazyflie from
  19. // a conventional RC transmitter (ie no PC and no CrazyRadio module required).
  20. //
  21. // Only uses the Link ECHO and commander messages. No Log or Param messages are used
  22. // Author: Mike McCauley
  23. // Copyright (C) 2012 Mike McCauley
  24. #include <NRF24.h>
  25. #include <SPI.h>
  26. #include <RcTrainer.h>
  27. // Structure of Crazyflie commander messages
  28. #pragma pack(1);
  29. typedef struct
  30. {
  31. float roll;
  32. float pitch;
  33. float yaw;
  34. uint16_t thrust;
  35. } CommanderCrtpValues;
  36. #pragma pack()
  37. // Useful macros for CRTP message contents and formatting
  38. #define CRTP_HEADER(port, channel) (((port & 0x0F) << 4) | (channel & 0x0F))
  39. #define CRTP_HEADER_PORT(h) ((h >> 4) & 0xf)
  40. #define CRTP_HEADER_CHANNEL(h) (h & 0x3)
  41. // Param channels
  42. #define PARAM_TOC_CH 0
  43. #define PARAM_READ_CH 1
  44. #define PARAM_WRITE_CH 2
  45. // Log channels
  46. #define LOG_TOC_CH 0
  47. #define LOG_CONTROL_CH 1
  48. #define LOG_LOG_CH 2
  49. // Log packet parameters storage
  50. #define LOG_MAX_OPS 64
  51. #define LOG_MAX_BLOCKS 8
  52. // Port definitions
  53. typedef enum {
  54. CRTP_PORT_CONSOLE = 0x00,
  55. CRTP_PORT_PARAM = 0x02,
  56. CRTP_PORT_COMMANDER = 0x03,
  57. CRTP_PORT_LOG = 0x05,
  58. CRTP_PORT_LINK = 0x0F,
  59. } CRTPPort;
  60. // Common command numbers
  61. #define CMD_GET_ITEM 0
  62. #define CMD_GET_INFO 1
  63. // Singleton instance of the radio
  64. NRF24 nrf24;
  65. // NRF24 nrf24(8, 7); // use this to be electrically compatible with Mirf
  66. // NRF24 nrf24(8, 10);// For Leonardo, need explicit SS pin
  67. // The currently used radio channel
  68. uint8_t channel;
  69. // The expected address of the Crazyflie server (copter)
  70. // This is in fact also the default address of the NRF24
  71. uint8_t address[] = { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7 };
  72. uint32_t failed_packet_count = 0;
  73. // Object to get servo positions from RC trainer on pin D2
  74. RcTrainer rc;
  75. void setup()
  76. {
  77. Serial.begin(115200);
  78. while (!Serial)
  79. ; // Wait for serial port, only required for Leonardo
  80. if (!nrf24.init())
  81. Serial.println("NRF24 init failed");
  82. // Be Crazyflie radiolink compatible
  83. // We use the NRF24 library for convenience, but
  84. // we use a different configuration to the default NRF24
  85. if (!nrf24.setChannel(13))
  86. Serial.println("setChannel failed");
  87. // Set data rate to 250k and low power
  88. if (!nrf24.setRF(NRF24::NRF24DataRate250kbps, NRF24::NRF24TransmitPower0dBm))
  89. Serial.println("setRF failed");
  90. // Be compatible with Crazyflie: No interrupts, 2 bytes CRC
  91. nrf24.setConfiguration(NRF24_MASK_RX_DR | NRF24_MASK_TX_DS | NRF24_MASK_MAX_RT | NRF24_EN_CRC | NRF24_CRCO);
  92. nrf24.spiWriteRegister(NRF24_REG_1D_FEATURE, NRF24_EN_DPL | NRF24_EN_ACK_PAY); // Dynamic size payload + ack
  93. nrf24.spiWriteRegister(NRF24_REG_1C_DYNPD, NRF24_DPL_P0); // Dynamic payload on pipe 0
  94. if (!nrf24.setRetry(6, 3)) // 1500us and 3 retries
  95. Serial.println("setRetry failed");
  96. if (!nrf24.setTransmitAddress(address, sizeof(address)))
  97. Serial.println("setTransmitAddress failed");
  98. Serial.println("initialised");
  99. }
  100. // Debugging data dumper
  101. void dump(char* prompt, uint8_t* data, uint8_t len)
  102. {
  103. Serial.print(prompt);
  104. Serial.print(": ");
  105. for (int i = 0; i < len; i++)
  106. {
  107. Serial.print(data[i], HEX);
  108. Serial.print(" ");
  109. }
  110. Serial.println("");
  111. }
  112. // Scan for a Crazyflie server (ie a copter) that responds
  113. // If one is found, set the channel and return true
  114. boolean scan()
  115. {
  116. // Standard LINK echo message
  117. // If there is a Crazyflie present on a channel it will reply with an ACK and no payload
  118. uint8_t msg[] = { CRTP_HEADER(CRTP_PORT_LINK, 3) };
  119. for (channel = 0; channel < 125; channel++)
  120. {
  121. nrf24.setChannel(channel);
  122. if (!nrf24.send(msg, sizeof(msg)))
  123. Serial.println("scan send failed");
  124. if (nrf24.waitPacketSent())
  125. return true; // Got an ACK, expect no payload. This channel works, use it
  126. }
  127. return false;
  128. }
  129. // Send a message to the copter and detect failures
  130. void send(uint8_t* data, uint8_t len)
  131. {
  132. if (!nrf24.send(data, len))
  133. Serial.println("send failed");
  134. if (nrf24.waitPacketSent())
  135. {
  136. // Analyze payload?
  137. }
  138. else
  139. {
  140. failed_packet_count++;
  141. }
  142. }
  143. void loop()
  144. {
  145. // Poll until we have a positive response from a Crazyflie
  146. // and then use its channel
  147. while (!scan())
  148. ;
  149. // Now run a session with the one we found...
  150. failed_packet_count = 0;
  151. Serial.print("found a crazyflie on channel: ");
  152. Serial.println(channel);
  153. // ...until we get too many comms failures
  154. while (failed_packet_count < 50)
  155. {
  156. // Send a commander message
  157. uint8_t buf[32];
  158. buf[0] = CRTP_HEADER(CRTP_PORT_COMMANDER, 0);
  159. CommanderCrtpValues* msg = (CommanderCrtpValues*)(buf+1);
  160. // Mode 2 stick layout, map standard stick values to suitable Crazyflie commander ranges
  161. msg->roll = map(rc.getChannel(1), 0, 1023, 30.0, -30.0);
  162. msg->pitch = map(rc.getChannel(2), 0, 1023, 30.0, -30.0);
  163. msg->yaw = map(rc.getChannel(3), 0, 1023, 200.0, -200.0);
  164. msg->thrust = map(rc.getChannel(0), 0, 1023, 0, 65000);
  165. send(buf, sizeof(CommanderCrtpValues) + 1);
  166. delay(20); // 50 per sec
  167. }
  168. Serial.println("connection failed");
  169. // Too many failed messages, fall out here and rescan for a new Crazyflie
  170. }