Midi control using a linear optical encoder

Hello to all :slight_smile: I've hacked an old inkjet printer for use with various musical instruments. I'm particularly interested in using the print head and rail assembly to track back and fourth over sets of strings. While I have had success in positioning the head at various target points within my loop, once I add midi code to my sketch she fails to budge. The code compiles and the print head travels to both ends during setup but then stops altogether. Could someone please point out where I'm going wrong?
Thanks, Robbie

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();



int enablePin = 10;
int motor1 = 9;
int motor2 = 8;

int encoderI = 2;
int encoderQ = 3;

byte target1 = 2000;
byte target2 = 400;
byte target3 = 3000;
byte target4 = 1000;


#define encoderI 2
#define encoderQ 3 // Only use one interrupt in this example

volatile int count;

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleNoteOn(Note);

  count = 0;
  Serial.begin(115200);

  pinMode(motor1, OUTPUT);
  pinMode(motor2, OUTPUT);
  pinMode(enablePin, OUTPUT);


  pinMode(encoderI, INPUT); attachInterrupt(digitalPinToInterrupt(2), handleEncoder, CHANGE);
  pinMode(encoderQ, INPUT);




  // Finding home position by driving slowly to both end positions
  setMotor (0);
  Delay(1500);
  setMotor(100);
  Delay(1000);

  count = 0;
  setMotor(-100);
  Delay(900);
  setMotor(0);
  count = 0;


}

void loop() {

  MIDI.read();
}
void Note(byte channel, byte note, byte velocity) {

  if (note == 60)

  {
    driveTo(target1);
  }

  if (note == 62)

  {
    driveTo(target2);
  }

  if (note == 64)

  {
    driveTo(target3);
  }

  if (note == 65)

  {
    driveTo(target4);
  }

}


void setMotor(int speed) {

  // make sure  speed variable is within accepted margins

  if (speed == 0) {
    analogWrite(enablePin, speed);
    digitalWrite(motor1, HIGH);
    digitalWrite(motor2, LOW);


  }
  else if (speed > 0 ) {

    if (speed >= 255) {
      speed = 255;
    }
    speed = map( speed, 0, 255, 200, 255);
    analogWrite(enablePin, speed);
    digitalWrite(motor1, HIGH);
    digitalWrite(motor2, LOW);

  }
  else {


    if (speed <= -255) {
      speed = -255;
    }
    speed = map (speed, -255, -1, -255, -200);
    analogWrite(enablePin, -1 * speed);
    digitalWrite(motor1, LOW);
    digitalWrite(motor2, HIGH);

  }
}

void handleEncoder() {

  if (digitalRead(encoderI) == digitalRead(encoderQ))

  { count++;
  }
  else
  { count--;
  }

}

void Delay(int interval) {

  unsigned long startTime = millis();

  while (millis() - startTime <= interval ) {
    // do nothing while waiting for time to pass
    Serial.println(count);
  }
  return;

}

void driveTo(int setpoint) {

  // basic Proportional feedback control for driving to set position
  float gain = 0.08;
  int error = 0;

  error = setpoint - count;

  while (error >= 20 || error <= -20) {

    error = setpoint - count;
    int control = gain * error;

    setMotor(control);
    Serial.print(count);
    Serial. print ("  ");
    Serial.println(error);

  }
  // turn motor off when setpoint is reached
  setMotor (0);

}

You could add some debug code (Serial output or just an LED if your only UART is being used for MIDI) to see if the 'if' clauses in the Note function are executed.

Pieter

Thanks for your reply Pieter.

The board is definitely receiving midi as the board's led is blinking in sync with incoming midi notes. The serial monitor first shows the optical encoder's readings as the print head moves to both ends of the assembly and then tries reading the incoming midi notes even though the baud rate is not set correctly. I tried removing the "if" clauses and just replaced them with my original commands...

driveTo(target1);
 Delay(500);

 driveTo(target2);
 Delay(500);

 driveTo(target3);
 Delay(500);

 driveTo(target4);
 Delay(500);

But it's as if the midi code cuts dead anything that's about to happen in the loop!

Try to isolate the problem. First try to get MIDI working. Just write a sketch that turns on an LED when it receives a MIDI note.

