Sunday, August 7, 2016

Posting to Thingspeak over GPRS with SIM900 & Seeeduino Stalker & GPRSBee

My family has a cabin in the remote upper peninsula of Michigan. There we have a solar array that keeps the various vehicles batteries charged over the winter. I wanted to track the battery status through the winter when no one is up there. However, there is no internet up that far, but there is cell phone reception. So the plan is to have a Seeeduino Stalker run up 24/7/365 off of a lipo battery. Every hour or so it will power up and push the state of charge of the battery bank and voltage of the solar panels to Thingspeak.

A few people have worked on this, but even less have published in detail how to do it for the rest of us. So I've been working on it for the last month or so. I now have the GPRS able to connect to thingspeak and push data manually. All I have to do it clean up the code and make it into a more power friendly version that will work year round.

Hardware:

SeeedStalker 3.0
GPRS Bee Rev. 4 (SIM900)
LiPo Battery

Steps:
  1. Wake Seeedstalker from sleep
  2. Power up GPRSBee
  3. Pull data from sensors
  4. Connect to wireless network
  5. Connect to thingspeak
  6. Push data to thingspeak
Hardware Modifications:

It is necessary to solder P3 and P4 for for the RTC interrupts to function correctly. See the Seeeduino Stalker wiki for more details on this.
You will also need to solder a wire from pin 9 on the Bee socket to D5. See why here:
http://old.gprsbee.com/ 
Finally, for debugging, I find it's essential to have serial communication with my computer, so I've had to switch to using SW serial on D6 & D7. This means dealing with the Seeeduino Stalker v3.0's hardware bug. I found Seeed's wiki does not completely address the hardware bug. I had to cut a trace on P6 in addition to the one for P7. If you're having a hard time, just use a multi-meter to ensure you are wired how you expect to be.


Code:

1) Wake Seeedstalker from sleep -

This code has been written mostly by SeeedStudio on their wiki:
http://www.seeedstudio.com/wiki/Seeeduino-Stalker_v3#Data_Logger_Example
I'm not going to cover it again.

2) Power up GPRSBee - I will be adding this gradually in the coming weeks.
void gprspwr_on()
{
  Serial.println("Turning on GPRS");
  pinMode(5, OUTPUT);
  digitalWrite(5,LOW);
  delay(1000);
  digitalWrite(5,HIGH);
  delay(2000);
  digitalWrite(5,LOW);
  readATcommand("Call Ready",6,10000);
  if (answer == 1){
    Serial.println("GPRSbee is on!");
  }
}

void gprspwr_off()
{
  Serial.println("Turning off GPRS");
  pinMode(5, OUTPUT);
  digitalWrite(5,LOW);
  delay(1000);
  digitalWrite(5,HIGH);
  delay(2000);
  digitalWrite(5,LOW);
  answer = readATcommand("NORMAL POWER DOWN",2,2000);
  if (answer == 1){
    Serial.println("Sucessful Powerdown Complete");
  }
}

boolean gprspwr_status()
{
  Serial.println("GPRS Power Status");
  answer = sendATcommand("AT", "OK", 2, 2000);
  if (answer == 0){
    Serial.println("GPRSbee is Powered off!");
  }  
  else if (answer == 1){
    Serial.println("GPRSbee is on!");
  }
  return answer;
}

int8_t readATcommand(char* expected_answer1, unsigned int expected_answers, unsigned int timeout)
{

  uint8_t x=0,  answer=0;
  boolean complete = 0;
  char a;
  char response[100];
  unsigned long previous;
  String  incomingdata;
  boolean first;

  previous = millis();

  for(int i = 0; i < expected_answers; i++){
    x = 0;
    complete = 0;
    a = 0;
    first = 0;
    memset(response, '\0', 100);    // Initialize the string
    do{
      if(SIM900.available() != 0){
        a = SIM900.read();
        //Serial.println(a,DEC);
        if (a == 13){
          a = SIM900.read();
          //Serial.println(a,DEC);
          if (a == 10){
            if (first == 0){
              //keep going, just ignore it
            }
            else{
              Serial.print("string: #");
              Serial.print(response);
              Serial.println("#");
              complete = 1;
            }
          }
        }
        else if(a == 0){
          Serial.println("Found a blank");
        }
        else  {
          response[x] = a;
          x++;
          first = 1;
          //Serial.println(response);
        }
        if(strstr(response, expected_answer1) != NULL)
        {
          answer = 1;
          complete = 1;
          Serial.print("string: #");
          Serial.print(response);
          Serial.println("#");
          return answer;
        }
        else if(strstr(response, "ERROR") != NULL)
        {
          answer = 2;
        }
      }
    }
    while((complete == 0) && ((millis() - previous) < timeout));
    //Serial.println(i);
 
  }

  return answer;
}

