Robot arm control

Hey guys, I’ve spent A LOT of time trying to figure this out and finally had to give up and try here. I’m trying to control a robot arm by using the keys on my computer (using java though serial communication). I’m almost positive that it does what I tell it to do and then just stops. I think this because one, it does the first thing I tell it to do then doesn’t respond to the next set of commands and two, I’m using the visual micro debugger and it just stops showing anything after running the first command. Here’s the code tonned down a bit.

#include <Servo.h>

Servo bases;

byte serial;
const int p = 90;
const int r = 20;
const int l = -20;

void setup() {
bases.attach(2);

Serial.begin(9600);
while (!Serial);
}

void loop() {
serial = Serial.read();

switch (serial) {
case 1:base(l);
break;

case 2:base(r);
break;

default:
break;
}
serial = 0;
}

void base(int num){
if (!check(bases, num)) {
bases.write(p - num);
delay(num*4);
}
}

boolean check(Servo s, int num) {
if ((s.read() <= 5 && num < 0)|| (s.read() >= 175 && num>0))
return true;
else
return false;
}

I just put the code for one servo. Thanks.

I'm trying to control a robot arm by using the keys on my computer (using java though serial communication)

If your java code opens and closes the pc comport for each command, that could be causing the arduino to reset every time a command is sent. Also, please read #7 below:

http://forum.arduino.cc/index.php/topic,148850.0.html

What zoomkat said. Also, it is unclear why you read from Serial without first checking that a character is available.

Below is some servo test code you might use with the serial monitor to test your servos. There has been code posted in the forum that is a varient of the “sweep” example code that moves a servo slowly as long as a specific condition exist.

//zoomkat 11-22-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added 
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);

  //myservoa.writeMicroseconds(1500); //set initial servo position if desired

  myservoa.attach(6);  //the pin for the servoa control
  myservob.attach(7);  //the pin for the servob control
  myservoc.attach(8);  //the pin for the servoc control
  myservod.attach(9);  //the pin for the servod control 
  Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}

void loop() {

  //expect single strings like 700a, or 1500c, or 2000d,
  //or like 30c, or 90a, or 180d,
  //or combined like 30c,180b,70a,120d,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
          if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.write(n);
          if(readString.indexOf('b') >0) myservob.write(n);
          if(readString.indexOf('c') >0) myservoc.write(n);
          if(readString.indexOf('d') >0) myservod.write(n);
        }
         readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Thanks for your help guys. Right now, all I’m wanting to be able to do is control the servos from the serial monitor using the number keys. Then I’ll interface that with the java program I made. As I said earlier, all it does is do the first command I send it. So for example, if I send a ‘1’ then it will move the base servo left 20 degrees. Now if I want to send that command again or any other command it won’t do anything. I hope that sorta cleared things up. Thanks. Oh and by the way, I add the full, slightly updated version of my code so far.

#include <Servo.h>

Servo bases;
Servo armas;
Servo armbs;
Servo armcs;
Servo grippers;

int SizeOfObject = 20;
byte serial;
const int p = 90;
const int r = 20;
const int l = -20;

void setup() {
  bases.attach(2);
  armas.attach(3);
  armbs.attach(4);
  armcs.attach(5);
  grippers.attach(6);

  
  universal(90);
  Serial.begin(9600);
  while (!Serial);
}

void loop() {
}

void universal(int num){
  bases.write(num);
//  armas.write(num);
//  armbs.write(num);
//  armcs.write(num);
//  grippers.write(num);
  delay(num*4);
}
void base(int num){
	if (!check(bases, num)) {
		bases.write(p - num);
		delay(num*4);
	}
}

void arma(int num){
	if (!check(armas, num)) {
		armas.write(p - num);
		delay(num *4);
	}
}
void armb(int num){
	if (!check(armbs, num)) {
		armbs.write(p - num);
		delay(num *4);
	}
}
void armc(int num){
	if (!check(armcs, num)) {
		armcs.write(p - num);
		delay(num *4);
	}
}
void grab(){
  grippers.write(175);
  delay(1000);
  grippers.write(SizeOfObject);
  delay(1000);
}
boolean check(Servo s, int num) {
	if ((s.read() <= 5 && num < 0) || (s.read() >= 175 && num>0))
		return true;
	else
		return false;
}
void serialEvent() {
		serial = Serial.parseInt();

		switch (serial) {
		case 1:base(l);//left arrow
			break;

		case 2:base(r);//right arrow
			break;

		case 3:universal(p);//j
			break;

		case 4:arma(l);//up arrow
			armb(l - 1);
			armc(l - 2);
			break;

		case 5:arma(r);//down arrow
			armb(r - 1);
			armc(r - 2);
			break;

		case 6:arma(l);//a key + up arrow
			break;

		case 7:armb(l);//s key + up arrow
			break;

		case 8:armc(l);//d key + up arrow
			break;

		default:
			break;
		}
}

