My Cart

How to Control a Servo with Text Messages Using Tracking Kit (GPRS + GPS)

Difficulty Level: Intermediate -

1. Introduction

This tutorial allows the user to move a servo sending text messages with the mobile phone. Depending on the number received by the module, the servo is placed in one position or another corresponding to the indicated degrees.

Ingredients:

    - 1 x Tracking Kit (GPRS + GPS):
    • 1x Platform
    • 1x GPRS+GPS Quadband Module (SIM908)
    • 1x GPRS antenna
    • 1x Servo
    • 1x Breadboard
    • 1x External power supply
    • 1x Programming cable
    • Jumper Wires

Preparation Time: 30 minutes

Buy now
NOTE: Depending on the platform chosen to develop the project, the ingredients and the schematics shown in this tutorial can vary.

This project can be developed with Arduino or Intel Galileo. It is also compatible with Raspberry Pi using the Raspberry Pi to Arduino shields connection bridge.

For further information about the GPRS+GPS (SIM908) Shield, consult the main tutorial.

Step 1: Connection

Connect the GPRS antenna to the shield and then, connect the shield to the Arduino or to Raspberry Pi connection bridge. Connect servo in the breadboard as you can see in the next diagram.

Connect two wires, red and black, to the two long rows on the side of the breadboard to provide access to 3.3 volt supply and ground. Servo has 3 wires with different colors. Connect Black/Brown wire to GND, Red wire to 3.3 volt and the remaining wire, Yellow/Orange, to pin 9 of Arduino. Pin 9 has PWM control so you can move your servo from 0 to 180 degrees.

WARNING: In Raspberry Pi, GPIO voltage levels are 3.3 V and are not 5 V tolerant. There is no over-voltage protection on the board. Digital inputs use a 3V3 logic level and are not tolerant of 5V levels, such as you might find on a 5V powered Arduino. Extreme caution when working with GPIO, you may damage your Raspberry Pi, your equipment and potentially yourself and others. Doing so is at your own risk!

Step 2: The Code

Arduino:

Code:
/*  
 *  GPRS+GPS Quadband Module (SIM908)
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Victor Boria
 */

#include <Servo.h> //Include the servo-motor library

//Enter here you data
const char pin_number[] = "****";     // Write the pin number of the SIM card

Servo myServo;  // Create a servo object
int angle;   // Variable to hold the angle for the servo motor


int8_t answer;
int onModulePin = 2;
char aux_string[50];

unsigned long previous;
int count;

void setup() {
  myServo.attach(9); // Attaches the servo on pin 9 to the servo object
  myServo.write(90); // Set the servo in the center position
  pinMode(onModulePin, OUTPUT);
  Serial.begin(115200);

  Serial.println("Starting...");
  power_on(); // Powering the module

  delay(3000);

  //sets the PIN code
  sprintf(aux_string, "AT+CPIN=%s", pin_number);
  sendATcommand(aux_string, "OK", 2000);
  
  delay(3000);
  
  Serial.println("Connecting to the network...");

  while ( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) ||
           sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );

  Serial.print("Setting SMS mode...");
  sendATcommand("AT+CMGF=1", "OK", 1000);    // sets the SMS mode to text
  sendATcommand("AT+CPMS=\"SM\",\"SM\",\"SM\"", "OK", 1000);    // selects the memory

  sendATcommand("AT+CNMI=2,1,0,0", "OK", 1000);    // Sets mode to wait for an incoming SMS
  
  Serial.println("Waiting incoming SMS");
}