3) Pull data from sensors - This is dependent on your application, so I'm not going to cover it.

4) Connect to wireless network & thingspeak - I will be adding this gradually in the coming weeks.

void loop() {
  if (SIM900.available())
  {
    Serial.write(SIM900.read());
  }
  //power up gprs
  gprspwr_on();

  //connect gprs to internet
  answer = sendATcommand("AT+CGATT?","OK",5,2000);
  answer = sendATcommand("AT+CSTT=\"CMNET\"","OK",3,2000);
  answer = sendATcommand("AT+CIICR","OK",3,2000);
  answer = sendATcommand("AT+CIFSR","OK",3,2000);
  answer = sendATcommand("AT+CIPSPRT=0","OK",3,2000);

  //connect gprs to thingspeak
  answer = sendATcommand("AT+CIPSTART=\"tcp\",\"api.thingspeak.com\",\"80\"","CONNECT OK",5,2000);

  //post data to thingspeak
  answer = senddata(battery_percent());

  delay(5000);

  //power down gprs
  gprspwr_off();

  //put arduino to sleep?
  for (int i=0; i<60; i++){
    delay(1000);
    Serial.println(i);
  }
}

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

  uint8_t x=0,  answer=0;
  boolean complete = 0, first = 0;
  char a;
  char response[100];
  unsigned long previous;
  String  incomingdata;


  delay(100);
  //Serial.println("Send AT Command");
  while( SIM900.available() > 0) SIM900.read();    // Clean the input buffer
  SIM900.println(ATcommand);    // Send the AT command
  Serial.println(ATcommand);
  //Serial.println("AT Command Sent!");

  previous = millis();

  for(int i = 0; i < expected_answers; i++){
    x = 0;
    complete = 0;
    a = 0;
    first = 0;
    memset(response, '\0', 100);    // Initialize the string
    do{
      if(SIM900.available() != 0){
        a = SIM900.read();
        //Serial.println(a);
        //Serial.println(a,DEC);
        if (a == 13){
          a = SIM900.read();
          //Serial.println(a,DEC);
          if (a == 10){
            if (first == 0){
              //keep going, just ignore it
            }
            else{
              Serial.print("string: #");
              Serial.print(response);
              Serial.println("#");
              complete = 1;
            }
          }
        }
        else if(a == 0){
          Serial.println("Found a blank");
        }
        else  {
          response[x] = a;
          x++;
          first = 1;
          //Serial.println(response);
        }
        if (strstr(response, expected_answer1) != NULL)  
        {
          answer = 1;
          complete = 1;
          Serial.print("string: #");
          Serial.print(response);
          Serial.println("#");
        }
        else if(strstr(response, "ERROR") != NULL)
        {
          answer = 2;
          complete = 1;
        }
      }
    }
    while((complete == 0) && ((millis() - previous) < timeout));
 
  }
  return answer;
}

5) Push data to thingspeak - I will be adding this gradually in the coming weeks.

