Commanding servos with audio wave form.

wow, Grumpy Mike - you certainly have a 'personality' - it's not super nice, it made me feel a little shitty actually, maybe that's my thin skin.

To answer and reply your questions and statements:

Yes, I've used MIDI

'You don't use mod wheel at all' - you don't have to use mod wheel, but you can use mod wheel (or pitch if you want more bit depth)

'you put the messages in where you want them in the score' I'm aware of that, I was referring to something else, maybe I wasn't clear enough

You omit my question marks in your quotes - I made it clear, at least I thought I made it clear that I was just shooting the breeze, thinking out loud - questioning things, myself included.

Context is key.

Ok, so I had to look up PPM - turns out it's something I knew about but didn't know the term for - but I don't see why PPM excludes PWM, it's sort of sideways to the matter at hand, or kind of extension of capability ?

(I wonder how you're going to able to handle me saying things like 'sideways' and 'kinda' but yeah whatevs)

PPM I thought was how transmitters and receivers for want of a better term multiplexed multiple servo channels into one signal (kinda like parallel to serial if you like).

But servos themselves - and I would have thought for the case of an arduino output to a single servo - use plain ol' PWM, and yes I thought it was 50Hz ... you're saying it isn't ?

Could have sworn when I changed the .h file for some servo library recently I was changing a period or something that meant I went from 50Hz to 200Hz (for digitals) - would have gone higher if I could.

Absolute rubbish ? really ?

When I said "sending a pos command at 'whatever' Hz doesn't seem to hurt it though.."
I meant within arduino code - if you have a loop running at 13KHz and within that loop you are sending a pos command to a servo, you're saying 'go to pos X' 13,000 times a second. What I'm saying is that even if the servo is updating at whatever Hz you think it is (but whatever it is it's much less than 13KHz), then there doesn't seem to be any hurt done to the servo.

I wasn't saying sending 333Hz commands to a cheap analog will be fine. But I can see how if you wanted you could have read it that way, but there were other possible interpretations.

I suggest before saying rubbish this and rubbish that, you might want to consider this.

I'm guessing with your name, you dont care what other people think - I could be wrong (?) - but, just, I dunno, I'm not saying don't call people out when they're wrong, but just maybe think about being...

heh heh

being cool

:grin:

forgot to address one other part:

By 'clock' I was referring to - actually questioning - if the digital protocol was synchronous or asynchronous - that is, the signal itself, not the information in the signal.

rah rah 'irrelevant' etc.

::slight_smile:

Guys no need to get angry over this :slight_smile:

Grumpy Mike, I'm having a bit of trouble with my previous code and the new one. Basically I'm trying to call a specific function using MIDI.

What's the best way to deal with it, knowing the fact that I have about 30 functions.

  • One different note by function? E.g note 60 for function 1, note 48 for function 2 and so forth?
  • The same note but with different velocity?

I'd go for option 1 which is more convenient and more distinctive, can you confirm?

Here's the code that is successfully moving one or two servos if I type note 60, the angle change with the velocity. (Ignore the solenoid part)

#include <VarSpeedServo.h> 

VarSpeedServo myServo[2]; 
int servoPin[]={7,8};
int sol1Pin = 9;
 
byte incomingByte;
byte note;
byte velocity;
int chan = 1;  //specify what MIDI channel we're listing to
 
int action=2; //0 =note off ; 1=note on ; 2= null
const int lowNote = 60; //what's the first note?  36 is C1 in Ableton
 
//setup: declaring inputs and outputs and begin serial
void setup() {
 
  Serial.begin(38400);  
 
  //setup our outputs
  for(int i= 0; i<2; i++){
  myServo[i].attach(servoPin[i]);
  myServo[i].write(90);
  }
 
  pinMode(sol1Pin, OUTPUT);
}
 
//loop: wait for serial data, and interpret the message
void loop () {
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
 
    // wait for as status-byte, channel 1, note on or off
    if (incomingByte== 143+chan){ // note on message starting starting
      action=1;
    }else if (incomingByte== 127+chan){ // note off message starting
      action=0;
 
    }else if ( (action==0)&&(note==0) ){ // if we received a "note off", we wait for which note (databyte)
      note=incomingByte;
      triggerSolenoid(note, velocity);
      note=0;
      velocity=0;
      action=2;
    }else if ( (action==1)&&(note==0) ){ // if we received a "note on", we wait for the note (databyte)
      note=incomingByte;
    }else if ( (action==1)&&(note!=0) ){ // ...and then the velocity
      velocity=incomingByte;
      triggerSolenoid(note, velocity);
      moveServo(note, velocity);
      note=0;
      velocity=0;
      action=0;
    }else{
      //nada
    }
  }
}
 
void moveServo(byte note, byte velocity){
//write an angle based on velocity to our servo
 
switch(note){
   case lowNote:  //if it's note 36
   {int angle1 = int(map(velocity, 0,127, 0,180)); //map velocity to angle
   myServo[0].write(angle1); //write our angle to the servo
   break;
   }
   case lowNote+1:{ //if it's note 37
   int angle2 = int(map(velocity, 0,127, 0,180)); //map velocity to angle
   myServo[1].write(angle2); //write our angle to the servo
   break;
   }
}
 
 }
 
void triggerSolenoid(byte note, byte velocity){
 if(note == lowNote+2){ //if it's note 38
      int value=LOW; 
  if (velocity >10){ //if the velocity is over 10 turn the solenoid on
      value=HIGH;
  }else{  //other wise turn it off
   value=LOW;
  }
   digitalWrite(sol1Pin, value);  //write our value to the solenoid
 
   }
 
}

Right now, by typing note 60, the servo in pin 7 is moving. If I change the velocity it changes the angle. GREAT.

However I'm gonna try to mix this piece of code with my old one.

Here's a piece of the beginning of my actual piece of code controlling 8 servos and 1 solenoid with a PS2 remote controller.

#include <VarSpeedServo.h> 
#include <servo.h> 

//right now, the library does NOT support hot pluggable controllers, meaning 
//you must always either restart your Arduino after you conect the controller, 
//or call config_gamepad(pins) again after connecting the controller.
int error = 0; 
byte type = 0;
byte vibrate = 0;
byte boucle= 0;   // for boucle

VarSpeedServo servoI1;   // create servo object to control a servo that inflate 1
VarSpeedServo servoD1;   // create servo object to control a servo that deflate 1

VarSpeedServo servoI2;   // create servo object to control a servo that Inflate 2
VarSpeedServo servoD2;   // create servo object to control a servo that Deflate 2

VarSpeedServo servoI3;   // create servo object to control a servo that Inflate 3
VarSpeedServo servoD3;   // create servo object to control a servo that Deflate 3

VarSpeedServo servoI4;   // create servo object to control a servo that Inflate 4
VarSpeedServo servoD4;   // create servo object to control a servo that Deflate 4
 
int Rollfast = 0;  //Value read off the PS2 Right Stick up/down.
int Pitchfast = 0;  //Value read off the PS2 Right Stick left/right
int Rollslow = 0; //Value read off the PS2 Left Stick up/down
int Pitchslow = 0; // Value read off the PS2 Left Stick left/right 

// the loop function runs over and over again forever

void setup(){
 Serial.begin(57600);
 // initialize digital pin 13 as an output.
  pinMode(31, OUTPUT);
  digitalWrite (31, LOW);
 //CHANGES for v1.6 HERE!!! **************PAY ATTENTION*************
  
 error = ps2x.config_gamepad(13,11,10,12, true, true);   //setup pins and settings:  GamePad(clock, command, attention, data, Pressures?, Rumble?) check for error

  servoI1.attach(22);   // Set I1 servo to digital pin 22
  servoD1.attach(23);  //  Set D1 servo to digital pin 23
  servoI2.attach(24);   // Set I2 servo to digital pin 24
  servoD2.attach(25);   // Set D2 servo to digital pin 25
  servoI3.attach(26);   // Set I1 servo to digital pin 26
  servoD3.attach(27);   // Set D2 servo to digital pin 27
  servoI4.attach(28);   // Set I2 servo to digital pin 28
  servoD4.attach(29);   // Set I2 servo to digital pin 29
}

void infslow1() {    // Monte 1 lentement
  servoI1.write(45, 5, true); 
  servoI1.write(32, 0, true); 
}

void infslow2() {    // Monte 2 lentement
  servoI2.write(45, 5, true); 
  servoI2.write(32, 0, true); 
}

void infslow3() {    // Monte 3 lentement
  servoI3.write(45, 5, true); 
  servoI3.write(32, 0, true); 
}

void infslow4() {    // Monte 4 lentement
  servoI4.write(45, 5, true); 
  servoI4.write(32, 0, true); 
}

void infslow12() {    // Monte 1 et 2 lentement
  servoI1.write(45, 5); 
  servoI2.write(45, 5, true);
  servoI1.write(32, 0);
  servoI2.write(32, 0, true);  
}

void infslow43() {    // Monte 4 et 3 lentement
  servoI4.write(45, 5); 
  servoI3.write(45, 5, true);
  servoI4.write(32, 0);
  servoI3.write(32, 0, true);  
}

void infslow14() {    // Monte 1 et 4 lentement
  servoI1.write(45, 5); 
  servoI4.write(45, 5, true);
  servoI1.write(32, 0);
  servoI4.write(32, 0, true);  
}

void infslow23() {    // Monte 2 et 3 lentement
  servoI2.write(45, 5); 
  servoI3.write(45, 5, true);
  servoI2.write(32, 0);
  servoI3.write(32, 0, true);  
}

void infslow1234 () { // Monte 1 2 3 4 lentement
  servoI1.write(47, 3);
  servoI2.write(47, 3);
  servoI3.write(47, 3);
  servoI4.write(47, 3, true);
  delay (4500); 
  servoI1.write(32, 3); 
  servoI2.write(32, 3);
  servoI3.write(32, 3);
  servoI4.write(32, 3, true);
}

void vibrationslow () {
        digitalWrite (31, LOW);
   servoI1.write(60, 0);
   servoI2.write(60, 0);
   servoI3.write(60, 0);
   servoI4.write(60, 0, true);
   servoD1.write(50, 0);
   servoD2.write(50, 0);
   servoD3.write(50, 0);
   servoD4.write(50, 0, true);
   delay (100);
    
    for (boucle=0;boucle<10;boucle++)
        {
        boucle= 2; 
         digitalWrite (31, HIGH); 
         delay(100);
         digitalWrite (31, LOW); 
         delay(100);
         digitalWrite (31, HIGH); 
         delay(100);
         digitalWrite (31, LOW); 
         delay(100); 
         digitalWrite (31, HIGH); 
         delay(100);
         digitalWrite (31, LOW); 
         delay(100);
         ps2x.read_gamepad();          //read controller 
        if(ps2x.ButtonReleased(PSB_L3))
           boucle=11;  
        }
  delay (100);  
  servoI1.write(32, 0); 
  servoI2.write(32, 0);
  servoI3.write(32, 0);
  servoI4.write(32, 0, true);
  delay (700);
  digitalWrite (31, LOW);
  servoD1.write(32, 0); 
  servoD2.write(32, 0);
  servoD3.write(32, 0);
  servoD4.write(32, 0, true);
}


//and it goes on and on till the void loop.

Part 2

Here's what i'm trying to achieve:

  1. I d'like to mix my code with the MIDI one so that for example, when I hit note 60 on garageband It'll call infslow1. If I hit note 58 it'll call infslow2 and so forth. That's what I'm currently trying to do and I'm struggling a bit.

I'm sure that it is possible, even though I have no idea how to implement it :blush:

  1. This seems much harder to explain/do but I'll try my best. So far I'm controlling my 8 servos (and 1 solenoid) with a PS2 controller. Each button pressed is calling up a function as explained above.
    and with 1) I'll be able to call a function with a MIDI note. That's for the easy functions.