void loop() {
  answer = sendATcommand("", "+CMTI: ", 1000);
  //Detect incomming SMS
  if (answer == 1)
  {
    count = 0;
    previous = millis();
    do
    {
      while (((millis() - previous) < 1000) && (Serial.available() == 0))
      {
        // Condition to avoid an overflow 
        if ( millis() < previous) previous = millis();
      }
      // Condition to avoid an overflow
      if ( millis() < previous) previous = millis();
      //Search a "," in the command received
    } while (((millis() - previous) < 1000) && (Serial.read() != ','));

    previous = millis();
    do {
      
      while (((millis() - previous) < 1000) && (Serial.available() == 0))
      {
        // Condition to avoid an overflow 
        if ( millis() < previous) previous = millis();
      }
      
      aux_string[count] = Serial.read();
      count++;

      // Condition to avoid an overflow 
      if ( millis() < previous) previous = millis();
    } while ((aux_string[count - 1] != '\r') && ((millis() - previous) < 1000) && (count < 30));

    aux_string[count - 1] = '\0';

    count = atoi(aux_string);
    Serial.print(F("SMS index: "));
    Serial.println(count, DEC);
    Serial.println(aux_string);

    if (count != 0)
    {
      //Check the comunication with the module
      sendATcommand("AT", "OK", 1000);
      
      //Read the received SMS
      snprintf(aux_string, sizeof(aux_string), "AT+CMGR=%d", count);
      answer = sendATcommand(aux_string, "+CMGR:", 1000);
      if (answer == 1)
      {
        previous = millis();
        do
        {
          while (((millis() - previous) < 1000) && (Serial.available() == 0))
          {
            // Condition to avoid an overflow 
            if ( millis() < previous) previous = millis();
          }
          // Condition to avoid an overflow 
          if ( millis() < previous) previous = millis();
        } while (((millis() - previous) < 1000) && (Serial.read() != '\n'));

        count = 0;
        previous = millis();
        do {

          while (((millis() - previous) < 1000) && (Serial.available() == 0))
          {
            // Condition to avoid an overflow 
            if ( millis() < previous) previous = millis();
          }

          aux_string[count] = Serial.read();
          count++;

          // Condition to avoid an overflow 
          if ( millis() < previous) previous = millis();
        } while ((strstr(aux_string, "OK") == NULL) && ((millis() - previous) < 1000) && (count < 30));

        aux_string[count - 1] = '\0';
        Serial.print("Received SMS: ");
        Serial.println(aux_string);
        
        //Conversion de string a int
        angle = atoi(aux_string);
        //The servo turn the angle read in the SMS
        myServo.write(angle);
      }
    }


  }
}
void power_on() {

  uint8_t answer = 0;

  // checks if the module is started
  answer = sendATcommand("AT", "OK", 2000);
  if (answer == 0)
  {
    // power on pulse
    digitalWrite(onModulePin, HIGH);
    delay(3000);
    digitalWrite(onModulePin, LOW);

    // waits for an answer from the module
    while (answer == 0) {   // Send AT every two seconds and wait for the answer
      answer = sendATcommand("AT", "OK", 2000);
    }
  }

}

int8_t sendATcommand(char * ATcommand, char * expected_answer, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialice the string

  delay(100);

  while ( Serial.available() > 0) Serial.read();   // Clean the input buffer

  if (ATcommand[0] != '\0')
  {
    Serial.println(ATcommand);    // Send the AT command
  }


  x = 0;
  previous = millis();

  // this loop waits for the answer
  do {
    // if there are data in the UART input buffer, reads it and checks for the asnwer
    if (Serial.available() != 0) {
      response[x] = Serial.read();
      x++;
      // check if the desired answer is in the response of the module
      if (strstr(response, expected_answer) != NULL)
      {
        answer = 1;
      }
    }
    // Waits for the asnwer with time out
  } while ((answer == 0) && ((millis() - previous) < timeout));

  return answer;
}
        

Raspberry Pi:

Code:
/*  
 *  GPRS+GPS Quadband Module (SIM908)
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Marcos MartĂ­nez
 */

//Include arduPi library
#include "arduPi.h"

int8_t sendATcommand(const char* ATcommand, const char* expected_answer, unsigned int timeout);
void power_on();
void servoWrite(int servo, int angle);

int servo = 9;
int angle;
unsigned int us;

