tttapa / Control-Surface-Motor-Fader

Arduino motorized fader controller, and example code for integration with the Control Surface library.
https://tttapa.github.io/Pages/Arduino/Control-Theory/Motor-Fader/
GNU General Public License v3.0
107 stars 10 forks source link

Problems using 8 motorized faders and Midi Interface #3

Open Vahen1981 opened 3 years ago

Vahen1981 commented 3 years ago

Hi Pieter! I hope you are fine... First of all, I should say that I'm pretty new in this things, and since many days I'm trying to understand your code for motorized faders. At this point I think I learnt a lot, but there is still a huge part of your code that is too much complex for my understanding. So, please forgive me if my questions are too basic.

I was trying to run 8 motorized faders using two arduinos pro mini for the fader controller, and a mega 2560 pro (the small version of arduino mega) for the midi controller.

I took your sketch "MIDI-Controller.ino" and I modified a bit to run this 8 faders through this two slaves. I choosed the HardwareSerialMIDI_Interface for this project. Everything was fine, the eight faders were running very good, untill I disconnected the usb from the mega... I don't know why, but when I did this appears that the master doesn`t send anything to the slaves... I am using the rx0 and tx0 pin for the midi circuit, and an external power supply.

Another sintom is that if I disconnect the second slave, I can disconnect the usb from mega without any problem, but obviously just with 4 faders.

Any suggestion about where is the problem?

tttapa commented 3 years ago

I don't immediately see any problems with what you've described, that should work fine in theory. Could this be a power issue?

You can start debugging by using a simple program to the Mega, e.g. one that just sends a setpoint change over I2C every second or so, this way you can eliminate any MIDI-related issues.

If you post your code I'll have a quick look at it, maybe I can spot something obvious.

Vahen1981 commented 3 years ago

I think is not a code problem... In fact... this morning I was trying many things and I just upload your code to the mega, exactly as you wrote... the only difference was that I changed the midi interface for a Hardware serial midi... The behavior was the same... if I use the usb of the mega connected works perfect (obviously with just the first slave), but if I unconnect the usb the faders doesn't respond and doesn't send any midi message... to weird... I think is a power issue or some connection... as you say... can I share my schematics with you?

Another thing that I realized was that when I disconnect just the SDA line to the second slave, the first slave start to work fine, but obviously not the second.

Vahen1981 commented 3 years ago

Here is my code anyway, thank you pieter!


#include <Wire.h>

uint8_t mcu_idx = 0;    // MCU track number
uint8_t fader_idx = 0;  // Index of the fader connected to the slave
const uint8_t slave_addr = 11; // I²C address of slave fader controller
const uint8_t slave_addr2 = 8; 
//USBDebugMIDI_Interface midi;  // MIDI interface to DAW
//HairlessMIDI_Interface hairless;
HardwareSerialMIDI_Interface midiser = {Serial, 115200};
PBValue pb[8] = {{MCU::VOLUME_1},{MCU::VOLUME_2},{MCU::VOLUME_3},{MCU::VOLUME_4},{MCU::VOLUME_5},{MCU::VOLUME_6},{MCU::VOLUME_7},{MCU::VOLUME_8}};   // Receive pitch bend with setpoint
PitchBendSender<10> sender;             // Send pitch bend with actual position
Hysteresis<4, uint16_t, uint16_t> hyst; // Filter the actual position
constexpr bool debug_print = false;     // Print the data from the slave
bool prevTouchedA = false;
bool prevTouchedB = false;
bool prevTouchedC = false;
bool prevTouchedD = false;
bool prevTouchedE = false;
bool prevTouchedF = false;
bool prevTouchedG = false;
bool prevTouchedH = false;
uint16_t faderposCS[8];
uint16_t lastSetpoint1;
uint16_t prevSetpointDAW1 = 0;
uint16_t prevSetpointCS1 = 0;
uint16_t prevLastSetpoint1 = 0;
uint16_t lastSetpoint2;
uint16_t prevSetpointDAW2 = 0;
uint16_t prevSetpointCS2 = 0;
uint16_t prevLastSetpoint2 = 0;
uint16_t lastSetpoint3;
uint16_t prevSetpointDAW3 = 0;
uint16_t prevSetpointCS3 = 0;
uint16_t prevLastSetpoint3 = 0;
uint16_t lastSetpoint4;
uint16_t prevSetpointDAW4 = 0;
uint16_t prevSetpointCS4 = 0;
uint16_t prevLastSetpoint4 = 0;