There's another function i'm using which is below:

void vibrationslow () {
        digitalWrite (31, LOW);
   servoI1.write(60, 0);
   servoI2.write(60, 0);
   servoI3.write(60, 0);
   servoI4.write(60, 0, true);
   servoD1.write(50, 0);
   servoD2.write(50, 0);
   servoD3.write(50, 0);
   servoD4.write(50, 0, true);
   delay (100);
    
    for (boucle=0;boucle<10;boucle++)
        {
        boucle= 2;
         digitalWrite (31, HIGH); 
         delay(100); 
         digitalWrite (31, LOW); 
         delay(100);
         digitalWrite (31, HIGH); 
         delay(100);
         digitalWrite (31, LOW); 
         delay(100);
         digitalWrite (31, HIGH); 
         delay(100);
         digitalWrite (31, LOW); 
         delay(100);
         ps2x.read_gamepad();          //read controller 
        if(ps2x.ButtonReleased(PSB_L3))
           boucle=11;  
        }
  delay (100);  
  servoI1.write(32, 0); 
  servoI2.write(32, 0);
  servoI3.write(32, 0);
  servoI4.write(32, 0, true);
  delay (700);
  digitalWrite (31, LOW);
  servoD1.write(32, 0); 
  servoD2.write(32, 0);
  servoD3.write(32, 0);
  servoD4.write(32, 0, true);
}

