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

Some questions about using arduino nano, TB6612 #24

Open Renlong2020 opened 3 months ago

Renlong2020 commented 3 months ago

First of all, thank you so much for your library, it's great。 This is my case, I use the arduino nano as the motor controller and the TB6612 as the driver。 13E7618E-96A6-4E1B-A608-1BE0645DF8C4

FaderTouch to Nano PB0 parallel Vcc resistance 680K FaderPot A to Vcc 5V, B to Nano A0 The parallel Gnd capacitor is 100uF and C to Gnd 6612 Ain1 to Nano D3, Ain2 to Nano D2

The test runs in the following video https://youtu.be/kXwtsr7uJ-A?si=9EeRVP1t-SH2OW_5

The problem is, it doesn't look right now. Where should I debug it? Or the wiring is wrong?

Renlong2020 commented 3 months ago

This is the situation of midi debugging after the test, touch is very sensitive, and there is no big problem, even when moving the fader, there will be midi parameter pitchbend, but after letting go, he will return to the starting point, what is the problem?

https://youtu.be/q9bpTxY4fMY?si=pdHMKDRcKFYfzA6d

tttapa commented 3 months ago

I'll have a detailed look later today, but 100µF is way too large, you need a capacitor of ~100nF (1000× smaller). The capacitor you have now will introduce a huge amount of delay in the measurement of the potentiometer.

The potentiometer moves back to zero because the reference doesn't get updated when you move it. Usually, the reference only gets updated when the MIDI software sends a new position to the Arduino. You can send "E0 00 40" in the serial monitor to change the reference to the middle position, as described here: https://tttapa.github.io/Pages/Arduino/Control-Theory/Motor-Fader/Configuration.html#debugging-direct-midi-control

Renlong2020 commented 2 months ago

Thank you very much for your reply. Under your guidance, I have been able to complete the connection and debugging of a single fader. Today, I made four fader connections and debugging, which can run normally at present, but there are two problems.

  1. In test mode, some faders, such as the third and fourth faders, are slightly slower than those of 1 and 2, that is, they cannot be fully synchronized. What is the problem? https://youtu.be/gHFz0rAuss8?si=h2z1bj_hKoeczhj5 https://youtu.be/H9VjfjDLeU4?si=WfxNzi5VqDV6BqoV
  2. In manual mode, midi information can be normally sent by touch, and pitchbend can also be pushed, but there is a little jitter, and the motor itself jitter. Including sending midi commands in the serial port, there will be jitter, where should I debug? Looking forward to your reply https://youtube.com/shorts/e1TpWmeXJis?si=SDOjHhvRdlF4pp67
tttapa commented 2 months ago

Are you using the same tuning for all four faders? By default, the code has different tunings for demonstration purposes. You should also be able to get rid of most of the jitter by tuning the controllers for your specific faders.

https://github.com/tttapa/Control-Surface-Motor-Fader/blob/fe8a54f912ea0bac2d75647e6f40e23807e00823/Motor-Controller/main.cpp#L217-L254

tttapa commented 2 months ago

If the actual references are getting out of sync (which might be the case, looking at the video), that probably means you're getting overrun. Try enabling the overrun indicator by using pin A2 for fader 3, and then lower the sampling rate until you're no longer getting any overruns.

https://github.com/tttapa/Control-Surface-Motor-Fader/blob/fe8a54f912ea0bac2d75647e6f40e23807e00823/Motor-Controller/main.cpp#L129-L136

Renlong2020 commented 2 months ago

Thank you for your guidance. Currently, four faders can work normally. However, when working on the slave computer of the host, my host is arduino uno, which obtains fader data and sends it to the serial port. How to set the data received by the serial port to be pure midi data without other characters? So my 5pin midi eloquence can process midi information correctly?

#include <Control_Surface.h>
#include <Wire.h>

const uint8_t mcu_idx = 0;    // MCU track number
const uint8_t fader_idx_0 = 0;  // Index of the first fader
const uint8_t fader_idx_1 = 1;  // Index of the second fader
const uint8_t fader_idx_2 = 2;  // Index of the third fader
const uint8_t fader_idx_3 = 3;  // Index of the fourth fader
// I2C address of slave fader controller
const uint8_t slave_addr = 8; 