uint16_t lastSetpoint5;
uint16_t prevSetpointDAW5 = 0;
uint16_t prevSetpointCS5 = 0;
uint16_t prevLastSetpoint5 = 0;
uint16_t lastSetpoint6;
uint16_t prevSetpointDAW6 = 0;
uint16_t prevSetpointCS6 = 0;
uint16_t prevLastSetpoint6 = 0;
uint16_t lastSetpoint7;
uint16_t prevSetpointDAW7 = 0;
uint16_t prevSetpointCS7 = 0;
uint16_t prevLastSetpoint7 = 0;
uint16_t lastSetpoint8;
uint16_t prevSetpointDAW8 = 0;
uint16_t prevSetpointCS8 = 0;
uint16_t prevLastSetpoint8 = 0;

void setup() {
    Wire.begin();                          // Join the I²C bus
    Wire.setClock(400000);                 // Set higher I²C speed
    Control_Surface.begin();               // Initialize everything else
}

void readFromSlave() {
    // Request the position from the slave over I²C
    uint8_t maxlen = 1 + (1 + fader_idx) * 2;
    Wire.requestFrom(slave_addr, maxlen);
    uint8_t buf[maxlen];
    uint8_t i = 0;
    while (Wire.available() && i < maxlen)
        buf[i++] = Wire.read();

    // If we received the “touch” byte
    if (i >= 1) {
        bool touchedA = buf[0] & (1 << 0);
        bool touchedB = buf[0] & (1 << 1);
        bool touchedC = buf[0] & (1 << 2);
        bool touchedD = buf[0] & (1 << 3);
        const MIDIAddress addr1 = MCU::FADER_TOUCH_1;
        const MIDIAddress addr2 = MCU::FADER_TOUCH_2;
        const MIDIAddress addr3 = MCU::FADER_TOUCH_3;
        const MIDIAddress addr4 = MCU::FADER_TOUCH_4;
        if (touchedA != prevTouchedA) {
            touchedA ? Control_Surface.sendNoteOn(addr1, 127)
                    : Control_Surface.sendNoteOff(addr1, 127);
            prevTouchedA = touchedA;
        }
        if (touchedB != prevTouchedB) {
            touchedB ? Control_Surface.sendNoteOn(addr2, 127)
                    : Control_Surface.sendNoteOff(addr2, 127);
            prevTouchedB = touchedB;
        }
        if (touchedC != prevTouchedC) {
            touchedC ? Control_Surface.sendNoteOn(addr3, 127)
                    : Control_Surface.sendNoteOff(addr3, 127);
            prevTouchedC = touchedC;
        }
        if (touchedD != prevTouchedD) {
            touchedD ? Control_Surface.sendNoteOn(addr4, 127)
                    : Control_Surface.sendNoteOff(addr4, 127);
            prevTouchedD = touchedD;
        }
    }

    // If we received the position and if the fader is being touched
    if(fader_idx == 0){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedA) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[0] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_1 + mcu_idx);
        }
    }

    if(fader_idx == 1){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedB) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[1] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_1 + mcu_idx);
        }
    }

    if(fader_idx == 2){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedC) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[2] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_1 + mcu_idx);
        }
    }

    if(fader_idx == 3){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedD) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[3] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_1 + mcu_idx);
        }
    }
}

void sendF1ToSlave() {
    uint16_t setpointDAW1 = pb[0].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS1 = faderposCS[0] >> 4;
    if(setpointDAW1 != prevSetpointDAW1){
      lastSetpoint1 = setpointDAW1;
      prevSetpointDAW1 = setpointDAW1;
    }
    if(setpointCS1 != prevSetpointCS1){
      lastSetpoint1 = setpointCS1;
      prevSetpointCS1 = setpointCS1;
    }
    if (lastSetpoint1 != prevLastSetpoint1) {
        uint16_t idx1 = 0;
        uint16_t data1 = lastSetpoint1;
        data1 |= idx1 << 12;
        Wire.beginTransmission(slave_addr);
        Wire.write(reinterpret_cast<const uint8_t *>(&data1), 2);
        Wire.endTransmission();
        prevLastSetpoint1 = lastSetpoint1;
    }
 }

