Giter VIP home page Giter VIP logo

Comments (9)

oscarosky avatar oscarosky commented on May 24, 2024 3

It would be great! I think it's very good what you've written so far ..

from control-surface.

tttapa avatar tttapa commented on May 24, 2024 3

For future reference:
Motorized faders are now supported, you can find the documentation at https://tttapa.github.io/Pages/Arduino/Control-Theory/Motor-Fader and the code in tttapa/Control-Surface-Motor-Fader.

from control-surface.

tttapa avatar tttapa commented on May 24, 2024

Yes, but it requires specialized timing, and complicated control systems. That's why I didn't include it with the library (yet).

from control-surface.

oscarosky avatar oscarosky commented on May 24, 2024

I am writing a code to incorporate the motorized faders and a bridge of meters powered by the Arduino PWM outputs. I have modified a code written in 2012 by Cody Hazelwood and updated in 2016 by Guerau Pasola and Adrian Salvador. But the original code only controlled one fader.
Everything seems to work correctly although not fluid enough as it should. :(

Your library seems very good to me and I would like to use it for the rest of the controls, but I have not been here for a long time and I do not know how to do it.
I thought that when you have time maybe you can help me solve this.

Thank you.

#include <CapacitiveSensor.h>                  // Biblioteca para la sensibilidad táctil del fader
#include <MIDI.h>                                     // Biblioteca para recibir mensajes MIDI
MIDI_CREATE_DEFAULT_INSTANCE();
#define PitchBend 0xE0                             // Byte de estado para control de faders
#define AfterTouchChannel 0xD0              // Byte de estado para control de medidores
#define N 4                                               // Especifica aquí el numero de faders (max.8)
 
// Asignación de Pins en Arduino (MEGA)

const int motorUp[] = {23, 25, 27, 29, 31, 33, 35, 37};        // Controla H-Bridge para hacer que el motor ascienda
const int motorDown[] = {22, 24, 26, 28, 30, 32, 34, 36};      // Controla H-Bridge para hacer que el motor descienda
const int meterPin [] = {2, 3, 4, 5, 6, 7, 8, 9};              // pines PWM que se van a utilizar para los medidores

// Entradas 

const int fader[] = {0, 1, 2, 3, 4, 5, 6, 7}; // Pin de entrada analogica del fader relativo a GND
const int touchSend = 10;                     // Pin de envio para circuito de detección de capacitancia
const int touchReceive = 11;                  // Pin de recepción para circuito de detección de capacitancia

// Variables

double faderMax[N];                            // Valor leído por la posición máxima del fader (0-1023)
double faderMin[N];                            // Valor leído por la posición mínima del fader (0-1023)
double posicion[N];
int faderChannel[N];                           // Canal MIDI del fader (desde 1-8)
int returnValue[N];

int meterChannel  = 0 ;                        // Canal MIDI del medidor
int valueAT = 0;                               // Valor de lectura desde DAW
int valueMeter = 0;                            // Valor de salida para PWM

bool touched = false;
bool positionUpdated[N];

CapacitiveSensor touchLine = CapacitiveSensor(touchSend, touchReceive);

void setup() {  
  MIDI.begin(MIDI_CHANNEL_OMNI);               // Recibe mensajes en todos los canales MIDI
//  Serial.begin(115200);                        // habilitar esta linea para testear a traves de Hairless MIDI
 
  for (int i = 0; i < N; i++) {
    pinMode (motorUp[i], OUTPUT);
    pinMode (motorDown[i], OUTPUT); 
    faderMax[i] = 0 ;
    faderMin[i] = 0 ;
    posicion[i] = 0 ;
    faderChannel[i] = (i+1);
    positionUpdated[i] = false ;
    analogWrite (meterPin[i], valueMeter);     // Puesta a cero de medidores
  }
   calibrateFader();  
}

void loop() { 

  for (int i = 0; i < N; i++) {

    /* Si hay un mensaje MIDI en espera, y corresponde al actualmente seleccionado
      fader, y es un mensaje PitchBend (usado para controlar el fader), luego convierte
      el valor PitchBend y actualizar la posición actual del fader. */
    if (MIDI.read() && MIDI.getChannel() == faderChannel[i] && MIDI.getType() == PitchBend ) {

      /* Mapeo bit a bit para tomar dos valores de 7 bits para PitchBend y convertir a 
        un solo valor de 14 bits. Luego lo convierte en valor entre 0 y 1023
        para controlar el fader */
      int value = (((MIDI.getData2() << 7) + MIDI.getData1()) * 0.0625);
      updateFader(value, i);
      }
   
  checkTouch(i);                        //Comprueba si el fader está siendo tocado  
 
    if (!positionUpdated[i]) {          //Si se ha tocado el fader, necesita actualizar la posición en el DAW
      updateFaderMidi(i);      
      positionUpdated[i] = true;
    }

    if (MIDI.read() && MIDI.getType() == AfterTouchChannel && ((MIDI.getData1() & 0x70) >> 4) == i) {
    // meterChannel = (MIDI.getData1() & 0x70) >> 4;
    valueAT = MIDI.getData1() & 0x0F;                     // Extrae el valor necesario del mensaje MIDI
    valueMeter = map(valueAT, 0, 13, 0, 190);             // Transformar los valores recibidos por el DAW para la salida PWM
    analogWrite (meterPin[i], valueMeter);                // Emite el valor por PWM hacia el filtro RC.
    }    
  }
}

void checkTouch(int i) {                // Comprueba el sensor capacitivo,
                                        // el valor 700 es arbitrario y puede ser cambiado
                                        //          |||
  if (!touched && touchLine.capacitiveSensor(30) >= 700) {  
    touched = true;                                         // Si se ha tocado .. 
                                                            // Envia mensaje Touch on  al DAW 
    Serial.write(0x90);
    Serial.write(0x67 + faderChannel[i]);
    Serial.write(0x7f);
  }
  else if (touched && touchLine.capacitiveSensor(30) < 700) {
    touched = false;                                        // Si se ha dejado de tocar ..
                                                            // Envia mensaje Touch Off al DAW
    Serial.write(0x90);
    Serial.write(0x67 + faderChannel[i]);
    Serial.write((byte) 0x00);
  }
  if (touched) {                                            // 
    positionUpdated[i] = false;
  }
}

void updateFaderMidi(int i) {                   // Envia posicion del fader al DAW
 
    int volumen = faderPosition(i);
    byte channelData = 0xE0 + (faderChannel[i] - 1);

     // MIDI Message:
     Serial.write(channelData);                 // E(PitchBend) Channel (0-9)
     Serial.write(volumen & 0x7F);              // Bits de datos menos significativos
     Serial.write((volumen >> 7) & 0x7F);       // Bits de datos más significativos
}

//  Muever el fader a una posición específica entre 0-1023 si aún no está allí

void updateFader(int valuepos ,int i ) {                                   // Envia posicion del DAW al fader
  posicion[i] = valuepos;
  if (posicion[i] < analogRead(fader[i]) - 10 && posicion[i] > faderMin[i] && !touched) {
      digitalWrite(motorDown[i], HIGH);
      while (posicion[i] < analogRead(fader[i]) - 10 && !touched) {};      // Bucles hasta que el motor se mueve
      digitalWrite(motorDown[i], LOW);
  }
  else if (posicion[i] > analogRead(fader[i]) + 10 && posicion[i] < faderMax[i] && !touched) {
      digitalWrite(motorUp[i], HIGH);
      while (posicion[i] > analogRead(fader[i]) + 10 && !touched) {};      // Bucles hasta que el motor se mueve
      digitalWrite(motorUp[i], LOW);
  }
}
int faderPosition(int i) {   
      posicion[i] = analogRead(fader[i]);
      
  if (posicion[i] <= faderMin[i]) {
      returnValue[i] = 0;
  }
  else if (posicion[i] >= faderMax[i]) {
      returnValue[i] = 16383;
  }
  else {
      returnValue[i] = ((float)(posicion[i] - faderMin[i]) / (faderMax[i] - faderMin[i])) * 16383;
  }
  return returnValue[i];      
}

void calibrateFader() {
  for (int i = 0; i < N; i++) {
                                                 // Enviar faders a la parte superior y leer las posiciónes máximas
    digitalWrite(motorUp[i], HIGH);
    delay(300);
    digitalWrite(motorUp[i], LOW);
    faderMax[i] = analogRead(fader[i]) - 5;
  }
  for (int i = 0; i < N; i++) { 
                                                 // Enviar faders a la parte inferior y leer las posiciónes mínimas
    digitalWrite(motorDown[i], HIGH);
    delay(300);
    digitalWrite(motorDown[i], LOW);
    faderMin[i] = analogRead(fader[i]) + 5;
  }
}

20180606_135932
20180602_155520
20180603_020346

from control-surface.

tttapa avatar tttapa commented on May 24, 2024

Looking good!

Like I said in the other issue, I currently have exams, so there's not much I can do until early July.

I have tried the same (or similar) motorized fader sketch, but I wasn't happy with the result, for multiple reasons:

  • The control system is very primitive, it's just "turn the motor all the way on until you reach your target value minus 10". It's not accurate.
  • The while loops of the fader movement block the entire system, so it doesn't react to MIDI in or button presses, etc.
  • "Smooth" fader curves aren't smooth, because of the terrible control system.

I've done some research into PID controllers, and that seems promising. However, I can't get them 100% smooth. The PWM power isn't linear at all, making it many times harder (especially at high frequencies, you don't want them in the audible spectrum, especially near audio equipent). You also need to call the control functions at a regular interval, which requires the use of timer interrupts. All tuning depends on the hardware it is used on, so it's really hard to come up with a "one-size-fits-all" solution to distribute with this library.

