Servo Motor & getting value from external HTTP request

Hi you all awesome people.
I am trying to get the servo motor to tilt according to a value fed by a php page which return just a 0-180 number.
So every couple of seconds I need to move to the new position according to the php script.
HTTP request and response works, but the servo is tilting quickly few degrees and then return to its original state.
So I think I miss the basic of it.
Could it be that the myservo.write(xxx) requires an int instead I have a char so it gets confused ?

Thanks for helping.

M.

Here is my code:

#include <SPI.h>
#include <Ethernet.h>
#include <Servo.h>

Servo myservo;

byte mac = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server = “dev.massimo.se”;
IPAddress ip(192,168,1,177);
EthernetClient client;
//////////////////////

void setup(){

myservo.attach(9);
Ethernet.begin(mac, ip);
Serial.begin(9600);
}

void loop(){
sendGET();
delay(2000);
}

//////////////////////////

void sendGET() //client function to send/receive GET request data.
{

int pos;

if (client.connect(server, 80)) {
Serial.println(“connected”);
client.println(“GET /arduino/servo.php HTTP/1.1”);
client.println(“Host: dev.massimo.se”);
client.println(“Connection: close”);
client.println();
}
else {
Serial.println(“connection failed”);
Serial.println();
}

while(client.connected() && !client.available()) delay(1);
while (client.connected() || client.available()) {
char c = client.read();
Serial.print(c);

myservo.write(c);

}

Serial.println();
Serial.println(“disconnecting.”);
Serial.println("==================");
Serial.println();
client.stop();

}