//Enter here you data
const char pin_number[] = "****";     // Write the pin number of the SIM card

int8_t answer;
int onModulePin = 2;
char aux_string[50];

unsigned long previous;
int count;

void setup() {
  pinMode(onModulePin, OUTPUT);
  pinMode(servo, OUTPUT);
  Serial.begin(115200);

  printf("Starting...\n");
  power_on(); // Powering the module
  delay(3000);

  //sets the PIN code
  sprintf(aux_string, "AT+CPIN=%s", pin_number);
  sendATcommand(aux_string, "OK", 2000);
  
  delay(3000);
  
  printf("Connecting to the network...\n");

  while ( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) ||
           sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );

  printf("Setting SMS mode...\n");
  sendATcommand("AT+CMGF=1", "OK", 1000);    // sets the SMS mode to text
  sendATcommand("AT+CPMS=\"SM\",\"SM\",\"SM\"", "OK", 1000);    // selects the memory

  sendATcommand("AT+CNMI=2,1,0,0", "OK", 1000);    // Sets mode to wait for an incoming SMS
  
  printf("Waiting incoming SMS\n");
}


void loop() {
  answer = sendATcommand("", "+CMTI: ", 1000);
  //Detect incomming SMS
  if (answer == 1)
  {
    count = 0;
    previous = millis();
    do
    {
      while (((millis() - previous) < 1000) && (Serial.available() == 0))
      {
        // Condition to avoid an overflow 
        if ( millis() < previous) previous = millis();
      }
      // Condition to avoid an overflow
      if ( millis() < previous) previous = millis();
      //Search a "," in the command received
    } while (((millis() - previous) < 1000) && (Serial.read() != ','));

    previous = millis();
    do {
      
      while (((millis() - previous) < 1000) && (Serial.available() == 0))
      {
        // Condition to avoid an overflow 
        if ( millis() < previous) previous = millis();
      }
      
      aux_string[count] = Serial.read();
      count++;

      // Condition to avoid an overflow 
      if ( millis() < previous) previous = millis();
    } while ((aux_string[count - 1] != '\r') && ((millis() - previous) < 1000) && (count < 30));

    aux_string[count - 1] = '\0';

    count = atoi(aux_string);
    printf("SMS index: %i %s\n",count,aux_string);

    if (count != 0)
    {
      //Check the comunication with the module
      sendATcommand("AT", "OK", 1000);
      
      //Read the received SMS
      snprintf(aux_string, sizeof(aux_string), "AT+CMGR=%d", count);
      answer = sendATcommand(aux_string, "+CMGR:", 1000);
      if (answer == 1)
      {
        previous = millis();
        do
        {
          while (((millis() - previous) < 1000) && (Serial.available() == 0))
          {
            // Condition to avoid an overflow 
            if ( millis() < previous) previous = millis();
          }
          // Condition to avoid an overflow 
          if ( millis() < previous) previous = millis();
        } while (((millis() - previous) < 1000) && (Serial.read() != '\n'));

        count = 0;
        previous = millis();
        do {

          while (((millis() - previous) < 1000) && (Serial.available() == 0))
          {
            // Condition to avoid an overflow 
            if ( millis() < previous) previous = millis();
          }

          aux_string[count] = Serial.read();
          count++;

          // Condition to avoid an overflow 
          if ( millis() < previous) previous = millis();
        } while ((strstr(aux_string, "OK") == NULL) && ((millis() - previous) < 1000) && (count < 30));

        aux_string[count - 1] = '\0';
        printf("Received SMS: %s\n",aux_string);
        
        //Conversion de string a float
        
        angle = atof(aux_string);
        //The servo turn the angle read in the SMS
        servoWrite(servo,angle);
      }
    }


  }
}
void power_on() {
  uint8_t answer = 0;

  // checks if the module is started
  answer = sendATcommand("AT", "OK", 2000);
  if (answer == 0)
  {
    // power on pulse
    digitalWrite(onModulePin, HIGH);
    delay(3000);
    digitalWrite(onModulePin, LOW);

    // waits for an answer from the module
    while (answer == 0) {   // Send AT every two seconds and wait for the answer
      answer = sendATcommand("AT", "OK", 2000);
    }
  }

}

