3689623748?profile=original3689623490?profile=original3689623649?profile=original


 

As I wasn't able to flash the newer Arducopter firmware on my Walkera X350 Pro (Devo-M) and wasn't able to find the correct Firmware to get my APM 2.6 to work with my SIM900D module. I had to come up with another way to add GSM/GPRS telemetry to my drone. I created a GPRS module using an Arduino Nano 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. This is already available on the APM 2.6 via the telemetry port.

What you'll need:

- Arduino Nano

AT-command compatible modem (I used the Linkto SIM900D)

- 1 Red LED

- 1 Green LED

- 2 220 ohm Resistors

3689623874?profile=original

3689623801?profile=original

You'll need to interface the modem with your Arduino. TX from the modem's TTL port to D4 on the Arduino, RX on the modem's TTL port to D5 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 needs a clean 5V 2.5A source. To handle loss of connection, you'll need to connect Pin 3 of your Arduino to the PWRKEY / PWRKEY_OUT pin on your modem and then connect Pin 2 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 APM 2.6 or Devo-M by connecting the GND to the GND and the TX from the APM/Devo-M to the RX0 on the Arduino and the RX from the Devo-M to TX1 on the Arduino. 

*Note: You can use either the same 5V supply for the modem to power the Arduino Nano or the 5V line from the Telemetry port as long as you are sharing the ground.

3689623815?profile=original


Next add the LEDs:

Red LED (ERR): To build the circuit, attach a 220-ohm resistor to pin D11. 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 D12. 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)

3689623828?profile=original

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 Telemetry Port of your APM/DEVO-M to 57600 as well. Finally you need to program your Arduino with this code:

