1

I've got a DC motor connected to an Arduino Nano, L298N H-Bridge and a 12v Power supply. I'm trying to make it respond to incoming MIDI data a bit quicker. Right now, it seems awfully slow, and lags in response to quick value changes. I'm using MIDI to send data into my Arduino, so my baud rate is limited to 31250.

The issue is mainly with my DAW (Ableton), as my motor responds quickly when I try to control it with a fader on my MIDI keyboard.

Note: I'm also using a potentiometer and a capacitive touch sensor in this code. I'll try to simplify it as much as I can so I can isolate the issue Here's the code:

#include <SoftwareSerial.h> // MIDI Input
#include <CapacitiveSensor.h>
#include <MIDI.h> // MIDI Output
#define txPin 1
#define rxPin 4

SoftwareSerial midiSerial (rxPin, txPin);

const byte touchSend    = 2;//Send pin for Capacitance Sensing Circuit (Digital 7)
const byte motorPWM     = 3;
const byte motorDown    = 5;
const byte motorUp      = 6;
const byte touchReceive = 7; //Receive pin for Capacitance Sensing Circuit (Digital 8)
const byte wiper        = 7; //Position of fader relative to GND (Analog 0)

int incomingCommand;
int incomingNote;
int incomingVelocity;
byte motorSpeed = 75; // Raise if the fader is too slow (0-255)
byte minimumCp  = 200; // Raise if the fader is too sensitive (0-16383)
byte tolerance  = 10; // Raise if the fader is too shaky (0-1023)
double faderMax = 0; //Value read by fader's maximum position (0-1023)
double faderMin = 0; //Value read by fader's minimum position (0-1023)
bool touched = false; //Is the fader currently being touched?
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay    = 10;    // the debounce time; increase if the output flickers
int lastfaderValue    = 0;

byte ch1Vol = 224;
byte fullVel = 127;
byte ch_1 = 1;
byte Db_1 = 1;

CapacitiveSensor touch = CapacitiveSensor(touchReceive, touchSend);
MIDI_CREATE_DEFAULT_INSTANCE();

void setup() {
  touch.set_CS_AutocaL_Millis(0xFFFFFFFF);
  midiSerial.begin(31250);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  while (!Serial);
  pinMode(motorDown, OUTPUT);
  pinMode(motorUp, OUTPUT);
  pinMode(motorPWM, OUTPUT);
  pinMode(rxPin, INPUT );
  pinMode(txPin, OUTPUT);
  analogWrite(motorPWM, motorSpeed);
  calibrateFader(); }

void calibrateFader() {
  digitalWrite(motorUp, HIGH);
  analogWrite(motorPWM, 100);
  delay(300);
  digitalWrite(motorUp, LOW);
  faderMax = analogRead(wiper) - tolerance;
  digitalWrite(motorDown, HIGH);
  analogWrite(motorPWM, 100);
  delay(300);
  digitalWrite(motorDown, LOW);
  faderMin = analogRead(wiper) + tolerance; }

void loop() {
  int faderPos = analogRead(wiper);
  int faderMIDI = faderPos / 8;
  int faderHiResMIDI = ((faderPos *16) - 8191);
  while ( midiSerial.available() > 0 ) {
    int commandByte = midiSerial.read();
    int noteByte = midiSerial.read();
    byte velocityByte = midiSerial.read();
    midiSerial.write( commandByte);
    midiSerial.write( noteByte);
    midiSerial.write( velocityByte);
    incomingCommand = commandByte;
    incomingNote = noteByte;
    incomingVelocity = velocityByte*8; }
    
 { int totalCp =  touch.capacitiveSensor(30); 
 if ( (millis() - lastDebounceTime) > debounceDelay) {
    if (totalCp <= minimumCp) { touched = false; // Not Touching Fader 
      if (incomingCommand == ch1Vol) { updateFader(incomingVelocity); } }
    if ((faderPos == lastfaderValue) && (totalCp > minimumCp)) { touched = true; // Touching Fader
      MIDI.sendNoteOn(Db_1, fullVel, ch_1);
      digitalWrite(motorDown, LOW);
      digitalWrite(motorUp, LOW); }
    if (((faderPos > lastfaderValue+1) or (faderPos < lastfaderValue-1)) && (totalCp > minimumCp)) { touched = true; // Moving Fader
      MIDI.sendPitchBend(faderHiResMIDI, ch_1);
      digitalWrite(motorDown, LOW);
      digitalWrite(motorUp, LOW); }
    lastfaderValue = faderPos;  
    lastDebounceTime = millis(); //set the current time
} } }

void updateFader(int position) {     //Function to move fader to a specific position between 0-1023 if it's not already there
  if (position < analogRead(wiper) - tolerance && position > faderMin && !touched) {
    digitalWrite(motorDown, HIGH);
    while (position < analogRead(wiper) - tolerance && !touched) {}; //Loops until motor is done moving
    digitalWrite(motorDown, LOW); }
  else if (position > analogRead(wiper) + tolerance && position < faderMax && !touched) {
    digitalWrite(motorUp, HIGH);
    while (position > analogRead(wiper) + tolerance && !touched) {}; //Loops until motor is done moving
    digitalWrite(motorUp, LOW); } }
12
  • It probably because those while() {} (wait until...) codes that are blocking.
    – hcheung
    Jun 20, 2021 at 5:58
  • About what lack are we talking here exactly? Is it the delay between sending a command and the fader starting to move? Or is it the fader not reacting directly when it already received a command? From your code the former should be rather short (a bit more than 10ms I think), while the latter will be a bit greater than the time that the motor needs to drive the fader to its previously commanded position (because of the while loop).
    – chrisl
    Jun 20, 2021 at 7:01
  • There's a fundamental flaw in your serial reading code. Read: majenko.co.uk/blog/reading-serial-arduino
    – Majenko
    Jun 20, 2021 at 9:08
  • Good point. @zRockafellow You are checking for more than zero bytes being available, but then you read 3 bytes. You cannot be sure, that all these bytes where already received. Maybe just check for 3 bytes being available
    – chrisl
    Jun 20, 2021 at 10:54
  • I tried replacing the while() codes with if, but I found that the motor stopped responding to data completely. I'll try rewriting that section without any while loops. Jun 20, 2021 at 15:28

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.