int8_t senddata(float data){

  Serial.print("Battery Percent = ");
  Serial.println(data);

  //while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  SIM900.println("AT+CIPSEND");
  //Serial.println("AT+CIPSEND");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("POST /update HTTP/1.1");    // Send the AT command
  //Serial.println("POST /update HTTP/1.1");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Host: api.thingspeak.com");    // Send the AT command
  //Serial.println("Host: api.thingspeak.com");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Connection: close");    // Send the AT command
  //Serial.println("Connection: close");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("X-THINGSPEAKAPIKEY: J79IQXQ0EOM6NCZX");    // Send the AT command
  //Serial.println("X-THINGSPEAKAPIKEY: J79IQXQ0EOM6NCZX");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Content-Type: application/x-www-form-urlencoded");    // Send the AT command
  //Serial.println("Content-Type: application/x-www-form-urlencoded");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("Content-Length:12");    // Send the AT command
  //Serial.println("Content-Length:12");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println("");    // Send the AT command
  //Serial.println("");
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.print("field1=");    // Send the AT command
  SIM900.println(data);
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);
  SIM900.println((char)26);
  delay(500);
  while( SIM900.available() > 0) Serial.write(SIM900.read());    // Clean the input buffer
  delay(500);

  answer = 0;
  return answer;
}


Complete Code:

GPRS ThingSpeak v0.1 Beta

Useful Links:

Seeeduino Stalker v3 Wiki:
http://www.seeedstudio.com/wiki/Seeeduino-Stalker_v3

Original GPRSBee Site:
 http://old.gprsbee.com/

GSM Particulate Sensor - Thanks alcomposer!!! This code helped me a lot and some of my code is base on this.
https://github.com/alcomposer/GSM-Particulate-Meter/blob/master/ParticulateSensorSIM900.ino

SIM900 Thingspeak Code - Thanks maliki!!! This code was also key in helping me get all of this together.
https://codebender.cc/sketch:267851#sim900%20thingspeak.ino

Misc Others:
http://community.thingspeak.com/forum/thingspeak-api/http-post-using-gsm-module/
https://www.pubnub.com/blog/2015-02-17-connect-arduino-gsm-gprs-shield-to-the-internet/
https://community.particle.io/t/uploading-sensor-data-to-thingspeak/5497
http://www.seeedstudio.com/wiki/Seeeduino_GPRS

Sunday, April 3, 2016

New 3020 CNC Controller Box


  I'm not happy with my current controller setup. It just looks terrible, consists of two separate boxes, with a hanging out a-axis stepper driver. My plans are to design and entirely new controller box with all new hardware (almost). The plan is to make it an affordable upgrade since I'm on a tight budget these days. That means no Gecko drives '-( In addition to the 4 axes, there will be a spindle controller and an Arduino for controlling the heaters on the 3D printer. The intention is to have a dual purpose box for both CNC routing and 3D printing.

Component List:
1x 200 x 400 x 40mm Enclosure
4x RATTM RTM5742A Stepper Drivers - Details
1x Generic 480Watt 24V 20A Power Supply
5x 5-Pin Twist-Lock Connectors
4x 12mm Assorted Connectors
1x SCR Motor Driver - Reused from original controller box
1x 5-Axis Isolated Breakout Board
1x 5V Isolated Regulator - To Power the Breakout Board






Later I will be adding an Arduino board to control the heaters as well as machining new front and rear panels to the box.

Stepper Motor Drivers - Rattm RTM5742A Review

I'm currently in the planning/ordering stage of  my build of a new controller box for the 3020 CNC router/printer. I've been looking around for motor drivers and there are a lot of cheap options and some expensive options. There are not many good options in the $20-$40 range. Gecko drives are of course always ideal, but $100 per axis is out of my budget. I have been hunting on eBay for a while and have previously posted on the notorious HY-DIV268N-5A. In my eBay searches  I also saw a few drives that looked similar the the HY-DIV268N-5A, but had are rumored to have performed much better. I wanted to try them out!


They appear to all be based on Leadshine and rebranded into at least two other names, Rattam and Wantai.


Rattam Motor RTM5740A
Price: $25

I have purchased 4x RTM5742A drives and plan to do some analysis of the hardware. I hope to get a good idea of the quality and share this with you.

Based on the ON Semiconductor LV8727. I have sadly found that there are several other boards based on the same IC for much cheaper, some as low as $10 each. Just search for "DD8727v1" on google or eBay.

To be continued....