while (client.connected() || client.available()) {
  char c = client.read();
  Serial.print(c);

  myservo.write(c);

Several problems here. First, the while statement should be while the client is connected AND the client is available (not OR).

Second, the PHP script is almost certainly sending a text string, not a binary value. You need to collect all the data in an array, until the end of packet is received (however that happens) and then parse and convert the data to an int to give to the servo.

Could it be that the myservo.write(xxx) requires an int instead I have a char so it gets confused ?

Yes, it does require an int. I can’t speak to your php stuff, but below is router bot control web page that sends servo control values to the arduino server.

//zoomkat 11-20-12//routerbot code
//for use with Arduino IDE 1.0
//open serial monitor to see what the arduino receives
//address will look like http://192.168.1.102:84 when submited
//servos are continous rotation for drive wheels 

#include <SPI.h>
#include <Ethernet.h>
#include <Servo.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
String readString, servo1, servo2; //strings to hold data
Servo myservo1, myservo2;  // create servo object to control a servo 
//Servo myservo2;
//////////////////////
void setup(){
  //start Ethernet
  Ethernet.begin(mac,ip,gateway,gateway,subnet);
  server.begin();

  //enable serial data print 
  Serial.begin(9600); 
  myservo1.attach(7);
  myservo2.attach(6);
  Serial.println("routerbot-11-20-12"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        //read char by char HTTP request
        if (readString.length() < 100) {
          //store characters to string 
          readString += c; 
        } 
        //if HTTP request has ended
        if (c == '\n') {
          ///////////////
          //readString looks like "GET /?-1500-1500 HTTP/1.1"
          Serial.print(readString);
          //now output HTML data header
          if(readString.indexOf('?') >=0) { //don't send new page
            client.println(F("HTTP/1.1 204 Zoomkat"));
            client.println();
            client.println();  
          }
          else {   
            client.println(F("HTTP/1.1 200 OK")); //send new page on browser request
            client.println(F("Content-Type: text/html"));
            client.println();
            client.println(F("<HTML><HEAD>"));
            client.println(F("<H3>Zoomkat's Routerbot
Web Control Page
11-20-12</H3>"));
            client.println(F("<TITLE>Zoomkat's Routerbot Control Page</TITLE>"));
            client.println(F("</HEAD><BODY>"));
            client.println(F("Foward&nbsp;&nbsp;&nbsp;-*Stop*-&nbsp;&nbsp;&nbsp;Reverse
"));
            client.println(F("<a href=/?-1000-2000 target=inlineframe>F-F</a>|"));
            client.println(F("<a href=/?-1450-1550 target=inlineframe>S-F</a>|"));
            client.println(F("<a href=/?-1500-1500 target=inlineframe>*-Stop-*</a>|"));
            client.println(F("<a href=/?-1550-1450 target=inlineframe>S-R</a>|"));
            client.println(F("<a href=/?-2000-1000 target=inlineframe>F-R</a>|

"));
            client.println(F("Turn-L&nbsp;&nbsp;&nbsp;-*Stop*-&nbsp;&nbsp;&nbsp;Turn-R
"));
            client.println(F("<a href=/?-1000-1000 target=inlineframe>F-L</a>|"));
            client.println(F("<a href=/?-1450-1450 target=inlineframe>S-L</a>|"));
            client.println(F("<a href=/?-1500-1500 target=inlineframe>*-Stop-*</a>|"));
            client.println(F("<a href=/?-1550-1550 target=inlineframe>S-R</a>|"));
            client.println(F("<a href=/?-2000-2000 target=inlineframe>F-R</a>|
"));
            client.println(F("<IFRAME name=inlineframe style='display:none'>")); 
            client.println(F("</IFRAME>

"));
            client.println(F("<a href=\"#\"onClick=\"MyWindow=window.open('http://192.168.1.102:84/',"));
            client.println(F("'MyWindow','width=200,height=200');\">Popout Control Window</a>"));
            client.println(F("</body></html>"));
          }
          delay(1);
          //stopping client
          client.stop();

          if (readString.length() >0) {
            //Serial.println(readString);
            servo1 = readString.substring(7, 11);
            servo2 = readString.substring(12, 16);

            int n1 = servo1.toInt();
            int n2 = servo2.toInt();

            Serial.println("the numbers are :");
            Serial.println(n1);  //print to serial monitor to see number results
            Serial.println(n2);
            Serial.println("");
            myservo1.writeMicroseconds(n1); //set servo position 
            myservo2.writeMicroseconds(n2);
            //clearing string for next read            
            readString="";
            servo1="";
            servo1="";
          } 
        }
      }
    }
  }
}

Zoomkat, i am trying to understand the code in your example, as i want to modify it to work with a different speed controller. I dont understand how the String works, or where it gets its values from.

Can you explain to a beginner, how this code of your works?

Northof49: Zoomkat, i am trying to understand the code in your example, as i want to modify it to work with a different speed controller. I dont understand how the String works, or where it gets its values from.

Can you explain to a beginner, how this code of your works?

The arduino (with a w5100 based ethernet shield) is running web server code which supplies a web page to a requesting browser. The web page has clickable links that send GET request to the arduino with the servo commands embedded in the request. A GET request like "GET /?-1000-2000 HTTP/1.1" is captured in the String "readString" and then parsed to get the servo command values. Below is what is displayed in the serial monitor when the GET request is received by the arduino and processed.

GET /?-1000-2000 HTTP/1.1
the numbers are :
1000
2000

GET /?-1450-1550 HTTP/1.1
the numbers are :
1450
1550

GET /?-1500-1500 HTTP/1.1
the numbers are :
1500
1500

How does it write to the servos? I thought servos needed a 0-180 write to turn?

Northof49:
How does it write to the servos? I thought servos needed a 0-180 write to turn?

Using servo.writeMicroseconds() provides finer control of the servo than servo.write(). For continuous rotation servos servo.writeMicroseconds() provides much better servo control. Below is some servo control code you can use to see the difference between the two methods.

// zoomkat 3-28-14 serial servo incremental test code
// using serial monitor type a character (s to increase or a 
// to decrease) and enter to change servo position 
// (two hands required, one for letter entry and one for enter key)
// use strings like 90x or 1500x for new servo position 
// for IDE 1.0.5 and later
// Powering a servo from the arduino usually *DOES NOT WORK*.

#include<Servo.h>
String readString;
Servo myservo;
int pos=1500; //~neutral value for continuous rotation servo
//int pos=90;

void setup()
{
  myservo.attach(7, 400, 2600); //servo control pin, and range if desired
  Serial.begin(9600);
  Serial.println("serial servo incremental test code");
  Serial.println("type a character (s to increase or a to decrease)");
  Serial.println("and enter to change servo position");
  Serial.println("use strings like 90x or 1500x for new servo position");
  Serial.println();
}

void loop()
{
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }
  if (readString.length() >0) {
    if(readString.indexOf('x') >0) { 
      pos = readString.toInt();
    }

    if(readString =="a"){
      (pos=pos-1); //use larger numbers for larger increments
      if(pos<0) (pos=0); //prevent negative number
    }
    if (readString =="s"){
      (pos=pos+1);
    }

    if(pos >= 400) //determine servo write method
    {
      Serial.println(pos);
      myservo.writeMicroseconds(pos);
    }
    else
    {   
      Serial.println(pos);
      myservo.write(pos); 
    }
  }
  readString=""; //empty for next input
}

Thank you very much!

I now have it working with a motor speed controller that mixes throttle and steering. It works well, other than the slight delay between between the client and server.

My plans are to add more controls for finer increments of steering and movement, see if I can get the server to also serve up various data such as distance readings, gps, etc and add an ip camera.

I currently have software running that serves up data, gps, compass and distance readings. I'm hoping I can integrate it into your sketch, or vice versa.

I now have it working along with software that reads various sensors, distances, gps and compass. I have it print out the data on the screen beneath the control commands, which I have expanded upon for more fine motor control.

The only problem is that I have to refresh the web browser to get updated values. Is there a way I could have the server automatically refresh it's values perhaps every second or two? Or would that take too long interfere with the motor control?

The only problem is that I have to refresh the web browser to get updated values. Is there a way I could have the server automatically refresh it’s values perhaps every second or two? Or would that take too long interfere with the motor control?

You might put the data in an iframe some what like below.

// zoomkat's meta refresh data frame test page 5/25/13
// use http://192.168.1.102:84 in your brouser for main page
// http://192.168.1.102:84/data static data page
// http://192.168.1.102:84/datastart meta refresh data page
// for use with W5100 based ethernet shields
// set the refresh rate to 0 for fastest update
// use STOP for single data updates

#include <SPI.h>
#include <Ethernet.h>

const int analogInPin0 = A0;
const int analogInPin1 = A1;
const int analogInPin2 = A2;
const int analogInPin3 = A3;
const int analogInPin4 = A4;
const int analogInPin5 = A5;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // arduino ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
unsigned long int x=0; //set refresh counter to 0
String readString; 

//////////////////////

void setup(){
  Serial.begin(9600);
    // disable SD SPI if memory card in the uSD slot
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();
  Serial.println("meta refresh data frame test 5/25/13"); // so I can keep track of what is loaded
}

void loop(){
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
         if (readString.length() < 100) {
          readString += c; 
         } 
        //check if HTTP request has ended
        if (c == '\n') {

          //check get atring received
          Serial.println(readString);

          //output HTML data header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();

          //generate data page
          if(readString.indexOf("data") >0) {  //checks for "data" page
            x=x+1; //page upload counter
            client.print("<HTML><HEAD>");
            //meta-refresh page every 1 seconds if "datastart" page
            if(readString.indexOf("datastart") >0) client.print("<meta http-equiv='refresh' content='1'>"); 
            //meta-refresh 0 for fast data
            if(readString.indexOf("datafast") >0) client.print("<meta http-equiv='refresh' content='0'>"); 
            client.print("<title>Zoomkat's meta-refresh test</title></head><BODY>
");
            client.print("page refresh number: ");
            client.print(x); //current refresh count
            client.print("

");
            
              //output the value of each analog input pin
            client.print("analog input0 is: ");
            client.print(analogRead(analogInPin0));
            
            client.print("
analog input1 is: ");
            client.print(analogRead(analogInPin1));
                        
            client.print("
analog input2 is: ");
            client.print(analogRead(analogInPin2));
            
            client.print("
analog input3 is: ");
            client.print(analogRead(analogInPin3));
                                    
            client.print("
analog input4 is: ");
            client.print(analogRead(analogInPin4));
            
            client.print("
analog input5 is: ");
            client.print(analogRead(analogInPin5));
            client.println("
</BODY></HTML>");
           }
          //generate main page with iframe
          else
          {
            client.print("<HTML><HEAD><TITLE>Zoomkat's frame refresh test</TITLE></HEAD>");
            client.print("Zoomkat's Arduino frame meta refresh test 5/25/13");
            client.print("

Arduino analog input data frame:
");
            client.print("&nbsp;&nbsp;<a href='/datastart' target='DataBox' title=''yy''>META-REFRESH</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='/data' target='DataBox' title=''xx''>SINGLE-STOP</a>");
            client.print("&nbsp;&nbsp;&nbsp;&nbsp;<a href='/datafast' target='DataBox' title=''zz''>FAST-DATA</a>
");
            client.print("<iframe src='/data' width='350' height='250' name='DataBox'>");
            client.print("</iframe>
</HTML>");
          }
          delay(1);
          //stopping client
          client.stop();
          //clearing string for next read
          readString="";
        }
      }
    }
  }
}

Is there a way I could have the server automatically refresh it's values perhaps every second or two?

The server should refresh data far more often than that. The client should ask for a refresh less often than than.

Or would that take too long interfere with the motor control?

Having the client(s) request a new page too often WILL interfere with the Arduino's ability to do anything else.

That works slick. Now to figure out how it works.