| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- // crazyflie.pde
- // -*- mode: C++ -*-
- //
- // This sketch act like a Crazyflie quadcopter http://www.bitcraze.se/
- // using the CRTP radiolink protocol:
- // http://wiki.bitcraze.se/projects:crazyflie:firmware:comm_protocol
- //
- // Requires
- // - NRF24 radio module such as the sparkfun WRL-00691 http://www.sparkfun.com/products/691
- // - Arduino such as Uno
- // - A Crazyflie transmitter, such as the Carzyflie PC client+CrazyRadio module
- // or
- // the NRF24 crazyflie client part of the NRF24 library
- //
- // Uses NRF24 library to comunicate with the Crazyflie,
- // http://www.airspayce.com/mikem/arduino/NRF24
- //
- // Receives and decodes varion message types from teh Crazyflie transmitter, although
- // only the link echo and commander messages are fully implemented
- //
- // Author: Mike McCauley
- // Copyright (C) 2012 Mike McCauley
- #include <NRF24.h>
- #include <SPI.h>
- // Structure of Crazyflie commander messages
- #pragma pack(1);
- typedef struct
- {
- float roll;
- float pitch;
- float yaw;
- uint16_t thrust;
- } CommanderCrtpValues;
- #pragma pack()
- // Useful macros for CRTP message contents and formatting
- #define CRTP_HEADER(port, channel) (((port & 0x0F) << 4) | (channel & 0x0F))
- #define CRTP_HEADER_PORT(h) ((h >> 4) & 0xf)
- #define CRTP_HEADER_CHANNEL(h) (h & 0x3)
- // Param channels
- #define PARAM_TOC_CH 0
- #define PARAM_READ_CH 1
- #define PARAM_WRITE_CH 2
- // Log channels
- #define LOG_TOC_CH 0
- #define LOG_CONTROL_CH 1
- #define LOG_LOG_CH 2
- // Log packet parameters storage
- #define LOG_MAX_OPS 64
- #define LOG_MAX_BLOCKS 8
- // Port definitions
- typedef enum {
- CRTP_PORT_CONSOLE = 0x00,
- CRTP_PORT_PARAM = 0x02,
- CRTP_PORT_COMMANDER = 0x03,
- CRTP_PORT_LOG = 0x05,
- CRTP_PORT_LINK = 0x0F,
- } CRTPPort;
- // Common command numbers
- #define CMD_GET_ITEM 0
- #define CMD_GET_INFO 1
- // Singleton instance of the radio
- NRF24 nrf24;
- // NRF24 nrf24(8, 7); // use this to be electrically compatible with Mirf
- // NRF24 nrf24(8, 10);// For Leonardo, need explicit SS pin
- // The address to use for this Crazyflie
- uint8_t address[] = { 0xe7, 0xe7, 0xe7, 0xe7, 0xe7 };
- void setup()
- {
- Serial.begin(115200);
- while (!Serial)
- ; // Wait for serial port, only required for Leonardo
- if (!nrf24.init())
- Serial.println("NRF24 init failed");
- // Be Crazyflie radiolink compatible
- // We use the NRF24 library for convenience, but
- // we use a different configuration to the default NRF24
- if (!nrf24.setChannel(13))
- Serial.println("setChannel failed");
- // Set data rate to 250k and low power
- if (!nrf24.setRF(NRF24::NRF24DataRate250kbps, NRF24::NRF24TransmitPower0dBm))
- Serial.println("setRF failed");
- if (!nrf24.setPipeAddress(0, address, sizeof(address)))
- Serial.println("setPipeAddress failed");
- // Be compatible with Crazyflie: No interrupts, 2 bytes CRC
- nrf24.setConfiguration(NRF24_MASK_RX_DR | NRF24_MASK_TX_DS | NRF24_MASK_MAX_RT | NRF24_EN_CRC | NRF24_CRCO);
- nrf24.spiWriteRegister(NRF24_REG_1D_FEATURE, NRF24_EN_DPL | NRF24_EN_ACK_PAY); // Dynamic size payload + ack
- nrf24.spiWriteRegister(NRF24_REG_1C_DYNPD, NRF24_DPL_P0); // Dynamic payload on pipe 0
- if (!nrf24.setRetry(6, 3)) // 1500us and 3 retries
- Serial.println("setRetry failed");
- Serial.println("initialised");
- }
- // Debugging data dumper
- void dump(char* prompt, uint8_t* data, uint8_t len)
- {
- Serial.print(prompt);
- Serial.print(": ");
- for (int i = 0; i < len; i++)
- {
- Serial.print(data[i], HEX);
- Serial.print(" ");
- }
- Serial.println("");
- }
- // Send an ACK with a payload on pipe 0
- void sendAckPayload(uint8_t* data, uint8_t len)
- {
- nrf24.spiBurstWrite(NRF24_COMMAND_W_ACK_PAYLOAD(0), data, len);
- nrf24.waitPacketSent();
- }
- // ACK with no payload on pipe 0
- void sendAck()
- {
- sendAckPayload(0, 0);
- }
- void loop()
- {
- uint8_t buf[100];
- uint8_t buflen = sizeof(buf);
- static uint32_t last_second = 0;
-
- // enable receiver again, after transmit and wait for a message
- nrf24.waitAvailable();
- if (nrf24.recv(buf, &buflen))
- {
- // Decode incoming messages from client based on port number in the header byte
- // dump("msg", buf, buflen);
- if (CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_LINK) // Link Echo
- {
- sendAck(); // Just ack, no payload
- }
- else if (CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_COMMANDER) // Commander
- {
- // Commander message to set control positions
- CommanderCrtpValues *p = (CommanderCrtpValues*)(buf+1);
- Serial.println(p->roll); // -30.0 to 30.0
- Serial.println(p->pitch); // -28.0 to 32.0
- Serial.println(p->yaw); // -200.0 to 200.0
- Serial.println(p->thrust); // 0 to 45755
- sendAck(); // Just ack, no payload
- // dump("commander", buf, buflen);
- }
- else if (CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_PARAM) // Parameter
- {
- if (buf[1] == CMD_GET_INFO) // Param GET_INFO
- {
- // pc client only fetches item data if the CRC changes
- // If you change the contents of your TOC, you must change the CRC
- // Crazyflie PC client doesnt relaly believe it if you say there are no TOC entries
- uint8_t reply[] = { CRTP_HEADER(CRTP_PORT_PARAM, PARAM_TOC_CH), CMD_GET_INFO, 1, 0, 0, 2, 0}; // 1 params in toc
- sendAckPayload(reply, sizeof(reply));
- }
- else if (buf[1] == CMD_GET_ITEM) // Param GET_ITEM
- {
- // Set up a fax param as item 0
- 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
- sendAckPayload(reply, sizeof(reply));
- }
- else
- {
- Serial.print("unknown param type ");
- Serial.println(buf[1]);
- }
- // dump("param", buf, buflen);
- }
- else if (buf[0] == CRTP_HEADER_PORT(buf[0]) == CRTP_PORT_PARAM) // Log
- {
- // http://wiki.bitcraze.se/projects:crazyflie:crtp:log
- if (buf[1] == CMD_GET_INFO) // Log GET_INFO
- {
- // pc client only fetches item data if the CRC changes
- // If you change the contents of your TOC, you must change the CRC
- // Crazyflie PC client doesnt relaly believe it if you say there are no TOC entries
- 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
- sendAckPayload(reply, sizeof(reply));
- }
- else if (buf[1] == CMD_GET_ITEM) // Log GET_ITEM
- {
- // Set up a fake battery voltage as item 0
- 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
- sendAckPayload(reply, sizeof(reply));
- }
- // dump("log", buf, buflen);
- }
- else
- {
- // Sometimes get bogus type 0x93
- // dump("unknown", buf, buflen);
- }
- }
-
- // Do once per second tasks
- uint32_t this_second = millis() / 1000;
- if (this_second != last_second)
- {
- // This is how you would send value data for a log block
- // with current real-time data
- // if a log block has ben set up by the client
- // uint8_t msg[] = {CRTP_HEADER(CRTP_PORT_LOG, LOG_LOG_CH), 0, 0, 0, 0, 11, 11, 11, 11};
- // sendAckPayload(msg, sizeof(msg));
- last_second = this_second;
- }
- }
|