Controlling 2 servo motors with Arduino via Processing (is there a better way?)

I´m pretty new to Arduino but has been determend to build me a little USB-robot controlled with the WASD-keyboard keys.

I have bought the s.k. "junkBot-kit" from Robobits (http://robotbits.co.uk/robot-kits/junkbot-kit/prod_97.html) and have after two days succesfully gotten the to motors to run forward when pressing W, backwards when pressing S, turning when pressing A and the other wayt around with D. So, all good so far.

What I´m interested in is if there perhaps is a much better way to to this. It has been many hours of copy pasting, trail-and-error that got me this code and I have a feeling there is much improvment to be done :slight_smile: The code seem to work fine. The only thing that concerns me is that the servo motors sometimes is a little "choppy" in their movment. That is without a doubt due to the use of "delay(17)" code, to make them stop for 17 millisek between every reading of the last serial command. But I can´t seem to figure out a better way :slight_smile: So, let me have it!

Code needs a lot of beauty-work, I know. Also ignore the img-part. Only me playing with code :slight_smile:

Arduino code:

#include <Servo.h>

int leftServoPin = 0; // 
int rightServoPin = 5; // 

int incomingByte;      // a variable to read incoming serial data into

Servo leftservo; // Define our Servo 1
Servo rightservo; // Define our Servo 1

void setup()
{
   leftservo.attach(leftServoPin + 14);     // attaches the servo object to correct Analog pin
   rightservo.attach(rightServoPin + 14);     // attaches the servo object to correct Analog pin
                 Serial.begin(9600);
}

void loop(){ 

    if (Serial.available() > 0) {
    // read the oldest byte in the serial buffer:
    incomingByte = Serial.read();
    if (incomingByte == 'W') {

                 leftservo.write(110);
                 rightservo.write(70);
                 delay (17);
                 leftservo.write(90);
                 rightservo.write(90);
                }
                
     if (incomingByte == 'S') {

                 leftservo.write(70);
                 rightservo.write(110);
                 delay (17);
                 leftservo.write(90);
                 rightservo.write(90);
                }

     if (incomingByte == 'A') {

                 leftservo.write(110);
                 rightservo.write(110);
                 delay (17);
                 leftservo.write(90);
                 rightservo.write(90);
                }

     if (incomingByte == 'D') {

                 leftservo.write(70);
                 rightservo.write(70);
                 delay (17);
                 leftservo.write(90);
                 rightservo.write(90);
                }
    } else {
                 leftservo.write(90);
                 rightservo.write(90);
    }
}

Processing code:

import processing.serial.*;
Serial myPort; 
PImage img;

void setup() { 
   size(100, 100); 

   println(Serial.list()); 
   myPort = new Serial(this, Serial.list()[0], 9600); 

 img = loadImage("arrow-right.gif");
}
void draw() { 
  
  rect(25, 25, 50, 50); 
  
  if (keyPressed) { 
    
    if (key == 'w') { 
      myPort.write('W'); 
      fill(0); 
    }
    if (key == 's') { 
      myPort.write('S'); 
      fill(150); 
    }
    if (key == 'a') { 
      myPort.write('A');
      fill(150);
    }
    if (key == 'd') {
      myPort.write('D');      
      image(img, 25, 25);
    }

  } else { 
    fill(255); 
  }
}

Well for what it is worth, I must say you have accomplished a lot more than most Newbies do before they post for help. More than 30% of the time they don't even know what kind of motor they are going to use or how to drive it. One guy posted because he was puzzled because his 2A stepper motor wasn't working with a 9V smoke alarm battery. Can you believe that ? When we told him what the problem was he replied "oh, that can't be the problem because I already tried C & D size batteries...." We got a good laugh
out of that.

Are you using continuous rotation servos?

If so then this code

leftservo.write(110);
                 rightservo.write(70);
                 delay (17);
                 leftservo.write(90);
                 rightservo.write(90);

probably shouldn't have the last two lines which tell the motors to stop almost immediately after telling them to move.

And "delay(17)" is just 17 millisecs. I'm not sure if that serves any purpose. Try deleting it.

...R

You are absolutely right! The two last lines was not nessesary.

The delay is however needed. If I take it away the motors don´t have time to start since of the command sent to them only being processed for like 1ms. If i however add more than 17-20ish ms to delay the delay-time stacks up and when I then hold the button on the keyboard to drive the motors they don´t stop when i let the button go. Instead they stop when the stacked up ms is out.

For reference, if I change the delay to say 1000ms (1 sec) and hold down the responding keyboard button the motors go on way to long after the button is released. However, giving a lower value than 17 makes the motors run very choppy. And even with 17 they strutter every once in a while as well. I think I need to get them running smoother. Somthing like "Keep running untill the button is actually released", but can´t seem to find that kind of function...

If you look at the Blink Without Delay example sketch you will see that it is possible to get the same effect without using the delay() instruction which, as you have found out, just gets in the way - at least with longer delays.

...R

Some servo test code that uses the serial monitor to increase or decrease the command value being sent to the servo. Don't currently have a servo to test it on, but should work. You should be able to see the servo speed control difference between using the deg. value and microseconds. You could also use it to adjust the servo pot to the desired neutral point value. The code is set up for the right hand to hit the enter key and the left hand hit the a or s key.

// 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 
// 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 continous 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
}