run servo via servo array (position in array called via serial port)

Hi, i run my servos via an array. It works good. The array is called 'Servos' and have and slots. In my for loop i can run a servo by

Servos[1].write(pos);

or

char vals = 1;
Servos[vals].write(pos);

but my whole program is talking over serial with processing. Processing sends a byte which is stored in 'val'. So if i send '11' from processing char 'type' = 1' and char 'val' = '1'. But when trying to run the servo array with 'val' the servo doesent run, even if val=1. What is going on here? There are probably a lot of other problems in my code some might be related to this problem and some not, so bare with mig :slight_smile:

#include <Servo.h>

const int NoServos = 8;                 // number of servos in legs
Servo Servos[NoServos];                // Define servo array
int ServosPins[NoServos] =            // Servo pins, starting at servo0
{
  2,3,4,5,6,7,8,9};

long previousMillis = 0;       // will store last time LED was updated
long interval = 50;          // interval at which to blink (milliseconds)
boolean readSerials = true;
boolean isFunctionDone=false;

char val;                     // Data received from the serial port
char vals = 1;                     // Data received from the serial port

char type;                     // Data received from the serial port
int pos = 0;                   // Set servo to 0
char myservo;

int solenoid = 13; 


void setup() {

  Serial.begin(9600);
  for (int thisServo = 1; thisServo < NoServos; thisServo++) 
  {
    Servos[thisServo].attach(ServosPins[thisServo]);

  }
  pinMode(solenoid, OUTPUT); 
  establishContact();

}

void loop()
{
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
    updateSerialRead();
  }
}

void updateSerialRead(){
  if (Serial.available() > 0 ) { // If data is available to read,
    type = Serial.read(); // read it and store it in value
    val = Serial.read(); // read it and store it in value
    if (val > '0' && type > '0'){
      decideType();
      readSerials=false;
    }
  }
  else{
    Serial.println("STANDBY");
  }
}

void decideType(){
  if(type == '1'){
    type1();
  }
}

void type1(){
  if (type == '1') 
  { 
     
    for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
    {     
      Servos[val].write(pos);
      delay(15);                       // waits 15ms for the servo to reach the position 
    } 
    for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
    {    
     
      Servos[val].write(pos);          // tell servo to go to position in variable 'pos' 
      delay(15);     // waits 15ms for the servo to reach the position 
      isFunctionDone=true;
    }
    if (isFunctionDone=true){
      functionDone();
    }  
  }
}
void functionDone(){
  Serial.println("666");
  isFunctionDone=false;
}
void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("A");   // send a capital A
    delay(300);
  }
}
for (int thisServo = 1; thisServo < NoServos; thisServo++)

What happens to servo zero?

void decideType(){
  if(type == '1'){
    type1();
  }
}