void sendF2ToSlave() {
    uint16_t setpointDAW2 = pb[1].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS2 = faderposCS[1] >> 4;
    if(setpointDAW2 != prevSetpointDAW2){
      lastSetpoint2 = setpointDAW2;
      prevSetpointDAW2 = setpointDAW2;
    }
    if(setpointCS2 != prevSetpointCS2){
      lastSetpoint2 = setpointCS2;
      prevSetpointCS2 = setpointCS2;
    }
    if (lastSetpoint2 != prevLastSetpoint2) {
        uint16_t idx2 = 1;
        uint16_t data2 = lastSetpoint2;
        data2 |= idx2 << 12;
        Wire.beginTransmission(slave_addr);
        Wire.write(reinterpret_cast<const uint8_t *>(&data2), 2);
        Wire.endTransmission();
        prevLastSetpoint2 = lastSetpoint2;
    }
 }

void sendF3ToSlave() {
    uint16_t setpointDAW3 = pb[2].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS3 = faderposCS[2] >> 4;
    if(setpointDAW3 != prevSetpointDAW3){
      lastSetpoint3 = setpointDAW3;
      prevSetpointDAW3 = setpointDAW3;
    }
    if(setpointCS3 != prevSetpointCS3){
      lastSetpoint3 = setpointCS3;
      prevSetpointCS3 = setpointCS3;
    }
    if (lastSetpoint3 != prevLastSetpoint3) {
        uint16_t idx3 = 2;
        uint16_t data3 = lastSetpoint3;
        data3 |= idx3 << 12;
        Wire.beginTransmission(slave_addr);
        Wire.write(reinterpret_cast<const uint8_t *>(&data3), 2);
        Wire.endTransmission();
        prevLastSetpoint3 = lastSetpoint3;
    }
 }

void sendF4ToSlave() {
    uint16_t setpointDAW4 = pb[3].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS4 = faderposCS[3] >> 4;
    if(setpointDAW4 != prevSetpointDAW4){
      lastSetpoint4 = setpointDAW4;
      prevSetpointDAW4 = setpointDAW4;
    }
    if(setpointCS4 != prevSetpointCS4){
      lastSetpoint4 = setpointCS4;
      prevSetpointCS4 = setpointCS4;
    }
    if (lastSetpoint4 != prevLastSetpoint4) {
        uint16_t idx4 = 3;
        uint16_t data4 = lastSetpoint4;
        data4 |= idx4 << 12;
        Wire.beginTransmission(slave_addr);
        Wire.write(reinterpret_cast<const uint8_t *>(&data4), 2);
        Wire.endTransmission();
        prevLastSetpoint4 = lastSetpoint4;
    }
 }

void readFromSlave2() {
    // Request the position from the slave over I²C
    uint8_t maxlen = 1 + (1 + fader_idx) * 2;
    Wire.requestFrom(slave_addr2, maxlen);
    uint8_t buf[maxlen];
    uint8_t i = 0;
    while (Wire.available() && i < maxlen)
        buf[i++] = Wire.read();

    // If we received the “touch” byte
    if (i >= 1) {
        bool touchedE = buf[0] & (1 << 0);
        bool touchedF = buf[0] & (1 << 1);
        bool touchedG = buf[0] & (1 << 2);
        bool touchedH = buf[0] & (1 << 3);
        const MIDIAddress addr1 = MCU::FADER_TOUCH_5;
        const MIDIAddress addr2 = MCU::FADER_TOUCH_6;
        const MIDIAddress addr3 = MCU::FADER_TOUCH_7;
        const MIDIAddress addr4 = MCU::FADER_TOUCH_8;
        if (touchedE != prevTouchedE) {
            touchedE ? Control_Surface.sendNoteOn(addr1, 127)
                    : Control_Surface.sendNoteOff(addr1, 127);
            prevTouchedE = touchedE;
        }
        if (touchedF != prevTouchedF) {
            touchedF ? Control_Surface.sendNoteOn(addr2, 127)
                    : Control_Surface.sendNoteOff(addr2, 127);
            prevTouchedF = touchedF;
        }
        if (touchedG != prevTouchedG) {
            touchedG ? Control_Surface.sendNoteOn(addr3, 127)
                    : Control_Surface.sendNoteOff(addr3, 127);
            prevTouchedG = touchedG;
        }
        if (touchedH != prevTouchedH) {
            touchedH ? Control_Surface.sendNoteOn(addr4, 127)
                    : Control_Surface.sendNoteOff(addr4, 127);
            prevTouchedH = touchedH;
        }
    }

    // If we received the position and if the fader is being touched
    if(fader_idx == 0){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedE) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[4] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_5 + mcu_idx);
        }
    }

    if(fader_idx == 1){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedF) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[5] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_5 + mcu_idx);
        }
    }

    if(fader_idx == 2){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedG) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[6] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_5 + mcu_idx);
        }
    }

    if(fader_idx == 3){ 
        if (i >= 1 + (1 + fader_idx) * 2 && prevTouchedH) {
            uint16_t faderpos;
            memcpy(&faderpos, &buf[1 + fader_idx * 2], 2);
            faderposCS[7] = faderpos;
            // Send the fader position over MIDI if it changed
            if (hyst.update(faderpos))
                sender.send(hyst.getValue(), MCU::VOLUME_5 + mcu_idx);
        }
    }
}

