As I wasn't able to flash the newer Arducopter firmware on my Walkera X350 Pro (Devo-M). I had to come up with another way to add GSM/GPRS telemetry to my drone. I did this using an Arduino Mega 2560 to run the configuration script on a Linkto SIM900D module. I used Andreas' AP_Modem library as a guide for the AT Commands, but I had to change some of them to have it work better in my setup.
To do this, first you'll have to add wiring to your X350 Pro's serial port, you can follow these instructions by unmannedtech "Adding Telemetry to the Walkera QR X350 Pro" - Here it is.
What you'll need:
- Arduino Mega 2560 (Unfortunately the UNO didn't work as the SoftwareSerial is too slow)
- AT-command compatible modem (I used the Linkto SIM900D)
- 1 Red LED
- 1 Green LED
- 2 220 ohm Resistors
You'll need to interface the modem with your Arduino. TX from the modem's TTL port to RX1 on the Arduino, RX on the modem's TTL port to TX1 on the Arduino, Shared GND connecting the Modem with the Arduino and the power source and finally the VIN to your power source. The modem I'm using works with 5 to 20 v so I supply it from the X350 Pro's 11.1v battery. To handle loss of connection, you'll need to connect Pin 2 of your Arduino to the PWRKEY / PWRKEY_OUT pin on your modem and then connect Pin 3 of your Arduino to the Reset Pin of the Arduino (Make sure that this wire is disconnected during upload as it won't work if it is connected.
Next interface the Arduino with the Devo-M by connecting the 5v VIN from the DEVO-M to the 5V on the Arduino, the GND to the GND and the TX from the Devo-M to the RX2 on the Arduino and the RX from the Devo-M to TX2 on the Arduino.
Red LED (ERR): To build the circuit, attach a 220-ohm resistor to pin 11. Then attach the long leg of an LED (the positive leg, called the anode) to the resistor. Attach the short leg (the negative leg, called the cathode) to ground.
Green LED (LED): To build the circuit, attach a 220-ohm resistor to pin 12. Then attach the long leg of an LED (the positive leg, called the anode) to the resistor. Attach the short leg (the negative leg, called the cathode) to ground.
(Took that straight from the Arduino site: HERE except for the pins obviously)
Now that it's all wired up, I'll move on to the setup:
You'll need to set the Modems Baud Rate to 57600 and set the Serial Port of your DEVO-M to 57600 as well. Finally you need to program your Arduino with this code:
/*
* Serial_Comm_Mega.ino
*
*/
///@file Serial_Comm.ino
///@brief AT-command compatible cellular/GPRS/IP modem initialization & communication for SIM900D -> Arduino -> ArduCopter
///@author Robert Haddad
///@date 14-09-2014
#define LED 12 // All Good LED Turns green when data is being sent over UDP Connection
#define ERR 11 // Error LED Turns Red when error is encountered, turns off if all is okay
#define powerKey 2 // Set PWRKEY pin
#define resetPin 3 // Set reset pin
boolean isReady = false; // GSM modem is Ready to receive AT Commands flag
int count = 0; // Counter for instances of an error (For monitor/debug only);
String checker = ""; // String to hold serial output
// Setup procedure
void setup()
{
pinMode(LED, OUTPUT); // All Good LED
pinMode(ERR, OUTPUT); // Warning LED
digitalWrite(LED,LOW); // Set All Good LED to Off
digitalWrite(ERR,LOW); // Set Warning LED to Off
digitalWrite(resetPin, HIGH); // Set Reset Pin
// Set Data Rate for Serial Ports
Serial.begin(57600); // Start USB Port Serial @ 57,600 Baud Rate (For Monitor/Debug only)
Serial1.begin(57600); // Start GSM Module Serial Communication @ 57,600 Baud Rate
pinMode(resetPin, OUTPUT);
// Wait 3 Seconds for power on (Add Auto on feature through GSM module power button pin
startUPWait();
// Initializing GSM Module
Serial.println("Initializing...");
Serial1.print("AT\r");
while(!isReady){
if(Serial.available()){
String a=Serial.readString();
Serial1.print(a);
}
if(Serial1.available()){
String b=Serial1.readString();
if(b.indexOf("+CREG: 1") > 0){// || b.indexOf("OK") > 0){
Serial.println("SIM900 Ready & Loading");
isReady = true;
while(!sendATCommand("AT V1 E1 X1 S0=0","OK",100)); // Set error response and do not pickup on ring
while(!sendATCommand("AT+CREG=2","OK",100)); // Set various notice messages and parameters
Serial.println("Registered: Starting Configuration");
while(!sendATCommand("AT+CMEE=2","OK",100));
while(!sendATCommand("AT+CR=1","OK",100));
while(!sendATCommand("AT+CRC=1","OK",100));
while(!sendATCommand("AT+CSNS=4","OK",100));
while(!sendATCommand("AT+CSMINS=1","OK",100));
while(!sendATCommand("AT+CSCLK=0","OK",100));
while(!sendATCommand("AT+CIURC=1","OK",100));
while(!sendATCommand("AT+CGEREP=2","OK",100));
while(!sendATCommand("AT+CIPMUX=0","OK",100)); // Single channel communication (ie only one socket can be opened)
while(!sendATCommand("AT+CIPMODE=1","OK",100)); // Transparent bridge mode
while(!sendATCommand("AT+CIPCCFG=8,10,400,0","OK",100)); // GPRS params
Serial1.print("AT+CMUX=0,0,4,32768,10,3,30,10,2\r"); // GPRS/IP params
//0 4 127/32768 3 2
delay(2000);
while(!sendATCommand("AT+CGATT?","OK",1000)); // Make sure GPRS is Attached
while(!sendATCommand("AT+CSTT= \"internet\",\"\",\"\"","OK",1000)); // AT+CSTT="APN","username","password" - login to service provider/carrier
Serial.println("APN Set");
while(!sendATCommand("AT+CIICR","OK",1000)); // Connect!
while(!sendATCommand("AT+CIFSR",".",100)); // Get IP address (for info only);
//while(!sendATCommand("AT+CIPCTL=1","+CREG: 1",100)); // Set port to listen. Not needed
while(!sendATCommand("AT+CLPORT=\"UDP\",8888","OK",100)); // Prep UDP Port 8888
Serial.println("Connecting to UDP Server");
while(!sendATCommand("AT+CIPSTART=\"UDP\",\"drone.dyndns.org\",8888","OK",1000)); // AT+CIPSTART="protocol","ip address or domain","port #"
//while(!sendATCommand("AT+CIPSERVER=1,8888","OK",1000)); // TCP/UDP Server
digitalWrite(LED,HIGH); // Turn on All Good LED
digitalWrite(ERR,LOW); // Turn off Warning LED
delay(1000);
digitalWrite(LED,LOW);
Serial.end(); // Stop USB Serial communication
Serial2.begin(57600); // Start Autopilot Communication @ 57,600 Baud Rate
} else {
digitalWrite(ERR,HIGH); // Turn on Warning LED
digitalWrite(LED,LOW); // Turn off All Good LED
Serial.print(b);
}
}
}
}
// AT Command Sender
boolean sendATCommand(String input, String output, int wait){ // AT Command, Expected Result, Delay before issue command
boolean resp = false;
Serial.print(input + "\r");
Serial1.print(input + "\r");
delay(wait);
while(!resp){
if(Serial1.available()){
String b=Serial1.readString();
Serial.println(b);
Serial1.read();
Serial.read();
if(b.indexOf(output) > 0){ // True if expected result is returned
resp = true;
count = 0;
digitalWrite(ERR,LOW); // Warning LED OFF
return resp;
} else if(b.indexOf("DEACT") > 0){
if(powerUpOrDown()){
digitalWrite(resetPin,LOW);
}
} else {
digitalWrite(ERR,HIGH); // Warning LED ON
Serial.print(b);
count++;
return resp;
}
}
}
}
//Start Up Wait Period with LEDs
void startUPWait(){
digitalWrite(LED,HIGH);
digitalWrite(ERR,LOW);
delay(500);
digitalWrite(LED,LOW);
digitalWrite(ERR,HIGH);
delay(500);
digitalWrite(LED,HIGH);
digitalWrite(ERR,LOW);
delay(500);
digitalWrite(LED,LOW);
digitalWrite(ERR,HIGH);
delay(500);
digitalWrite(LED,HIGH);
digitalWrite(ERR,HIGH);
delay(1000);
digitalWrite(LED,LOW);
digitalWrite(ERR,LOW);
}
// Main Loop
void loop(){
// Relay All GSM Module communication to Autopilot and USB (USB for monitor/debug only)
if(Serial1.available()){
char b=Serial1.read();
Serial2.write(b);
// Check For Disconnection
checker += b;
if(checker.indexOf("\n") > 0 || checker.indexOf("\r") > 0){
if(checker.indexOf("DEACT") > 0){
if(powerUpOrDown()){
digitalWrite(3,LOW);
}
}
checker = "";
}
digitalWrite(ERR,HIGH);
digitalWrite(ERR,LOW);
Serial.print(b);
}
// Relay all Autopilot communication to GSM module and USB (USB for monitor/debug only)
if(Serial2.available()){
char c=Serial2.read();
Serial1.write(c);
digitalWrite(LED,HIGH);
digitalWrite(LED,LOW);
Serial.print(c);
}
}
boolean powerUpOrDown()
{
boolean powered = false;
pinMode(powerKey, OUTPUT);
digitalWrite(powerKey,LOW);
delay(1000);
digitalWrite(powerKey,HIGH);
delay(2000);
digitalWrite(powerKey,LOW);
delay(3000);
powered = true;
return powered;
}
On your GCS, choose UDP then 57600 Baud and Click connect once the green LED on your setup is blinking rapidly (Green LED blinks when the Drone is sending Data and the Red LED blinks when the GCS is sending Data) click the connect button and it should connect and then start to receive parameters from the drone. Once its connected, you should have a pretty good connection, mine averages between 80 - 99% signal strength with a 1 to 1.5 second delay.
I used this page which helped out a lot and you should too Testing the dronecell ...
Happy Flying :)
Replies
Hey, anybody flying with this setup? Do u have practical experience and uses this nowadays?
Thanks, wery interesting setup!
Hey everyone,
I've updated the instructions so that the telemetry link will be reestablished should the modem get disconnected from the GSM/GPRS network. I've tested the code and it works.
Happy flying
Does anyone know how to register the IP at DynDNS(or similar service) ? (or have the code to do so)?
It should be something like this:
String dyndns = "members.dyndns.org";
String hostname = "YOUR DYNAMIC HOST NAME"; // IE drone.dyndns.org
String userpwdb64 = "BASE64 Username & Password"; // username:password
String currentIP = "YOUR CURRENT IP ADDRESS";
Serial.print("AT+CIPSEND\r");
Serial.print("GET /nic/update?hostname=" + hostname + "&myip=" + currentIP + "&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0\r");
Serial.print("Host: " + dyndns + "\r");
Serial.print("Authorization: Basic " + userpwdb64 + "\r");
Serial.print("User-Agent: arduinodydns - 1.1\r");
Serial.print("\x1A\r");
@Robert Haddad , It is an ICOMSAT (http://imall.iteadstudio.com/im120417009.html) and an ITEADUINO MEGA 2560 (http://imall.iteadstudio.com/im120410003.html). The rest is an APM2.5 with a Hobbyking SK450.
The next step is to bring the thing up in the sky:-)
Hey @Hermann Roitinger,
Have you flown it with the modem yet?
Best of luck :)
nice job, the only thing that is missing, is a way to handle loss of GSM or EDGE/GPRS, detect it and re-establish UDP server.
do you have a lightweight method of detecting that situation ?
Hey Andre,
I add some new code to the example above that should take care of the disconnect issue and reconnect, I haven't had a chance to test it though. It basically checks the responses from the GSM module for "DEACT" which means it lost connection and then it will reinitialize the connection which should take about 3 seconds. You'll find the new bits of code with the word "NEW" in the comments
I hope that helps,
Robert
Hey Andre K,
I don't, but you could keep the module out of transparent mode and use "AT+CIPSEND" then check for an IP address "AT+CIFSR", but I think that would make you loose data. I'm open to suggestions as this is an important feature :)
Thanks,
Robert