What board are you using? How is the MIDI connected? Are you using a hardware MIDI connection? Or do you use HIDuino or Hairless for MIDI over USB.
Are you sure that the baud rate is correct? Hardware MIDI and HIDuino are 31250 baud, Hairless is 115200 by default.

Pieter

The midi code I'm using is from a previous sketch I put together which works perfectly with a set of servos. I'm using a Seeduino board which a little fancier than a Duemilanove and my midi is a hardware connection. This is my midi/servo sketch

#include <MIDI.h>
#include <Servo.h>


//#define LED 6
MIDI_CREATE_DEFAULT_INSTANCE();
byte servoPos1 = 110; // centred servo position
byte servoPos2 = 145; 
byte servoPos3 = 60;
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;
Servo servo6;

int delayPeriod1 = 200; // delay after first movement
int delayPeriod2 = 200; // delay after second movement before detach

void setup() {
  servo1.attach(3);
  servo2.attach(4);
  servo3.attach(5);
  servo4.attach(6);
  servo5.attach(7);
  servo6.attach(9);

  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleNoteOn(Note);
  //digitalWrite(6, LOW);
  //digitalWrite(5, LOW);
  //digitalWrite(4, LOW);
  //digitalWrite(3, LOW);
  //digitalWrite(2, LOW);
  //digitalWrite(6, LOW);

  //pinMode(7, OUTPUT); //LED on pin 6

  servo1.write(servoPos1); // callibrate's the initial servo position
  servo2.write(servoPos1);
  servo3.write(servoPos1);
  servo4.write(servoPos1); // callibrate's the initial servo position
  servo5.write(servoPos1);
  servo6.write(servoPos1);
  servo1.detach();          // detach preventing jitter after initialisation
  servo2.detach();
  servo3.detach();
  servo4.detach();
  servo5.detach();
  servo6.detach();


}

void loop() {
  MIDI.read();
}

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

  if (note == 60)

  {
    
    servo1.attach(3);
    servo1.write(servoPos2);
    delay (delayPeriod1);
    servo1.write(servoPos1);
    delay (delayPeriod2);
    servo1.detach();
  }
  
  if (note == 62)
  
  {
    servo1.attach(3);

    servo1.write(servoPos3);
    delay (delayPeriod1);
    servo1.write(servoPos1);
    delay(delayPeriod2);
    servo1.detach();

  }

  if (note == 64)

  {

    servo2.attach(4);

    servo2.write(servoPos2);
    delay (delayPeriod1);
    servo2.write(servoPos1);
    delay(delayPeriod2);

    servo2.detach();

  }
  
  if (note == 65)
  
  {
    servo2.attach(4);

    servo2.write(servoPos3);
    delay (delayPeriod1);
    servo2.write(servoPos1);
    delay (delayPeriod2);
    servo2.detach();

  }

  if (note == 67)

  {
    servo3.attach(5);

    servo3.write(servoPos2);
    delay (delayPeriod1);
    servo3.write(servoPos1);
    delay(delayPeriod2);

    servo3.detach();

  }
  
  if (note == 69)
  
  {
    servo3.attach(5);

    servo3.write(servoPos3);
    delay (delayPeriod1);
    servo3.write(servoPos1);
    delay (delayPeriod2);
    servo3.detach();

  }

  if (note == 71)

  {
    servo4.attach(6);

    servo4.write(servoPos2);
    delay (delayPeriod1);
    servo4.write(servoPos1);
    delay(delayPeriod2);

    servo4.detach();

  }
  
  if (note == 72)
  
  {
    servo4.attach(6);

    servo4.write(servoPos3);
    delay (delayPeriod1);
    servo4.write(servoPos1);
    delay (delayPeriod2);
    servo4.detach();

  }

   if (note == 74)

  {
    servo5.attach(7);

    servo5.write(servoPos2);
    delay (delayPeriod1);
    servo5.write(servoPos1);
    delay(delayPeriod2);

    servo5.detach();

  }
  
  if (note == 76)
  
  {
    servo5.attach(7);

    servo5.write(servoPos3);
    delay (delayPeriod1);
    servo5.write(servoPos1);
    delay (delayPeriod2);
    servo5.detach();

  }

   if (note == 77)

  {
    servo6.attach(9);

    servo6.write(servoPos2);
    delay (delayPeriod1);
    servo6.write(servoPos1);
    delay(delayPeriod2);

    servo6.detach();

  }
  
  if (note == 79)
  
  {
    servo6.attach(9);

    servo6.write(servoPos3);
    delay (delayPeriod1);
    servo6.write(servoPos1);
    delay (delayPeriod2);
    servo6.detach();

  }


}