void sendF5ToSlave() {
    uint16_t setpointDAW5 = pb[4].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS5 = faderposCS[4] >> 4;
    if(setpointDAW5 != prevSetpointDAW5){
      lastSetpoint5 = setpointDAW5;
      prevSetpointDAW5 = setpointDAW5;
    }
    if(setpointCS5 != prevSetpointCS5){
      lastSetpoint5 = setpointCS5;
      prevSetpointCS5 = setpointCS5;
    }
    if (lastSetpoint5 != prevLastSetpoint5) {
        uint16_t idx5 = 0;
        uint16_t data5 = lastSetpoint5;
        data5 |= idx5 << 12;
        Wire.beginTransmission(slave_addr2);
        Wire.write(reinterpret_cast<const uint8_t *>(&data5), 2);
        Wire.endTransmission();
        prevLastSetpoint5 = lastSetpoint5;
    }
 }

void sendF6ToSlave() {
    uint16_t setpointDAW6 = pb[5].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS6 = faderposCS[5] >> 4;
    if(setpointDAW6 != prevSetpointDAW6){
      lastSetpoint6 = setpointDAW6;
      prevSetpointDAW6 = setpointDAW6;
    }
    if(setpointCS6 != prevSetpointCS6){
      lastSetpoint6 = setpointCS6;
      prevSetpointCS6 = setpointCS6;
    }
    if (lastSetpoint6 != prevLastSetpoint6) {
        uint16_t idx6 = 1;
        uint16_t data6 = lastSetpoint6;
        data6 |= idx6 << 12;
        Wire.beginTransmission(slave_addr2);
        Wire.write(reinterpret_cast<const uint8_t *>(&data6), 2);
        Wire.endTransmission();
        prevLastSetpoint6 = lastSetpoint6;
    }
 }

void sendF7ToSlave() {
    uint16_t setpointDAW7 = pb[6].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS7 = faderposCS[6] >> 4;
    if(setpointDAW7 != prevSetpointDAW7){
      lastSetpoint7 = setpointDAW7;
      prevSetpointDAW7 = setpointDAW7;
    }
    if(setpointCS7 != prevSetpointCS7){
      lastSetpoint7 = setpointCS7;
      prevSetpointCS7 = setpointCS7;
    }
    if (lastSetpoint7 != prevLastSetpoint7) {
        uint16_t idx7 = 2;
        uint16_t data7 = lastSetpoint7;
        data7 |= idx7 << 12;
        Wire.beginTransmission(slave_addr2);
        Wire.write(reinterpret_cast<const uint8_t *>(&data7), 2);
        Wire.endTransmission();
        prevLastSetpoint7 = lastSetpoint7;
    }
 }