void type1(){
  if (type == '1')

You already know type is 1 before you call type1(), so why test it again?

I don't understand why you need to receive two bytes from the serial port when you only have 8 servos?

...R

Errm,
AWOL, servo zero was left out. its a mistake made by me. Ill correct it. I dont have any good answer to why testing if 'type' is true twice, just a mistake in my mind!

Robin2
in the end ill have 24 servos divided on 4 types. thats why the first byte = type and the second bytes = val.

  if (Serial.available() > 0 ) { // If data is available to read,
    type = Serial.read(); // read it and store it in value
    val = Serial.read(); // read it and store it in value

If there is at least one byte to read, read them both. I'd ask how that's working for you, but I already know.

PaulS:
If there is at least one byte to read, read them both. I'd ask how that's working for you, but I already know.

Paul, what you are writing is ringing a bell in my head. it seems obvious but still not…
Am i only reading the first byte?
Im picturing something like this.

  if (Serial.available() == 2 ) { // If there's 2 bytes to read,
    type = Serial.read(); // store the first byte in type (dont know how)
    val = Serial.read(); // store the second byte in val  (dont know how)

Am I thinking right or going in circles?

Am I thinking right or going in circles?

Not exactly either one.

  if (Serial.available() >= 2 ) { // If there's at least 2 bytes to read,

Are you trying to send the servos different command positions for each servo?

Why can't the PC figure out the types and just send a value for the relevant servo?
24 is still well within the 26 ascii text characters.

...R

Am I thinking right or going in circles?

Not exactly either one.

  if (Serial.available() >= 2 ) { // If there's at least 2 bytes to read,

[/quote]

I get it. But do i need to define so that the first byte = type and the second = val?

With the minor changes i made nothing changed.

zoomkat

I will have '4 servo' groups/types, each group/type will have a different command.

Robin2

ill have 24 servos and 6 solenoids.
I think ill need at least 35 outputs

#include <Servo.h>

const int NoServos = 8;                 // number of servos in legs
Servo Servos[NoServos];                // Define servo array
int ServosPins[NoServos] =            // Servo pins, starting at servo0
{
  2,3,4,5,6,7,8,9};

long previousMillis = 0;       // will store last time LED was updated
long interval = 50;          // interval at which to blink (milliseconds)
boolean readSerials = true;
boolean isFunctionDone=false;

char val;                     // Data received from the serial port
char type;                     // Data received from the serial port
int pos = 0;                   // Set servo to 0

int solenoid = 13; 


void setup() {

  Serial.begin(9600);
  for (int thisServo = 1; thisServo < NoServos; thisServo++) 
  {
    Servos[thisServo].attach(ServosPins[thisServo]);

  }
  pinMode(solenoid, OUTPUT); 
  establishContact();

}

void loop()
{
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
    updateSerialRead();
  }
}

void updateSerialRead(){
  if (Serial.available() >= 2 ) { // If data is available to read,
    type = Serial.read(); // read it and store it in value
    val = Serial.read(); // read it and store it in value
    if (val > '0' && type > '0'){
      decideType();
      readSerials=false;
    }
  }
  else{
    Serial.println("STANDBY");
  }
}

void decideType(){
  if(type == '1'){
    type1();
  }
}

void type1(){
    for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
    {     
      Servos[val].write(pos);
      delay(15);                       // waits 15ms for the servo to reach the position 
    } 
    for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
    {    
      Servos[val].write(pos);          // tell servo to go to position in variable 'pos' 
      delay(15);     // waits 15ms for the servo to reach the position 
      isFunctionDone=true;
    }
    if (isFunctionDone=true){
      functionDone();
    }  
}
void functionDone(){
  Serial.println("666");
  isFunctionDone=false;
}
void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("A");   // send a capital A
    delay(300);
  }
}

chrille_dill:
I get it. But do i need to define so that the first byte = type and the second = val?

If the bytes are always in the same order you can infer which is which

I think ill need at least 35 outputs

The upper and lower case letters give you 62 options counting the characters in between.

Edit to add ...

I have had a look at your code and I can't figure out what you are trying to do.

What is the purpose of the function establishContact() ? Why not a simple "Serial.println("I'm ready");"

What is the purpose of "readSerials=false;" - it isn't used anywhere.

What is the purpose of "type"? - it isn't effectively used anywhere
Val seems to select the servo - why not call it servoID to make it more obvious?

The function "functionDone()" doesn't seem very useful.

...R

Robin2:

chrille_dill:
I get it. But do i need to define so that the first byte = type and the second = val?

If the bytes are always in the same order you can infer which is which

I think ill need at least 35 outputs

The upper and lower case letters give you 62 options counting the characters in between.

Edit to add ...

I have had a look at your code and I can't figure out what you are trying to do.

What is the purpose of the function establishContact() ? Why not a simple "Serial.println("I'm ready");"

What is the purpose of "readSerials=false;" - it isn't used anywhere.

What is the purpose of "type"? - it isn't effectively used anywhere
Val seems to select the servo - why not call it servoID to make it more obvious?

The function "functionDone()" doesn't seem very useful.

...R

So you insist that i should use only ONE variable? The reason i use 'type' is because i wanted 5 functions, type1, type2, type3…
Each type contain a different servo setting. I thought it was more simple to have multiple types, and the solenoids wont be controlled in the same way as the servos. The solenoids will be in type5, and will be controlled by HIGH / LOW.

I still don understand why my code doesnt work, where does everything go wrong?

establishContact & functionDone communicates with processing which sends commands to a .PHP-file.

It looks like you're sending ascii characters in the range '1' to '8' to be used to populate val. Then you use val as an index into your servo array. Character '1' is decimal 49 though, so you're addressing memory far off the end of your array, hence the failure you see. You'll need to subtract '0' from it:

      val = Serial.read();	// read it and store it in value
      val=val-'0';

Robin 2 — i now updated val to motorID and type to typeID for a better overview.

wildbill:
It looks like you're sending ascii characters in the range '1' to '8' to be used to populate val. Then you use val as an index into your servo array. Character '1' is decimal 49 though, so you're addressing memory far off the end of your array, hence the failure you see. You'll need to subtract '0' from it:

i tried your suggestion, but it still doesnt position the servo. the subtraction didnt change anything.
In 'void typeID1(){' i print the value of 'motorID' which is printing it correct (1) but the servo doesnt move.
Again, if i define
'motorID = 1'
the servo moves, but when
motorID = Serial.read();
it doesnt move. but it prints '1' in serial print.

Updated code

#include <Servo.h>

const int NoServos = 8;                 // number of servos in legs
Servo Servos[NoServos];                 // Define servo array
int ServosPins[NoServos] =              // Servo pins, starting at servo0
{
  2,3,4,5,6,7,8,9};

long previousMillis = 0;               
long interval = 50;                    
boolean isFunctionDone=false;
                                    

char motorID;                         // Data received from the serial port
char typeID;                            // Data received from the serial port
int pos = 0;                         // Set servo to 0

int solenoid = 13; 


void setup() {

  Serial.begin(9600);
  for (int thisServo = 1; thisServo < NoServos; thisServo++) 
  {
    Servos[thisServo].attach(ServosPins[thisServo]);

  }
  pinMode(solenoid, OUTPUT); 
  establishContact();

}

void loop()
{
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    updateSerialRead();
  }
}

void updateSerialRead(){
  if (Serial.available() >= 2 ) { // If data is available to read,
    typeID = Serial.read(); // read it and store it in value
    motorID = Serial.read(); // read it and store it in value
    if (motorID > '0' && typeID > '0'){
      motorID=motorID-'0';
      motorType();

    }
  }
  else{
    Serial.println("STANDBY");
  }
}

void motorType(){
   
  if(typeID == '1'){
    typeID1();
  }
}

void typeID1(){
  Serial.println(typeID);
    for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
    {     
      Servos[motorID].write(pos);
      delay(15);                       // waits 15ms for the servo to reach the position 
    } 
    for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
    {    
      Servos[motorID].write(pos);          // tell servo to go to position in variable 'pos' 
      delay(15);     // waits 15ms for the servo to reach the position 
      isFunctionDone=true;
    }
    if (isFunctionDone=true){
      functionDone();
    }  
}
void functionDone(){
  Serial.println("666");
  isFunctionDone=false;
}
void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("A");   // send a capital A
    delay(300);
  }
}

Try making MotorId an int (just to eliminate possible confusion on the print) and print it before you use it in Type1.

wildbill:
Try making MotorId an int (just to eliminate possible confusion on the print) and print it before you use it in Type1.

:)! Thank you. it works, not 100% with the serial communication yet!

I have 1 more question. Instead of running the function motorType(); can i skip it and say

motorType() + typeID; // if typeID = 1 this would start 'void typeID1();'
So ill call all the motorType functions via the typeID variable.

    if (motorID > '0' && typeID > '0'){
      motorID=motorID-'0';
      motorType();
    }
void motorType(){
   
  if(typeID == '1'){
    typeID1();
  }
}

You can't create the name of a function on the fly. Those references are set by the compiler. There are complex ways to get the same effect but it would be much simpler just to pass a parameter such as motorType(typeID)

I sort-of understand your intended use of types now, but I can't help feeling there should be a simpler way to do it. Can you describe the sort of things that each different type is intended to achieve?

...R