Basically this function, when called, is closing 31 (so that water doesn't get through), moving servos I1, I2, I3 and I4 to position 60, moving servos D1, D2, D3 and D4 to position 50. Then the solenoid is vibration at 100ms (LOW,HIGH,LOW,HIGH and so forth) till I release the L3 button. Then servo I1,I2,I3,I4 are going back to their initial position, so does D1,D2,D3,D4 and then the solenoid goes into LOW mode. That's my function and it works very well with the PS2 controller.

as for 1) each midi note will call a specific function, for 2) I d'like also to hit a MIDI note that calls up the function above BUT the solenoid (thus the boucle) will keep vibrating if the note hasn't been turned OFF. What I mean is that for 1) I'll hit note 60 for function infslow1, it'll call up the function once that will do it's things and that is all.

for 2) I d'like to hit note 45 and if the duration of the note 45 on the MIDI software is 10 second then the function will be active for 10 seconds and thus the solenoid will be vibrating for 10 seconds till the note is being turned off.

Do you have any ideas on how to implement 1) and/or 2)?

I know I'm asking a lot but if you could try to at least explain by pseudo code so that I can try to mix up my code and the MIDI one that would help a lot. As you can see, I'm far far far from being a developer.

Basically I'm trying to call a specific function using MIDI. .... knowing the fact that I have about 30 functions. ...... One different note by function? E.g note 60 for function 1, note 48 for function 2 and so forth?