int8_t sendATcommand(const char* ATcommand, const char* expected_answer, unsigned int timeout){

    uint8_t x=0,  answer=0;
    char response[100];
    unsigned long previous;

    memset(response, '\0', 100);    // Initialize the string

    delay(100);

    while( Serial.available() > 0) Serial.read();    // Clean the input buffer

    Serial.println(ATcommand);    // Send the AT command 


        x = 0;
    previous = millis();

    // this loop waits for the answer
    do{
        if(Serial.available() != 0){    
            // if there are data in the UART input buffer, reads it and checks for the asnwer
            response[x] = Serial.read();
            printf("%c",response[x]);
            x++;
            // check if the desired answer  is in the response of the module
            if (strstr(response, expected_answer) != NULL)    
            {
				printf("\n");
                answer = 1;
            }
        }
    }
    // Waits for the asnwer with time out
    while((answer == 0) && ((millis() - previous) < timeout));    

        return answer;
}

void servoWrite(int servo, int angle)
{
  for(int i=0; i<20; i++){
    us = (angle*11) + 450;      // Convert angle to microseconds
    digitalWrite(servo, HIGH);
    delayMicroseconds(us);
    digitalWrite(servo, LOW);
    delay(50);                  // Refresh cycle of servo
  }               
}



int main (){
    setup();
    while(1){
        loop();
    }
    return (0);
}


        

Intel Galileo:

Code:
/*  
 *  GPRS+GPS Quadband Module (SIM908)
 *  
 *  Copyright (C) Libelium Comunicaciones Distribuidas S.L. 
 *  http://www.libelium.com 
 *  
 *  This program is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version. 
 *  a
 *  This program is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *  
 *  Version:           1.0
 *  Design:            David GascĂłn 
 *  Implementation:    Jorge Casanova, Luis MartĂ­n
 */

#include <Servo.h> //Include the servo-motor library

//Enter here you data
const char pin_number[] = "****";     // Write the pin number of the SIM card

Servo myServo;  // Create a servo object
int angle;   // Variable to hold the angle for the servo motor


int8_t answer;
int onModulePin = 2;
char aux_string[50];

unsigned long previous;
int count;

void setup() {
  myServo.attach(9); // Attaches the servo on pin 9 to the servo object
  myServo.write(90); // Set the servo in the center position
  pinMode(onModulePin, OUTPUT);
  Serial.begin(115200);
  Serial1.begin(115200);

  Serial.println("Starting...");
  power_on(); // Powering the module

  delay(3000);

  //sets the PIN code
  sprintf(aux_string, "AT+CPIN=%s", pin_number);
  sendATcommand(aux_string, "OK", 2000);
  
  delay(3000);
  
  Serial.println("Connecting to the network...");

  while ( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) ||
           sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );

  Serial.print("Setting SMS mode...");
  sendATcommand("AT+CMGF=1", "OK", 1000);    // sets the SMS mode to text
  sendATcommand("AT+CPMS=\"SM\",\"SM\",\"SM\"", "OK", 1000);    // selects the memory

  sendATcommand("AT+CNMI=2,1,0,0", "OK", 1000);    // Sets mode to wait for an incoming SMS
  
  Serial.println("Waiting incoming SMS");
}


