MIDI triggered motor control...

eddevane

Member
Hello all,

I'm posting this after hours of trying various things that don't quite work, I'm sure the answer is staring me in the face but so far not revealing itself.

Here's what I have: a linear actuator (car door motor) connected to a drum stick that creates a powerful mechanical drum beater. I have a control box with a teensy lc and L293d drivers. My plan was to use just the note on messages to trigger the following series of actions:

turn motors on in forward direction for 150ms
brake for 10ms
turn motors on in reverse direction for 150ms
brake for 10ms

...using millis timers. I can get one of these actions to happen, i.e. simply getting the motor to go in one direction or other based on note on and off messages, but not the sequence. Here's my code, please tell me what I'm doing wrong!
Code:
#include <Bounce.h>
int pot[4] = {A0, A1, A2, A3};
int potSwitch[4] = {18, 19, 7, 1};
int gateInput[4] = {2, 13, 22, 23};

const int motorA[4] = {3, 5, 9, 20};
const int motorB[4] = {4, 6, 10, 21};
//usbMIDI.setHandleNoteOn(myNoteOn);
static unsigned int motorState = 1;
int on = 1;
int off = 0;
int motorOnOff;
unsigned long currentMillis;
unsigned long previousMillis;
//int waitTime[4] = {150, 10, 150, 10};
int onTime = 150;
int offTime = 10;
int forwards = 0;
int backwards = 1;
int count;
bool latch = true;
void setup() {
  Serial.begin(115200);
  usbMIDI.setHandleNoteOn(myNoteOn);
  usbMIDI.setHandleNoteOff(myNoteOff);
  //  usbMIDI.setHandleControlChange(myControlChange);

  for (int i = 0; i < 4; i++) {
    pinMode(potSwitch[i], INPUT_PULLUP);
    pinMode(gateInput[i], INPUT_PULLUP);
    pinMode(motorA[i], OUTPUT);
    pinMode(motorB[i], OUTPUT);
  }
  Serial.begin(115200);

}
void loop() {
  if (digitalRead(potSwitch[0]) == HIGH) {
    Serial.println("off");
    motorOnOff = off;
    delay(1);
    stopMotor[0];
    // motorOnOff = off;
  } else {
    motorOnOff = on;
  }
  usbMIDI.read();

}

void myNoteOn(byte channel, byte note, byte velocity) {

  if (note == 60) {//C3
    motorRoutine(0, on);

  }
  if (note == 61) {//C3
    motorRoutine(1, on);
  }
  if (note == 62) {//C3
    motorRoutine(2, on);
  }
  if (note == 63) {//C3
    motorRoutine(3, on);
  }
}


void myNoteOff(byte channel, byte note, byte velocity) {

  if (note == 60) {//C3
    motorRoutine(0, off);

  }
  if (note == 61) {//C3
    motorRoutine(1, off);
  }
  if (note == 62) {//C3
    motorRoutine(2, off);
  }
  if (note == 63) {//C3
    motorRoutine(3, off);
  }
}

void motorRoutine(int whichMotor , int direction) {

  if  (motorOnOff == on && direction == on) {
    //Serial.println("made it this far");
    currentMillis = millis();
    static uint32_t waitTime;
    static bool motorOn;
    static bool motorDirection;

    if (currentMillis - previousMillis >= onTime) {//note on triggers forward direction for 150ms
      previousMillis = currentMillis;
      movement(whichMotor, forwards);
      latch = false;
    }
  }

  if (latch == false) {
    Serial.println("stop phase");
    //if (currentMillis - previousMillis >= offTime) {
      stopMotor(whichMotor);
      latch = true;

   // }
  }
  if  (motorOnOff == on && direction == off) {//note off triggers reverse direction for 150ms
    currentMillis = millis();

    if (currentMillis - previousMillis >= onTime) {
      previousMillis = currentMillis;
      movement(whichMotor, backwards);
      latch = false;
    }
  }
}
void stopMotor(int whichMotor) {
  Serial.println("stop phase");
  digitalWrite(motorA[whichMotor], LOW);
  digitalWrite(motorB[whichMotor], LOW);
}

void movement(int whichMotor, int motorDirection) {
  if (motorDirection == forwards) {
    Serial.println("on phase");
    digitalWrite(motorA[whichMotor], HIGH);
    digitalWrite(motorB[whichMotor], LOW);
  }
  else if (motorDirection == backwards) {
    Serial.println("off phase");
    digitalWrite(motorA[whichMotor], LOW);
    digitalWrite(motorB[whichMotor], HIGH);
  }
  //Serial.print(whichMotor);
  // Serial.println(motorDirection);
  //delay(1);
}
 
You need to progress the state-machines for the motor all the time, not just when a noteOn/Off message arrives.

Those messages just trigger one of the transitions in the state-machine, but all the timeouts need to be checked
repeatedly (from loop()) while the motor is in the sequence.

Perhaps you aren't really conversant with states and transitions and how they can be coded? I'm sure there are
good tutorials out there - for instance the sequencing of a traffic light or elevator are common didactic examples of
this you'll find loads of examples for.
 
Hi, for such things I would like to recommend the threads library.
Make a thread for each motor, which can do the the whole sequence with threads.delay(150) between the steps. The start of the sequence is started by a global flag variable, which is set by the main loop and reset by the thread.

Something like:
Code:
void m1Thread() {
while(1) {
while(m1trigger==0) threads.yield();
m1trigger=0;
doForwardM1();
threads.delay(150);
....
}
}
 
Back
Top