Right now, all I'm wanting to be able to do is control the servos from the serial monitor using the number keys.

That is probably not happen the way you want with the serial monitor. The enter key needs to be pressed any time anything is to be sent from the serial monitor.

Thanks. Okay, it still doesn't work.

You need to use a "real" terminal emulator program. I use Tera Term.

By the way, with all those delay()'s in it, it will be extremely sluggish to respond to input.

If you use a terminal program that sends a string of bytes as long as the keyboard key is pressed, then the arduino code would probably be fairly simple. The below servo test code does something similar as a servo is incremented one step when a specific character is received.

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

Thanks zoomkat, it works now. But not completely. If I send the same number twice then it won’t do anything. I don’t understand why it does that. Could you please tell me why it does that? Oh and thanks aarg, for the advice. Also, why didn’t my other piece of code work the way this one works. Isn’t it pretty much the same? Thanks.

#include <Servo.h>

Servo bases;
Servo armas;
Servo armbs;
Servo armcs;
Servo grippers;

int SizeOfObject = 20;
int serial;
const int p = 90;
const int r = 20;
const int l = -20;

void setup() {
  bases.attach(2);
  armas.attach(3);
  armbs.attach(4);
  armcs.attach(5);
  grippers.attach(6);

  
  universal(90);
  Serial.begin(9600);
}

void loop() {
	while (Serial.available()) {
		char c = Serial.read();
		String t;
		t += c;
		serial = t.toInt();
		delay(2);
	}
	if (!serial == 0) {
		switch (serial) {
		case 1:base(l);//left arrow
			break;

		case 2:base(r);//right arrow
			break;

		case 3:universal(p);//j
			break;

		case 4:arma(l);//up arrow
			armb(l - 1);
			armc(l - 2);
			break;

		case 5:arma(r);//down arrow
			armb(r - 1);
			armc(r - 2);
			break;

		case 6:arma(l);//a key + up arrow
			break;

		case 7:armb(l);//s key + up arrow
			break;

		case 8:armc(l);//d key + up arrow
			break;

		default:Serial.println(serial);
			break;
		}
	}
	serial = 0;
}

void universal(int num){
  bases.write(num);
//  armas.write(num);
//  armbs.write(num);
//  armcs.write(num);
//  grippers.write(num);
}
void base(int num){
	if (!check(bases, num)) {
		bases.write(p - num);
	}
}

void arma(int num){
	if (!check(armas, num)) {
		armas.write(p - num);
	}
}
void armb(int num){
	if (!check(armbs, num)) {
		armbs.write(p - num);
	}
}
void armc(int num){
	if (!check(armcs, num)) {
		armcs.write(p - num);
	}
}
void grab(){
  grippers.write(175);
  grippers.write(SizeOfObject);
}
boolean check(Servo s, int num) {
	if ((s.read() <= 5 && num < 0) || (s.read() >= 175 && num>0))
		return true;
	else
		return false;
}

If I send the same number twice then it won’t do anything

If you send the same data twice, what do you expect to have happen? The servos will be in some position(s) based on the first set of data. Send the same data, and the servo is, obviously, not going to move. It is already where you now want it to be.

I mean with my code. When I send a number it moves it 20 degrees either way depending on what number I send.

I mean with my code.

This code?

	while (Serial.available()) {
		char c = Serial.read();
		String t;
		t += c;
		serial = t.toInt();
		delay(2);
	}

That code is rubbish. If you send "20", the '2' will arrive. Then, there will be a relatively long pause before the '0' arrives.

Meanwhile, you read the '2', create a new String object, add the '2' to the String, and then convert to an int. A complete waste of resources, since serial will end up equal to '2' - '0', or 2.

Then, you hope that the '0' will have arrived. If it has, you read it, create a new String, add the '0' to it, and then trash the value in serial by storing the 0 there.

What should I do then? Thanks :confused:

quentinthornton:
What should I do then? Thanks :confused:

I'm trying to control a robot arm by using the keys on my computer (using java though serial communication).

Perhaps you should better explain what type of control you want from a keyboard. If you want to type in command positions and send them, that is fairly easy. If you just want to depress a keyboard key and have the arm move in a direction associated with that key (like depressing "u" and having the arm move up until the key is released), then different code would be needed.