It is best if you do not think like this, it will only lead to long and turgid code. You must isolate what you want to do differently and pass data describing that difference to the one function.
When you find yourself writing almost the same thing over and over then you are doing it wrong. This is your function followed by how you should write it.

// As you have it
void moveServo(byte note, byte velocity){
//write an angle based on velocity to our servo
 
switch(note){
   case lowNote:  //if it's note 36
   {int angle1 = int(map(velocity, 0,127, 0,180)); //map velocity to angle
   myServo[0].write(angle1); //write our angle to the servo
   break;
   }
   case lowNote+1:{ //if it's note 37
   int angle2 = int(map(velocity, 0,127, 0,180)); //map velocity to angle
   myServo[1].write(angle2); //write our angle to the servo
   break;
   }
}
 
 }
 
 // you can replace all the above and more with this:-
 void moveServo(byte note, byte velocity){
//write an angle based on velocity to our servo 
   int arrayPos = note - lowNote:  //subtract lownote to get the first servo
   int angle = int(map(velocity, 0,127, 0,180)); //map velocity to angle
   myServo[arrayPos].write(angle); //write our angle to the serv 
 }

) I d'like to mix my code with the MIDI one so that for example, when I hit note 60 on garageband It'll call infslow1. If I hit note 58 it'll call infslow2 and so forth. That's what I'm currently trying to do and I'm struggling a bit.

Again if your functions are simply as you put them:-

void infslow1() {    // Monte 1 lentement
  servoI1.write(45, 5, true); 
  servoI1.write(32, 0, true); 
}

void infslow2() {    // Monte 2 lentement
  servoI2.write(45, 5, true); 
  servoI2.write(32, 0, true); 
}

