[SOLVED] Control 3 Servos via Bluetooth

Hey dudes,

I'm so helpless in my topic. I want to control 3 servos (0-180°) via Bluetooth on an Android mobile. I already get 1 servo worked fine. The Android App works also fine. So the Problem is the Arduino-Code.

Problem with 3 Servos: I need an extra byte, char or int to tell arduino which servo should be controlled. I tried so much ways, but no one worked really fine.

  1. way:
    Send a control Byte (1;2;3;) and after that, sending the servo-position as a Byte. Well, this worked a little bit, but the servo motor does strange things.

Code:

#include <Servo.h>

byte valueByte;      
int value, servo;
Servo servoeins, servozwei, servodrei;    // declare Servo

void setup()
{
  pinMode(servo = 8, OUTPUT);  // pin 13 (on-board LED) as OUTPUT
  pinMode(servo = 9, OUTPUT);
  pinMode(servo = 10, OUTPUT);
  servoeins.attach(8);           // initialize servo to pin 8 
  servozwei.attach(9);
  servodrei.attach(10);
  Serial.begin(9600);       // start serial communication at 9600bps
 
}
 
void loop() {
  if(Serial.available()){   // if data is available to read
   byte command = Serial.read();  //store 1.st Byte as command
    switch(command){        
    valueByte = Serial.read();    //store 2.nd Byte as value
    value = (int) valueByte;      //cast ValueByte into Integer
    case 1:
    servoeins.write(value);       //start Servo with integer value
    delay(10);
    case 2:
    servozwei.write(value);
    delay(10);
    case 3:
    servodrei.write(value);
    delay(10);
    }
  }
}
  1. way:
    Send a 2 Byte message to Arduino, containing a number till 543. So the Arduino checks the value, and sees which servo he shall control. 0...180 he controls servo1, 181...361 he controls servo2, 362...542 he controls servo3. Thats the point why i use a 2Byte message.
    But how can I receive a 2 Byte Message? I tried so many ways (googled examples etc..) but none worked for me.

Does anyone of you guys have a working idea? Im pretty sure that it will work anyway, but how? :smiley:

Thanks a lot!

P.S. Im workin with App Inventor 2. I can choose between 1-Byte-Number, 2-Byte-Number oder 4-Byte-Number.

  pinMode(servo = 8, OUTPUT);  // pin 13 (on-board LED) as OUTPUT
  pinMode(servo = 9, OUTPUT);
  pinMode(servo = 10, OUTPUT);

There is no point in assigning a value to servo there. Stop that crap.

  if(Serial.available()){   // if data is available to read
   byte command = Serial.read();  //store 1.st Byte as command
    switch(command){       
    valueByte = Serial.read();    //store 2.nd Byte as value

Serial.available() returns the number of bytes available to be read, not true or false.

If it says that there is one byte, it is NOT okay to read two.

NOTHING follows a switch statement except cases.

Failing to omit the break statement from a case is a classic mistake.

What is the phone sending? ASCII data or binary data?

Get the bluetooth device off the hardware serial port so you can debug your program. Debug by guess is the worst possible way.

Does anyone of you guys have a working idea? Im pretty sure that it will work anyway, but how?

I don't know if this will fit your situation, but below is dome multiservo control code. The code provides for a servo position code, a servo identifier, and an end of data packet marker.

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

zoomkat you gave me the right input! Now my code works fine. I changed the code to my values and everything is fine. Thank you very much!

Here is the compelte code:

#include <Servo.h>
    
int value;                                // declare an integer named 'value'
Servo servoeins, servozwei, servodrei;    // declare servo1, servo2, servo3
String readString;                        // declare a String named 'readString'

void setup()                     // Setup Code
{
 pinMode(8, OUTPUT);            // initialize pin 8 as Output
 pinMode(9, OUTPUT);            // initialize pin 9 as Output
 pinMode(10, OUTPUT);           // initialize pin 10 as Output
 servoeins.attach(8);           // initialize servo1 to pin 8 
 servozwei.attach(9);           // initialize servo2 to pin 9
 servodrei.attach(10);          // initialize servo3 to pin 10
 Serial.begin(9600);            // start serial communication at 9600bps
} 
void loop() {                      // expects Data like "0a," "180b," or "270c,"
 if(Serial.available()){          // if data is available to read
  char c = Serial.read();         // stores 1.st byte from sent data
  if (c == ','){                  // check if its a ',' - so data comes from mobile
   if (readString.length()>1){    // check if the data is valid
   value = readString.toInt();    // convert the received String to a Number (skips alphabetics)
   if(readString.indexOf('a')>0){ // check if data is according to servo1
   servoeins.write(value);        // start Servo with received value
   delay(10);}                    // time for arduino to control servo to value position
   if(readString.indexOf('b')>0){ // check if data is according to servo2
   servozwei.write(value);        // start Servo with received value
   delay(10);}                    // time for arduino to control servo to value position
   if(readString.indexOf('c')>0){ // check if data is according to servo3
   servodrei.write(value);        // start Servo with received value
   delay(10);}                    // time for arduino to control servo to value position
   readString="";                 // clears String for new input
   }
   }
   else{                          
   readString += c;}              // makes the String readString
   }
   }

Is there a possibility to optimize this process, so the latence gets lower? I think the delay for the servos a low enough, or?

Is there a possibility to optimize this process, so the latence gets lower?

Of course. Quit using Strings to collect a fixed amount of data. Quit using delay() for anything.

Mhmm.. yeah i tried using functions like 'ReadyBytes' but it doesnt work. With 'readBytes' it should be also possible i think?
Is there an example, how to use it?
So i could send a 1-Byte-Number to choose the servo, and after that, the value shall be sent with an 1-Byte-Number.

You know what I mean?

Is there a possibility to optimize this process, so the latence gets lower?

Get rid of the below delays in your code. This delay seems to be a legacy item from the "sweep" servo example code.

delay(10);  // time for arduino to control servo to value position