void loop() {
  answer = sendATcommand("", "+CMTI: ", 1000);
  //Detect incomming SMS
  if (answer == 1)
  {
    count = 0;
    previous = millis();
    do
    {
      while (((millis() - previous) < 1000) && (Serial1.available() == 0))
      {
        // Condition to avoid an overflow 
        if ( millis() < previous) previous = millis();
      }
      // Condition to avoid an overflow
      if ( millis() < previous) previous = millis();
      //Search a "," in the command received
    } while (((millis() - previous) < 1000) && (Serial1.read() != ','));

    previous = millis();
    do {
      
      while (((millis() - previous) < 1000) && (Serial1.available() == 0))
      {
        // Condition to avoid an overflow 
        if ( millis() < previous) previous = millis();
      }
      
      aux_string[count] = Serial1.read();
      count++;

      // Condition to avoid an overflow 
      if ( millis() < previous) previous = millis();
    } while ((aux_string[count - 1] != '\r') && ((millis() - previous) < 1000) && (count < 30));

    aux_string[count - 1] = '\0';

    count = atoi(aux_string);
    Serial.print("SMS index: ");
    Serial.println(count, DEC);
    Serial.println(aux_string);

    if (count != 0)
    {
      //Check the comunication with the module
      sendATcommand("AT", "OK", 1000);
      
      //Read the received SMS
      snprintf(aux_string, sizeof(aux_string), "AT+CMGR=%d", count);
      answer = sendATcommand(aux_string, "+CMGR:", 1000);
      if (answer == 1)
      {
        previous = millis();
        do
        {
          while (((millis() - previous) < 1000) && (Serial1.available() == 0))
          {
            // Condition to avoid an overflow 
            if ( millis() < previous) previous = millis();
          }
          // Condition to avoid an overflow 
          if ( millis() < previous) previous = millis();
        } while (((millis() - previous) < 1000) && (Serial1.read() != '\n'));

        count = 0;
        previous = millis();
        do {

          while (((millis() - previous) < 1000) && (Serial1.available() == 0))
          {
            // Condition to avoid an overflow 
            if ( millis() < previous) previous = millis();
          }

          aux_string[count] = Serial1.read();
          count++;

          // Condition to avoid an overflow 
          if ( millis() < previous) previous = millis();
        } while ((strstr(aux_string, "OK") == NULL) && ((millis() - previous) < 1000) && (count < 30));

        aux_string[count - 1] = '\0';
        Serial.print("Received SMS: ");
        Serial.println(aux_string);
        
        //Conversion de string a int
        angle = atoi(aux_string);
        //The servo turn the angle read in the SMS
        myServo.write(angle);
      }
    }


  }
}
void power_on() {

  uint8_t answer = 0;

  // checks if the module is started
  answer = sendATcommand("AT", "OK", 2000);
  if (answer == 0)
  {
    // power on pulse
    digitalWrite(onModulePin, HIGH);
    delay(3000);
    digitalWrite(onModulePin, LOW);

    // waits for an answer from the module
    while (answer == 0) {   // Send AT every two seconds and wait for the answer
      answer = sendATcommand("AT", "OK", 2000);
    }
  }

}

int8_t sendATcommand(char * ATcommand, char * expected_answer, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialice the string

  delay(100);

  while ( Serial1.available() > 0) Serial1.read();   // Clean the input buffer

  if (ATcommand[0] != '\0')
  {
    Serial1.println(ATcommand);    // Send the AT command
  }


  x = 0;
  previous = millis();

  // this loop waits for the answer
  do {
    // if there are data in the UART input buffer, reads it and checks for the asnwer
    if (Serial1.available() != 0) {
      response[x] = Serial1.read();
      x++;
      // check if the desired answer is in the response of the module
      if (strstr(response, expected_answer) != NULL)
      {
        answer = 1;
      }
    }
    // Waits for the asnwer with time out
  } while ((answer == 0) && ((millis() - previous) < timeout));

  return answer;
}	  
		

If you are interested in Internet of Things (IoT) or M2M projects check our open source sensor platform Waspmote which counts with more than 100 sensors available to use 'off the shelf', a complete API with hundreds of ready to use codes and a low consumption mode of just 0.7µA to ensure years of battery life.

Know more at:

Get the Starter Kits at: