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;
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:
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.
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.
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.
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.