/*
* Serial_Comm_Nano.ino
*
*/
///@file Serial_Comm_Nano.ino
///@brief AT-command compatible cellular/GPRS/IP modem initialization & communication for SIM900D -> Arduino -> ArduCopter
///@author Robert Haddad
///@date 25-10-2014
#include <SoftwareSerial.h> // Include SoftwareSerial Library
//Serial Communication Ports
#define rxPin 4 // TX from GSM Modem to RX on Arduino
#define txPin 5 // RX from GSM Modem to TX on Arduino
#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 3 // Set PWRKEY pin
#define resetPin 2 // 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 = "";
// set up a new serial port for GSM Module
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin); // Initialize mySerial SoftwareSerial
// Setup procedure
void setup()
{
    pinMode(rxPin, INPUT); // Set pin mode to input for Software serial RX Pin
    pinMode(txPin, OUTPUT); // Set pin mode to output for Software serial TX Pin
    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 to high
 
    // Set Data Rate for Serial Ports
    mySerial.begin(57600); // Start GSM Module Serial Communication @ 57,600 Baud Rate
    pinMode(resetPin, OUTPUT); // Set reset pin to output
    // Wait 3 Seconds for power on (Add Auto on feature through GSM module power button pin
    startUPWait();
 
    // Initializing GSM Module
    mySerial.print("AT\r");
    while(!isR eady){
        if(mySerial.available()){
            String b=mySerial.readString();
            if(b.indexOf("+CREG: 1") > 0 || b.indexOf("+CREG: 2") > 0){
                isReady = true;
                //while(!sendATCommand("AT+IPR=57600","OK",100)); // Uncomment to set Modem Baudrate
                //while(!sendATCommand("AT&W","OK",100)); // Uncomment to write settings to non-volatile memory
                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
                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
                mySerial.print("AT+CMUX=0,0,4,32768,10,3,30,10,2\r"); // GPRS/IP params
                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
                while(!sendATCommand("AT+CIICR","OK",1000)); // Connect!
                while(!sendATCommand("AT+CIFSR",".",100)); // Get IP address (for info only);
                while(!sendATCommand("AT+CLPORT=\"UDP\",8888","OK",100)); // Prep UDP Port 8888
                while(!sendATCommand("AT+CIPSTART=\"UDP\",\"drone.dyndns.com\",8888","OK",1000));  // AT+CIPSTART="protocol","ip address or domain","port #"
                Serial.begin(57600); // Start Serial port for communication with Ardupilot
                digitalWrite(LED,HIGH); // Turn on All Good LED
                digitalWrite(ERR,LOW); // Turn off Warning LED
                delay(1000);
                digitalWrite(LED,LOW);
            } else {
                digitalWrite(ERR,HIGH); // Turn on Warning LED
                digitalWrite(LED,LOW); // Turn off All Good LED
            }
        }
    }
}
// AT Command Sender
boolean sendATCommand(String input, String output, int wait){ // AT Command, Expected Result, Delay before issue command
    boolean resp = false;
    mySerial.print(input + "\r"); // Send input command to modem
    delay(wait); // Delay function time "wait" variable
    while(!resp){
        if(mySerial.available()){ // Check if response is available
            String b=mySerial.readString(); // Store response string in "b"
            mySerial.read(); // Clear buffer again
            if(b.indexOf(output) > 0){ // True if expected result is returned
                resp = true;
                count = 0;
                digitalWrite(LED,HIGH); // Green LED ON
                digitalWrite(ERR,LOW); // Warning LED OFF
                digitalWrite(LED,LOW); // Green LED OFF
                return resp;
            } else if(b.indexOf("DEACT") > 0 || b.indexOf("NORMAL POWER DOWN") > 0){ // Check if lost connection or modem power down
                if(powerUpOrDown()){ // Reset comm hardware
                    digitalWrite(resetPin,LOW); // Restart Modem
                }
            } else {
                digitalWrite(ERR,HIGH); // Warning LED ON
                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(){
    digitalWrite(LED,HIGH); // Keep Green LED ON while connected
    // Relay All GSM Module communication to Autopilot
    if(mySerial.available()){
        char b=mySerial.read();
        Serial.write(b);
        // Check For Disconnection
        checker += b;
        if(checker.indexOf("\n") > 0 || checker.indexOf("\r") > 0){ // Check for new line
            if(checker.indexOf("DEACT") > 0 || checker.indexOf("NORMA") > 0){ // Check for lost connection or Modem power down
                digitalWrite(LED,LOW); // Green LED OFF
                digitalWrite(ERR,HIGH); // Warning LED ON
                if(powerUpOrDown()){ // Reset Comm Hardware
                    digitalWrite(resetPin,LOW); // Reset Modem
                }
            }
            checker = "";
        }
        digitalWrite(ERR,HIGH); // Flash Warning LED on data send/receive
        digitalWrite(ERR,LOW);
    }
 
    // Relay all Autopilot communication to GSM module and USB (USB for monitor/debug only)
    if(Serial.available()){
        char c=Serial.read();
        mySerial.write(c);
        digitalWrite(ERR,HIGH); // Flash Warning LED on data send/receive
        digitalWrite(ERR,LOW);
    }
}
boolean powerUpOrDown() // Cycle power on Modem
{
    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 on/solid (Green LED blinks when the module is connecting and the Red LED blinks when the data is being sent and received) 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 :)

    

E-mail me when people leave their comments –

You need to be a member of diydrones to add comments!

Join diydrones

Comments

  • Developer

    There no way to embed the link directly as a viewable element as it requires javascript. If the ace editor (that does the syntax highlighting) was hosted on DIYDRONES.COM, you maybe able to make it show the code as then you would avoid 'cross-site scripting' which is disabled (for good reason)

  • Sorry, I forgot to add the link --> http://www.seeedstudio.com/wiki/GPRS_Shield_V2.0
    Anyway, I got it working after I added these line after startUPWait();

    digitalWrite(powerKey,HIGH);
    delay(1000);
    digitalWrite(powerKey,LOW);
  • What modem are you using?
  • I finally got it working with my Pixhawk. It was a stupid wiring mistake.
    The only issue now is that the software power on of the modem does not seem to be working.
  • I'm still trying to get my setup to work with Pixhawk. Do you have any ideas why it wouldn't work with a Pixhawk when it's working just fine with APM 2.6?
  • @Bill Bonney, thank you, how do I add it to the post?
  • Developer

    I've reformatted the code so you can read it easier, see here https://gist.github.com/billbonney/0bbb90699f6d36f853d1

    /*
    * Serial_Comm_Nano.ino
    *
    */
    ///@file Serial_Comm_Nano.ino
    ///@brief AT-command compatible cellular/GPRS/IP modem initialization & communication for SIM900D -> Arduino -> ArduCopter
    ///@author Robert Haddad
    ///@date 25-10-2014
    #include <SoftwareSerial.h> // Include SoftwareSerial Library
    //Serial Communication Ports
    #define rxPin 4 // TX from GSM Modem to RX on Arduino
    #define txPin 5 // RX from GSM Modem to TX on Arduino
    #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 3 // Set PWRKEY pin
    #define resetPin 2 // 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 = "";
    // set up a new serial port for GSM Module
    SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin); // Initialize mySerial SoftwareSerial
    // Setup procedure
    void setup()
    {
    pinMode(rxPin, INPUT); // Set pin mode to input for Software serial RX Pin
    pinMode(txPin, OUTPUT); // Set pin mode to output for Software serial TX Pin
    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 to high
    // Set Data Rate for Serial Ports
    mySerial.begin(57600); // Start GSM Module Serial Communication @ 57,600 Baud Rate
    pinMode(resetPin, OUTPUT); // Set reset pin to output
    // Wait 3 Seconds for power on (Add Auto on feature through GSM module power button pin
    startUPWait();
    // Initializing GSM Module
    mySerial.print("AT\r");
    while(!isReady){
    if(mySerial.available()){
    String b=mySerial.readString();
    if(b.indexOf("+CREG: 1") > 0 || b.indexOf("+CREG: 2") > 0){
    isReady = true;
    //while(!sendATCommand("AT+IPR=57600","OK",100)); // Uncomment to set Modem Baudrate
    //while(!sendATCommand("AT&W","OK",100)); // Uncomment to write settings to non-volatile memory
    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
    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
    mySerial.print("AT+CMUX=0,0,4,32768,10,3,30,10,2\r"); // GPRS/IP params
    delay(2000);
    while(!sendATCommand("AT+CGATT?","OK",1000)); // Make sure GPRS is Attached
    while(!sendATCommand("AT+CSTT= \"zain\",\"\",\"\"","OK",1000)); // AT+CSTT="APN","username","password" - login to service provider/carrier
    while(!sendATCommand("AT+CIICR","OK",1000)); // Connect!
    while(!sendATCommand("AT+CIFSR",".",100)); // Get IP address (for info only);
    while(!sendATCommand("AT+CLPORT=\"UDP\",8888","OK",100)); // Prep UDP Port 8888
    while(!sendATCommand("AT+CIPSTART=\"UDP\",\"drone.dyndns.biz\",8888","OK",1000)); // AT+CIPSTART="protocol","ip address or domain","port #"
    Serial.begin(57600); // Start Serial port for communication with Ardupilot
    digitalWrite(LED,HIGH); // Turn on All Good LED
    digitalWrite(ERR,LOW); // Turn off Warning LED
    delay(1000);
    digitalWrite(LED,LOW);
    } else {
    digitalWrite(ERR,HIGH); // Turn on Warning LED
    digitalWrite(LED,LOW); // Turn off All Good LED
    }
    }
    }
    }
    // AT Command Sender
    boolean sendATCommand(String input, String output, int wait){ // AT Command, Expected Result, Delay before issue command
    boolean resp = false;
    mySerial.print(input + "\r"); // Send input command to modem
    delay(wait); // Delay function time "wait" variable
    while(!resp){
    if(mySerial.available()){ // Check if response is available
    String b=mySerial.readString(); // Store response string in "b"
    mySerial.read(); // Clear buffer again
    if(b.indexOf(output) > 0){ // True if expected result is returned
    resp = true;
    count = 0;
    digitalWrite(LED,HIGH); // Green LED ON
    digitalWrite(ERR,LOW); // Warning LED OFF
    digitalWrite(LED,LOW); // Green LED OFF
    return resp;
    } else if(b.indexOf("DEACT") > 0 || b.indexOf("NORMAL POWER DOWN") > 0){ // Check if lost connection or modem power down
    if(powerUpOrDown()){ // Reset comm hardware
    digitalWrite(resetPin,LOW); // Restart Modem
    }
    } else {
    digitalWrite(ERR,HIGH); // Warning LED ON
    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(){
    digitalWrite(LED,HIGH); // Keep Green LED ON while connected
    // Relay All GSM Module communication to Autopilot
    if(mySerial.available()){
    char b=mySerial.read();
    Serial.write(b);
    // Check For Disconnection
    checker += b;
    if(checker.indexOf("\n") > 0 || checker.indexOf("\r") > 0){ // Check for new line
    if(checker.indexOf("DEACT") > 0 || checker.indexOf("NORMA") > 0){ // Check for lost connection or Modem power down
    digitalWrite(LED,LOW); // Green LED OFF
    digitalWrite(ERR,HIGH); // Warning LED ON
    if(powerUpOrDown()){ // Reset Comm Hardware
    digitalWrite(resetPin,LOW); // Reset Modem
    }
    }
    checker = "";
    }
    digitalWrite(ERR,HIGH); // Flash Warning LED on data send/receive
    digitalWrite(ERR,LOW);
    //Serial.print(b);
    }
    // Relay all Autopilot communication to GSM module and USB (USB for monitor/debug only)
    if(Serial.available()){
    char c=Serial.read();
    mySerial.write(c);
    digitalWrite(ERR,HIGH); // Flash Warning LED on data send/receive
    digitalWrite(ERR,LOW);
    }
    }
    boolean powerUpOrDown() // Cycle power on Modem
    {
    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;
    }
  • Thank you for posting the code.

    For some reason it's not working with my Pixhawk but works fine with an APM 2.6.

    I think there might be a signal level issue because Pixhawk is a 3.3v device. Can anyone confirm that?

  • Plus signal strength is already calculated and shown in mission planner with this setup
  • Yi, you really don't want TCP for this. The nature of telemetry is such that "stale" data is essentially worthless anyway, so there's no point in waiting around trying to retransmit it on a less that stable link. The only thing you care about assured delivery for is command and control messages, and it is much better to implement this within the protocol itself than to rely on TCP to get the message there. I'm not positive, but it is my assumption that MAVlink will retry command statements until they are acknowledged.

This reply was deleted.