USBDebugMIDI_Interface midi;  // MIDI interface to DAW
PBValue pb0 {MCU::VOLUME_1 + mcu_idx};   // Receive pitch bend for the first fader
PBValue pb1 {MCU::VOLUME_2 + mcu_idx};   // Receive pitch bend for the second fader
PBValue pb2 {MCU::VOLUME_3 + mcu_idx};   // Receive pitch bend for the third fader
PBValue pb3 {MCU::VOLUME_4 + mcu_idx};   // Receive pitch bend for the fourth fader
PitchBendSender<10> sender0;           // Send pitch bend with actual position for the first fader
PitchBendSender<10> sender1;           // Send pitch bend with actual position for the second fader
PitchBendSender<10> sender2;           // Send pitch bend with actual position for the third fader
PitchBendSender<10> sender3;           // Send pitch bend with actual position for the fourth fader
Hysteresis<4, uint16_t, uint16_t> hyst0; // Filter the actual position
Hysteresis<4, uint16_t, uint16_t> hyst1; // Filter the actual position for the second fader
Hysteresis<4, uint16_t, uint16_t> hyst2; // Filter the actual position for the third fader
Hysteresis<4, uint16_t, uint16_t> hyst3; // Filter the actual position for the fourth fader
bool prevTouched0 = false;                // Whether the first fader is being touched
bool prevTouched1 = false;                // Whether the second fader is being touched
bool prevTouched2 = false;                // Whether the third fader is being touched
bool prevTouched3 = false;                // Whether the fourth fader is being touched
uint16_t prevSetpoint0 = 0;               // Previous setpoint for the first fader
uint16_t prevSetpoint1 = 0;               // Previous setpoint for the second fader
uint16_t prevSetpoint2 = 0;               // Previous setpoint for the third fader
uint16_t prevSetpoint3 = 0;               // Previous setpoint for the fourth fader
constexpr bool debug_print = false;      // Print the data from the slave

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

void readFromSlave() {
    // Request the position from the slave over I2C
    uint8_t maxlen = 1 + (2 + fader_idx_3) * 2; // Increased max length for 4 faders
    Wire.requestFrom(slave_addr, maxlen);
    uint8_t buf[maxlen];
    uint8_t i = 0;
    while (Wire.available() && i < maxlen)
        buf[i++] = Wire.read();
  if (debug_print) Serial << AH::HexDump(buf, i) << endl;

    // Handle each fader's touch and position
    for (uint8_t idx = 0; idx < 4; idx++) {
        if (i >= 1) {
            bool touched = buf[0] & (1 << idx);
            const MIDIAddress addr = MCU::FADER_TOUCH_1 + mcu_idx + idx;
            bool* prevTouched = (idx == 0) ? &prevTouched0 : 
                               (idx == 1) ? &prevTouched1 : 
                               (idx == 2) ? &prevTouched2 : 
                               &prevTouched3;

            // Handle touch changes
            if (touched != *prevTouched) {
                touched ? midi.sendNoteOn(addr, 127)  // Send MIDI Note On
                        : midi.sendNoteOff(addr, 127); // Send MIDI Note Off
                *prevTouched = touched;
            }

            // Handle position changes if touched
            if (i >= 1 + (1 + idx) * 2 && *prevTouched) {
                uint16_t faderpos;
                memcpy(&faderpos, &buf[1 + idx * 2], 2);
                Hysteresis<4, uint16_t, uint16_t>* hyst = (idx == 0) ? &hyst0 : 
                                                            (idx == 1) ? &hyst1 : 
                                                            (idx == 2) ? &hyst2 : 
                                                            &hyst3;
                PitchBendSender<10>* sender = (idx == 0) ? &sender0 : 
                                               (idx == 1) ? &sender1 : 
                                               (idx == 2) ? &sender2 : 
                                               &sender3;
                if (hyst->update(faderpos)){
                    sender->send(hyst->getValue(), MCU::VOLUME_1 + mcu_idx + idx);
                    }
            }
        }
    }
}