void sendF8ToSlave() {
    uint16_t setpointDAW8 = pb[7].getValue() >> 4; // 14-bit → 10-bit
    uint16_t setpointCS8 = faderposCS[7] >> 4;
    if(setpointDAW8 != prevSetpointDAW8){
      lastSetpoint8 = setpointDAW8;
      prevSetpointDAW8 = setpointDAW8;
    }
    if(setpointCS8 != prevSetpointCS8){
      lastSetpoint8 = setpointCS8;
      prevSetpointCS8 = setpointCS8;
    }
    if (lastSetpoint8 != prevLastSetpoint8) {
        uint16_t idx8 = 3;
        uint16_t data8 = lastSetpoint8;
        data8 |= idx8 << 12;
        Wire.beginTransmission(slave_addr2);
        Wire.write(reinterpret_cast<const uint8_t *>(&data8), 2);
        Wire.endTransmission();
        prevLastSetpoint8 = lastSetpoint8;
    }
 }

 void sumar(){
    fader_idx++;
    mcu_idx++;
    if(fader_idx == 4){fader_idx = 0; mcu_idx = 0;}
 }

void loop() {
    Control_Surface.loop();
    static Timer<millis> timer = 5;
    // Don't update at full speed, just every couple of milliseconds
    if (timer) {
        readFromSlave();
        sendF1ToSlave();
        sendF2ToSlave();
        sendF3ToSlave();
        sendF4ToSlave();
        readFromSlave2();
        sendF5ToSlave();
        sendF6ToSlave();
        sendF7ToSlave();
        sendF8ToSlave();
        sumar();
    }
}```
tttapa commented 3 years ago

HardwareSerialMIDI_Interface midiser = {Serial, 115200};

Are you sure this is the correct baud rate? Hardware MIDI with 5-pin DIN connectors use a baud rate of 31250 symbols per second, not 115200.

31250 is the default, so you can just use:

HardwareSerialMIDI_Interface midiser {Serial};

I didn't look into the rest of the code in detail, but it's in dire need of some arrays, there's too much code duplication. Also, you need one Hysteresis object for each fader.

Vahen1981 commented 3 years ago

Actually the first baud rate that I try was 31250, and the behavior was the same... I changed it to 115200 just trying to fix it... I'm aware about the code duplication sorry :( At the begining I was very confused trying to adapt the code to my hadware, but now I will try to optimize and use some arrays to fix it... I didn't know about hysteresis, I will try that. Thanks!

tttapa commented 3 years ago

I didn't know about hysteresis, I will try that.

It won't solve the problem you're facing right now, it's just a remark.

I'd try changing the setpoint without MIDI as I mentioned in my first reply.

Vahen1981 commented 3 years ago

Thank you! I will try with a simple program sending setpoints and I will let you know!

Vahen1981 commented 3 years ago

Hi Pieter, is definetely not a midi problem, I did a simple program as you suggest and happens the same... when it is connected to the usb works perfect, but if not nothing happens. this is the program that I tried:

#include <Wire.h>
#define slave_addr    11
#define slave_addr2   8

void setup() {
   Wire.begin();                     
   Wire.setClock(400000);               
}

void sendToSlave(uint8_t slaveIdx, uint16_t setpoint){
  for(byte idx = 0 ; idx < 4 ; idx++){
    uint16_t data = setpoint;
    data |= idx << 12;
    Wire.beginTransmission(slaveIdx);
    Wire.write(reinterpret_cast<const uint8_t *>(&data), 2);
    Wire.endTransmission();
    delay(250);
  }
}

void loop() {
  sendToSlave(slave_addr, 1023);
  sendToSlave(slave_addr2, 1023);
  sendToSlave(slave_addr, 0);
  sendToSlave(slave_addr2, 0);
}

So I assume, must be a power issue... or maybe a proble with the mega... I will keep researching...

Vahen1981 commented 3 years ago

I finally solve it!! I'm so happy haha Apparentely the midi controller should begin after the fader controller... I just put a delay(1000) in the setup of the midi controller, before the Wire.begin() and now is working perfect without the usb connection!

tttapa commented 3 years ago

Glad to hear!

There seems to be a timeout option in the Wire library: https://github.com/arduino/reference-en/issues/895
I don't have much time right now, but it might be interesting to look into to prevent issues like this one.

Vahen1981 commented 3 years ago

I'll check that, thank you for your support!

moimeme81 commented 10 months ago

@Vahen1981 since you got it to work, it would be interesting if you could create a fork with your code, wiring and all. At the very least it would be easier to follow that a code in a comment of an issue...