You have your servo identifiers in an array and simply set the array number.

There's another function i'm using which is below:

That contains the delay call. This stops any further processing until that delay has completed, therefore you can not receive any other MIDI information while that function is being executed. This then stops you having two of these functions working at the same time or anything else working.

The way you get round this is by using a technique called a state machine. A simple example of this is in the blink without delay in the Arduino IDE. For more discussion of this see:-
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html
Or Robin2's several things at once
http://forum.arduino.cc/index.php?topic=223286.0
This is advanced programming and you will have to take some time to figure out what is going on. So basically when you have your solenoid will be vibrating you will be calling a function based on when it is time to change something like the direction. When the note off message arrives you reset a variable or flag that will stop the function being called.
As I say this is advanced programming and is not what you originally asked for, this is feature creep and I would wait until you get the basics going before considering this extension.

Hi Grumpy Mike thanks for your answer,

It is best if you do not think like this, it will only lead to long and turgid code. You must isolate what you want to do differently and pass data describing that difference to the one function.
When you find yourself writing almost the same thing over and over then you are doing it wrong.

Very true, however when you're trying to make a group of multiple servos do a specific precise movement which will always be defined in advance. Isn't it easier to just call a function once rather than controlling each servo one by one? By that I mean that my 30 functions are doing 30 movements (which is the full need of my application, no more no less) each function is doing one movement per servo. Then calling 30 functions with 30 notes would be easier than calling one note per servo per movement.
For one function, instead of hitting one note I would have to hit 8 notes to make those 8 servos do the movement of the same function. I'm not sure I was clear enough ...

In a sense, I've understood your piece of code, here's what I've done, although it doesn't seems to be working.

#include <VarSpeedServo.h> 

VarSpeedServo servoI1;
VarSpeedServo servoI2;

void infslow1() {    // Monte 1 lentement
  servoI1.write(45, 5, true); 
  servoI1.write(32, 0, true); 
}

void infslow2() {    // Monte 2 lentement
  servoI2.write(45, 5, true); 
  servoI2.write(32, 0, true); 
}
 
byte incomingByte;
byte note;
byte velocity;
int chan = 1;  //specify what MIDI channel we're listing to

const int lowNote = 60; //what's the first note?  36 is C1 in Ableton
 
//setup: declaring inputs and outputs and begin serial
void setup() {
 
  Serial.begin(38400); 
  
}
 
//loop: wait for serial data, and interpret the message
void loop () {
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
  }
}
 
 void moveServo(byte note, byte velocity){
//write an angle based on velocity to our servo 
   int arrayPos = note - lowNote;  //subtract lownote to get the first servo
   int angle = int(map(velocity, 0,127, 0,180)); //map velocity to angle
   myServo[arrayPos].write(angle); //write our angle to the servo
 }

It is not working as I haven't declared myServo in that scope which is logical but should it be myServo[arrayPos].write(angle) with myServo being the name of each servos (servoI1, I2, I3 and so forth) or the name of my function?

The way you get round this is by using a technique called a state machine. A simple example of this is in the blink without delay in the Arduino IDE. For more discussion of this see:-

Very true and I read everything (very interesting btw) I'm aware of all that but the application that I'm using it for doesn't allow me to do multiple task at the same time for security reasons. Therefore delays seems a good things to use to make sure that when one function is being called, no others actions can be made. Therefore, is there a way to synchronize delay with note duration within a function in an easy manner?

Then calling 30 functions with 30 notes would be easier than calling one note per servo per movement.

But that was not what your code was doing. You need to be clear in your mind what you want to do. Then you have to communicate that. I can not understand that requirement with your code.
Instead of writing 30 functions that are all the same except for the servo they use then you only need one function that can work out what servo to use depending on a variable you pass it. In your case the servo to move could be calculated from the note number instead of a turgid checking each variable and a calling of a near identical function.

hould it be myServo[arrayPos].write(angle)

Yes

with myServo being the name of each servos

No.
The array index becomes the name of your servo, it is a way of assigning a variable name.

but the application that I'm using it for doesn't allow me to do multiple task at the same time for security reasons.

That makes no sense at all and does not affect what the arduino does.