And this code is the linear optical encoder working perfectly without midi and just positioning itself to preset targets

int enablePin = 10;
int motor1 = 9;
int motor2 = 8;

int encoderI = 2;
int encoderQ = 3;

int target1 = 2000;
int target2 = 400;
int target3 = 3000;
int target4 = 1000;


#define encoderI 2
#define encoderQ 3 // Only use one interrupt in this example

volatile int count;

void setup() {
  count=0;
  Serial.begin(115200);    

  pinMode(motor1, OUTPUT);
  pinMode(motor2, OUTPUT);
  pinMode(enablePin, OUTPUT);


  pinMode(encoderI, INPUT); attachInterrupt(digitalPinToInterrupt(2), handleEncoder, CHANGE);
  pinMode(encoderQ, INPUT); 


  // Finding home position by driving slowly to both end positions
  setMotor (0);
  Delay(1500);
  setMotor(100);
  Delay(1000);

  count = 0;
  setMotor(-100);
  Delay(900);
  setMotor(0);
  count = 0;


}

void loop() {

  driveTo(target1);
  Delay(500);

  driveTo(target2);
  Delay(500);

  driveTo(target3);
  Delay(500);

  driveTo(target4);
  Delay(500);


}

void setMotor(int speed){

  // make sure  speed variable is within accepted margins

  if (speed == 0){
    analogWrite(enablePin, speed);
    digitalWrite(motor1, HIGH);
    digitalWrite(motor2, LOW);


    }
  else if (speed > 0 ){

    if (speed >= 255) {
      speed = 255;
    }
    speed = map( speed, 0, 255, 200, 255);
    analogWrite(enablePin, speed);
    digitalWrite(motor1, HIGH);
    digitalWrite(motor2, LOW);

}  
else {


  if (speed <= -255){
    speed = -255;
    }
  speed = map (speed, -255, -1, -255, -200);  
  analogWrite(enablePin, -1* speed);
  digitalWrite(motor1, LOW);
  digitalWrite(motor2, HIGH);

  }
}

void handleEncoder(){

  if(digitalRead(encoderI) == digitalRead(encoderQ))

{ count++;
}
else
{ count--;
}

}

void Delay(int interval){

  unsigned long startTime = millis();

  while (millis() - startTime <= interval ){
    // do nothing while waiting for time to pass
   Serial.println(count); 
    }
  return;

} 

void driveTo(int setpoint){

  // basic Proportional feedback control for driving to set position
  float gain = 0.08;
  int error = 0;

  error = setpoint - count;

  while (error >= 20 || error <= -20){

  error = setpoint - count;
  int control = gain * error;

  setMotor(control);
  Serial.print(count);
  Serial. print ("  ");
  Serial.println(error);

  }
  // turn motor off when setpoint is reached
  setMotor (0);

  }

So essentially i've just taken the midi functioning from the working servo code and thrown it into the encoder sketch... Something is conflicting somewhere :frowning:

Serial.begin(115200);

There's your problem.
Hardware MIDI uses a baud rate of 31250.
The MIDI library uses UART0 as input/output device. On basic Arduino boards without USB, this UART is also used for debugging and uploading.
By calling Serial.begin, you change the baud rate of UART0, and you override the settings of the MIDI library.
If you delete it, it should work.

If you really need debug output, you can use SoftwareSerial for the MIDI connection, check the MIDI library examples and header files for more information.

Pieter

:slight_smile: :slight_smile: :slight_smile: Absolutely solved :slight_smile: :slight_smile: :slight_smile: I'm stupid to have overlooked that!! Thank you for helping me Pieter!!