If I manage to do it, I'll probably only support Teensy boards, because it is a pain to support the right PWM and Timer settings on AVR, while Teensy comes with easily portable function for all of this. I don't expect anyone to run such a "heavy" project on an AVR anyways.

I also have some updates (almost) ready for the MIDI Controller library, improving filtering of the analog inputs. If you're having problems with that, keep an eye out for version 3.1.0 somewhere in the first week of July.

from control-surface.

oscarosky avatar oscarosky commented on May 24, 2024

I agree with you.
The behavior of the system gets worse as new elements are added. Maybe the control of the faders needs a dedicated microcontroller.
We will also talk in a few weeks about the level meters on PWM.
A greeting.

from control-surface.

masydoblig avatar masydoblig commented on May 24, 2024

i was thinking that also if we put the faders on a dedicated controller

here is the design i'm working on for my studio. It is for Cubase.
i the code works really well as a generic controller

would love to get 8 motor faders working from one board so i can program them in banks of 8

long fader done

from control-surface.

masydoblig avatar masydoblig commented on May 24, 2024

Any progress with the faders ???

from control-surface.

tttapa avatar tttapa commented on May 24, 2024

I posted my code here: https://github.com/tttapa/MotorFader

I'm not satisfied with the results, and it's a lot of work to integrate it with the Control Surface library, and I don't have the time. I also have to add a Kalman filter and a better way to tune the PID controller dynamically.

from control-surface.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.