void sendToSlave() {
    // Sending setpoints for all 4 faders
    for (uint8_t idx = 0; idx < 4; idx++) {
        uint16_t setpoint;
        PitchBendSender<10>* sender = (idx == 0) ? &sender0 : 
                                       (idx == 1) ? &sender1 : 
                                       (idx == 2) ? &sender2 : 
                                       &sender3;
        uint16_t* prevSetpoint = (idx == 0) ? &prevSetpoint0 : 
                                 (idx == 1) ? &prevSetpoint1 : 
                                 (idx == 2) ? &prevSetpoint2 : 
                                 &prevSetpoint3;
        PBValue* pb = (idx == 0) ? &pb0 : 
                      (idx == 1) ? &pb1 : 
                      (idx == 2) ? &pb2 : 
                      &pb3;

        setpoint = pb->getValue() >> 4; // 14-bit → 10-bit
        if (setpoint != *prevSetpoint) {
            uint16_t data = setpoint | (idx << 12);
            Wire.beginTransmission(slave_addr);
            Wire.write(reinterpret_cast<const uint8_t *>(&data), 2);
            Wire.endTransmission();
            *prevSetpoint = setpoint;
        }
    }
}

void loop() {
    Control_Surface.loop();
    static Timer<millis> timer = 5;
    if (timer) {
        readFromSlave();
        sendToSlave();
    }
}

6971D6A9-AD8E-4026-BBCF-4FCE660A3AB0

tttapa commented 2 months ago

To get actual MIDI output, you'll need to replace USBDebugMIDI_Interface midi by another MIDI interface, e.g. USBMIDI_Interface midi or HardwareSerialMIDI_Interface midi{Serial}. See https://tttapa.github.io/Control-Surface-doc/Doxygen/d3/df7/midi-tutorial.html for details.

But unless the host is doing stuff other than MIDI routing, you may want to use the WITH_MIDI option in the motor controller: https://tttapa.github.io/Pages/Arduino/Control-Theory/Motor-Fader/Configuration.html#direct-midi-control

(As an aside, it'd be much cleaner to use arrays instead of all the (idx == 0) ? x : (idx == 1) ? y : (idx == 2) ? ...).

Renlong2020 commented 2 months ago

Thank you for your guidance. In a midi controller, how do I customize this if instead of sending and receiving pitchbend, I want to send and receive B0 controllers? Because sendr is bound to the pitchbend send function. Is there an example of custom sending

tttapa commented 2 months ago

If you want to send/receive Control Change messages (which have status byte 0xB0), you can use the sendControlChange and onControlChange functions. See e.g. https://tttapa.github.io/Control-Surface-doc/Doxygen/d5/d35/Send-All-MIDI-Messages_8ino-example.html and https://tttapa.github.io/Control-Surface-doc/Doxygen/da/d27/MIDI-Input-Fine-Grained-All-Callbacks_8ino-example.html.

Specifically, you would have to change the following lines:

Convert to a 7-bit value, use sendControlChange, and change the MIDIAddress appropriately. https://github.com/tttapa/Control-Surface-Motor-Fader/blob/fe8a54f912ea0bac2d75647e6f40e23807e00823/Motor-Controller/main.cpp#L281-L282

Use MIDIMessageType::CONTROL_CHANGE, use msg.getData1() instead of the channel to get the fader index, and use msg.getData2() to get the target position. https://github.com/tttapa/Control-Surface-Motor-Fader/blob/fe8a54f912ea0bac2d75647e6f40e23807e00823/Motor-Controller/main.cpp#L288-L290

Keep in mind that control change messages are only 7-bit (pitch bend is 14-bit, of which usually only 10 bits are used), so you may need to change some other parts of the code, use bit shifts >> or AH::increaseBitDepth to convert between them.

In the MIDI controller sketch, you can use ContinuousCCSender and CCValue. https://github.com/tttapa/Control-Surface-Motor-Fader/blob/fe8a54f912ea0bac2d75647e6f40e23807e00823/MIDI-Controller/MIDI-Controller.ino#L15-L16

Renlong2020 commented 2 months ago

Hello, I have modified the motormain file and mid controller file according to your guidance, and can barely debug them. cc midi command can be sent when the fader is moved. However, when the device receives cc command, the fader can't be moved, because the command here is a little special. Can you sample the code? Because I still don't know enough about the control_surface library code to know its underlying logic. midi protocol for communication between controller and host software, template is b0 63 00 Fixed code b0 62 01 Fader 1, when data2 is 02, corresponds to fader 2, there are 32 faders, 01-32 b0 06 xx msb b0 26 xx lsb Looking forward to your reply