MIDI sync signal to servo movement

Hi all,

I’m taking a MIDI sync (not sure it’s actually MIDI or just a pulse) from a Korg Volca by using a cut-off headphone lead with one connection to ground and one to a digital pin. That works well and I’m flashing an LED in time with it. It syncs up nicely with a drum beat.

Now I’m trying to twitch a servo in time with it, as I want to play with an acoustic drum thing that syncs to the Volca. The servo matches well, but skips the odd beat - even though the LED doesn’t. I’ve got a short delay in there. Anything else I should try?

Thanks,
Matt

You could try posting the code you're using and some information about the servo and maybe a schematic showing how everything is connected and powered. Give us something to help with!

First guess...your servo is not adequately powered but it could be plenty of other things.

Steve

sparkes:
I’m taking a MIDI sync (not sure it’s actually MIDI or just a pulse) from a Korg Volca by using a cut-off headphone lead with one connection to ground and one to a digital pin.

What sort of Volca are we talking about here?

If it is you have done the mod to get a MIDI output it should be a single byte MIDI message. Otherwise it will be a physical pulse. Like Steve said we need to see your code and wiring.
Have you measured the size of this pulse?
Have you got a resistor in series with your LED?

I have the small 9g servo attached to pin 9, ground and 5v. The input from the Korg Volca Beats is going to ground and pin 7. The LED is the built-in one on the Diecimila. I don’t have a variable power supply yet but I just stripped a USB cord and ran the 5V to the servo, to see if power was the issue, but the behaviour didn’t change. I haven’t measured the size of the pulse from the Volca but the Arduino seems to be picking it up reliably, juding from the LED (it’s obviously not BPM, but a multiple of that, which is fine to deal with later). Here’s the code:

// Volca sync machine

#include <Servo.h>

int volcaPin = 7; // Incoming analogue sync signal
Servo myservo; // Create servo object to control a servo

void setup() {
pinMode(volcaPin, INPUT); // Sets the digital pin 7 as input
myservo.attach(9); // Attaches the servo on pin 9 to the servo object
}

void loop() {
if (digitalRead(volcaPin) == HIGH) { // Flash LED when sync signal detected
digitalWrite(LED_BUILTIN, HIGH);
myservo.write(20); // sets the servo position according to the scaled value
}
else {
digitalWrite(LED_BUILTIN, LOW);
myservo.write(70); // sets the servo position according to the scaled value
delay(15);
}
}

Thanks for that but could you please read this:-
How to use this forum
Because your post is breaking the rules about posting code.

So I see your code is looking at the input pin and from that information it is pulsing the internal LED, so that removes one potential problem.

The other problem I can see is that you have an asymmetry about how long it takes to turn the LED on and how long to turn it off. It is that delay in the turn off case only. So try moving it out of the if then structure.

The problem with what you are doing is there is no way to see the position of the servo.

Also the problem is that the on part of the pulse is short and the off part is long. The way you code works is that as soon as the pulse is seen the servo is told to move, and is told to move repeatedly as long as the pulse is present. Then when the pulse is removed the servo is told to move back, when it might not even have moved very far.

The way to approach this, given that the pulses are too fast anyway, is to detect the edge of the pulse, not the level. There is an example of this in the IDE examples called State Change detector. On each edge move the servo alternatively left and right. This will give the servo the whole time of the pulse to move, and even up the timing.

Thanks for that, and apologies for the infraction - didn’t realise. I had a little read and the edge case argument makes a lot of sense. I’ve come up with this code below based on that, but strangely it seems to be acting exactly as before: LED is regular, servo stutters after every few movements. I thought perhaps it was struggling with the speed of the pulse changes, but if I alter the tempo on the Volca it makes no difference.

// Volca sync machine

#include <Servo.h>

int volcaPin = 7;      // Incoming analogue sync signal
Servo myservo;         // Create servo object to control a servo
int currentSyncState;  // Current state of sync signal
int previousSyncState; // State of sync signal last time we checked

void setup() {
  pinMode(volcaPin, INPUT);  // Sets the digital pin 7 as input
  myservo.attach(9);            // Attaches the servo on pin 9 to the servo object
}

void loop() {
  if (digitalRead(volcaPin) == HIGH) {
    currentSyncState = 1;
  }
  else {
    currentSyncState = 0;
  }
  
  if (currentSyncState != previousSyncState) {
    if (currentSyncState == 1) {
      digitalWrite(LED_BUILTIN, HIGH);             
      myservo.write(0);                            
    }
    else {
      digitalWrite(LED_BUILTIN, LOW);    
      myservo.write(180);                    
    }
  }
  delay(30);
  previousSyncState = currentSyncState;
}

You're now trying to move the servo a full 180 degrees every time. That takes a lot longer than 30ms. Unless your beat rate is really slow you may simply be asking way too much of a cheap hobby servo.

Steve

I've dropped it down to just a few degrees and strangely I'm now getting three twitches of the servo, then a pause, then three twitches, then a pause, etc. The LED is now following the same pattern. Something is awry.

but strangely it seems to be acting exactly as before:

Well that is because you are doing the same thing as you did before.
And that else clause is making things not work.

You are not detecting the edge of the signal you are still looking at the level.

This code:-

if (digitalRead(volcaPin) == HIGH) {
    currentSyncState = 1;
  }
  else {
    currentSyncState = 0;
  }

is the same as saying

currentSyncState = digitalRead(volcaPin);

In other words the "if" part is doing nothing.
The rest of the code operates exactly like before. What you need is to look if the current state is high AND the previous state was low. Then you can do stuff based on a count.

currentRead = digitalRead(vocalPin);
if( currentRead!= previousRead && previousRead == LOW) { // you have found a rising edge
 stateCount ++;
if( stateCount >1) = 0;
// now do stuff based on the state count
if(stateCount == 0) {
// turn on LED and move servo
}
else {
// turn off LED and move servo back
}
previousRead = currentRead;

Note, no delay that is screwing you up as well.

That’s just to update the current state variable - there’s a section of code under that which compares that to the previously read state and acts accordingly.

Are you saying that you posted only a part of your code?
Please don’t do this because a lot of time can be wasted and errors are often in the code you don’t post.

No, it's there above.

Edit: Copying here for clarity...

 if (currentSyncState != previousSyncState) {
   if (currentSyncState == 1) {
     digitalWrite(LED_BUILTIN, HIGH);             
     myservo.write(0);                           
   }
   else {
     digitalWrite(LED_BUILTIN, LOW);   
     myservo.write(180);                   
   }
 }
 delay(30);
 previousSyncState = currentSyncState;

No, it's there above.

No it is not. Your code is triggering off both the rising and falling edge resulting in exactly the same behaviour as you had in the original code. That is the state of the led being turned on and the servo moving only lasts for the duration of the pulse. You need to give each state equal times which is what I am attempting to show you how to do.