Teensy 3.6 controlled motorfader panel

Gerrit

Well-known member
Using a Teensy 3.6 to control 8 ALPS motorfaders:


L293B H-bridges are used to drive the motors. The fader wipers and touchtracks are connected directly to the Teensy. Each faders has it's own PID control using 12 bit PWM at 14648.437 Hz. The ResponsiveAnalogRead library is used for the analog inputs, notice how stable the values are. Separate timers are used for the analogRead and touchRead:
Code:
elapsedMicros sinceFaderRead;                         // timer for fader check
unsigned int  faderReadInterval=500;                  // interval in microseconds for checking fader position(update)
elapsedMicros sinceTouchRead;                         // timer for touch read
unsigned int  touchReadInterval=5000;                 // interval in microseconds for reading fader touch

A second Teensy is reading the values from the faders via I2C and shows the raw values on the LED displays using the LedDisplay library.

Fader panel bottom view:

Zeus-SPS-8-fader-panel.jpg

The plan is to create a MIDI step & pattern sequencer with presets and this is an important first step. The code will of course be available when finished, in the meantime I'll be happy to provide snippets if somebody is interested.
A very big Thank You to everybody involved with the Teensy, Arduino and the great libraries that are available!

Kind regards,

Gerrit
 
Hello,

can you give us the complete Sketch? I need this functions for my project... Thanks

As I said, the code is not finished. It is full of debugging stuff, parts of examples and half-baked ideas so I'd rather not publish it as is.

What functions do you need and what is the context? Maybe I can provide pieces of code or functions. I'm currently working on controlling the panel via I2C commands, I still need to figure out want kind of little protocol I need (I'm using the advanced examples from the new I2C lib as a starting point) to be able to implement the functionality I want.
What you see in the video is what I call 'link mode', all untouched faders follow the one that is touched. This now works only for this panel but should work for multiple panels. The other function would be a simple preset recall. Based on my experiments it seems like a good idea to implement variable PID tuning for supporting these two different operating modes. As soon as I have figured this out and got it working I will publish the code.

Kind regards,

Gerrit
 
Thanks for your quick reply.

I search a solution to controll my fader like this Youtube Video


Later, I would like to replace the potentiometer with a readout value of 0-1023. But first I need it like this video.

I have the same H-Bridge like you.

I have connect it like this picture:
Motorfader-Arduino-Schaltung.jpg

And I used this sketch...

Code:
// pins
int motorA = 5;
int motorB = 6;
int enablePin = 3;
int button = 8;
int poti = 0;

// config
int target[] = {800, 100, 1000, 0, 500};
int targetsTotal = 5;
int theThreshold = 30;
int movingTimeout = 300;
long myTime = 0;

// programming stuff
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int currentTarget = 0;

void setup() {
  pinMode(enablePin, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop() {
  buttonState = digitalRead(button);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      currentTarget++;
      if (currentTarget > targetsTotal - 1) currentTarget = 0;
      myTime = millis();      
    }
  }

  if (myTime + movingTimeout > millis()) {
    digitalWrite(enablePin, HIGH);
    if (analogRead(poti) > (target[currentTarget] + theThreshold) ) {
      analogWrite(motorA, 255);
      analogWrite(motorB, 0);
    } else if (analogRead(poti) < (target[currentTarget] - theThreshold) ) {
      analogWrite(motorA, 0);
      analogWrite(motorB, 255);
    } else {
      analogWrite(motorA, 0);
      analogWrite(motorB, 0);
    }
  } else {
    digitalWrite(enablePin, LOW);
  }

  lastButtonState = buttonState;
}

When I Push the button the Fader runs..

Video to this project:

https://www.youtube.com/watch?v=GCttn3wnz-Q

Do you have any ideas how i can do it?
 
I don't understand what your problem is. You say the fader runs, is the issue that it doesn't stop? What Teensy do you use? How many faders do you need to control and what else do you expect it to do?

I the first video it is explicitly mentioned that no PID control and no PWM were used. It does look a bit jittery to me and I would like to see what happens if the fader has to hit a target at near maximum distance.

The second video uses a simple approach but the movement is too slow, faders can move much faster but then you run into problems with simple control. Also notice how when the fader is pulled from its positions it flips back with overshoot.

I based my controller on the code in the article PID without a PhD. In stead of structs I used arrays for the implementation:
Code:
// PID arrays
double dState[8];
double iState[8];
double iMin[8];
double iMax[8];
double pGain[8];
double iGain[8];
double dGain[8];
double minUpPWM[8];
double minDownPWM[8];
double plantDrive[8];
double maxD=0.00;       // maximum derivative value for debugging purposes

void UpdatePID(int faderIndex, double faderError, double faderPosition)
{
  double pTerm, dTerm, iTerm, plantDriveInput;
  // calculate the proportional term
  pTerm = pGain[faderIndex] * faderError;   
  // calculate the integral state with appropriate limiting
  iState[faderIndex] += faderError;
  if (iState[faderIndex] > iMax[faderIndex]){
    iState[faderIndex] = iMax[faderIndex];
    }
  else if (iState[faderIndex] < iMin[faderIndex]){
    iState[faderIndex] = iMin[faderIndex];
  }
  iTerm = iGain[faderIndex] * iState[faderIndex];  // calculate the integral term
  dTerm = dGain[faderIndex] * (faderPosition - dState[faderIndex]);
  if (abs(faderPosition - dState[faderIndex]) > maxD){
    maxD=abs(faderPosition - dState[faderIndex]);
  }
  dState[faderIndex] = faderPosition;

  plantDriveInput = pTerm + iTerm - dTerm;
  if (plantDriveInput > 4096) {
    plantDriveInput=4096;
  }
    if (plantDriveInput < -4096) {
    plantDriveInput=-4096;
  }
  if (plantDriveInput > 0 && plantDriveInput < minUpPWM[faderIndex]){
    plantDriveInput=0;
  }
  if (plantDriveInput < 0 && -plantDriveInput < minDownPWM[faderIndex]){
    plantDriveInput=0;
  }
  plantDrive[faderIndex]=plantDriveInput;
}

The code allows for individual tuning of the PID parameters for each fader. To make use of this I would have to figure out some kind of calibration procedure. The PID parameters are set in the setup routine:
Code:
  // set PID tuning parameters
  for (int i=0;i<8;i++){
    pGain[i]=20.00;
    iGain[i]=0.5;
    dGain[i]=40.00;
    iMin[i]=-4000;
    iMax[i]=4000;
    minUpPWM[i]=100;
    minDownPWM[i]=100;
  }

In the main loop the elepasedMicros timer updates the PIDs:

Code:
  // check elapsedMicros and millis timers
  // faders
  if (sinceFaderRead >=faderReadInterval) {
    sinceFaderRead = sinceFaderRead-faderReadInterval;
    readFaders();
    if (linkMode && faderTouchCount==1) {
      // first set linkValue
      for (int i=0;i<8;i++){
        if (faderTouched[i]){
          linkValue=faderValue[i];
        }
      }
      for (int i=0;i<8;i++){
        UpdatePID(i,linkValue-faderValue[i],faderValue[i]);
      }
      for (int i=0;i<8;i++){
        if (!faderTouched[i]){
          if(plantDrive[i]>0){
            analogWrite(faderMotorDownPin[i],0);
            analogWrite(faderMotorUpPin[i],plantDrive[i]);
          } else if (plantDrive[i] <=0){
            analogWrite(faderMotorUpPin[i],0);
            analogWrite(faderMotorDownPin[i],-plantDrive[i]);
          }
        } 
      }
    } else if(linkMode && faderTouchCount==0){
      for (int i=0;i<8;i++){
        analogWrite(faderMotorDownPin[i],0);
        analogWrite(faderMotorUpPin[i],0);
      }
    }
  }

Please beware that programming in C is new to me so there's always the chance I made some rookie mistake somewhere and I'm certain the code can be optimised. I also tried the PID library but wasn't able to achieve control. By creating my own implementation based on aforementioned article I got a much better understanding of what PID is about and why/when you need it. The speed and capabilities of the Teensy 3.6 allow for the implementation of sophisticated control so why not do it? Motorfaders are expensive parts so the cost of a Teensy 3.6 is not an issue, at least not in the context of DIY.

Kind regards,

Gerrit
 
On Teensy 3.6 only float is done by hardware. Unless you absolutely need the higher precision of double, you can run this code much faster if you change all the double variables to float.
 
On Teensy 3.6 only float is done by hardware. Unless you absolutely need the higher precision of double, you can run this code much faster if you change all the double variables to float.

Thanks for the tip, I'll change the code. It could be that even int is sufficient for this purpose, I'd have to try that as I do not have the experience to judge this up front. The setup is almost ready for testing the full I2C communication. After I have this up and running I planned on further tuning the PID parameters.

Kind regards,

Gerrit
 
I've got the I2C communication working, here's a video showing the cycling through several preset values. The target values for the faders are 10, 1000, 500 and 550. Large and small steps were deliberately chosen to show the response.


I think the performance is pretty good, if I dare say so myself, the faders can move very fast and there's practically no overshoot even at high speed. To improve on this I think it will be necessary to come up with a calibration function to adjust the PID tuning for each fader individually.

On button click a single message of 18 bytes is sent from the master to the panel:

Code:
void sendFaderCommand(byte mode){
  size_t idx;
  faderTargetData[16]=0;
  for (int i=0;i<8;i++){
    // split Target integers over two bytes in array
    faderTargetData[(i*2)]=(faderTarget[i] >> 8) & 0xFF;
    faderTargetData[(i*2)+1]=faderTarget[i] & 0xFF;
    // fill last byte in array with faderMove boolean array
    faderTargetData[16] |= faderMove[i] << i;
  }
  // Transmit to Slave
  Wire.beginTransmission(PANEL_ADDR);   // Slave address
  // Send mode
  Wire.write(mode);
  // Send target data
  for(idx = 0; idx <= MESSAGE_LEN; idx++) // Write data to I2C Tx buffer
      Wire.write(faderTargetData[idx]);
  Wire.endTransmission();           // Transmit to Slave
}

The first byte sets the operating mode: TARGET or FOLLOW. The intention is to allow for separate PID parameter tuning, now the difference is that with TARGET mode the PID state (integral & derivative) is cleared with each command. The PID control will time-out after the last command.
I removed the PWM threshold from the PID controller function , introducing a threshold in the control actually interferes with the PID algorithm.

Here's the complete code for the panel:
Code:
/* 
  Zeus Commander Controller Series
  I2C controlled motorfader octet

  Full PID motor control supporting two operating modes:
  TARGET  for fast preset recall
  FOLLOW  for slow to fast following of values 

  This code expands on the examples provided with the i2c_t3 library for the I2Ccommunication
  
  This code is in the public domain.
*/
#include <i2c_t3.h>
#include <ResponsiveAnalogRead.h>

// PID arrays
float dState[8];
float iState[8];
float iMin[8];
float iMax[8];
float pGain[8];
float iGain[8];
float dGain[8];
float plantDrive[8];
float maxD=0.00;       // maximum derivative value for debugging purposes

void UpdatePID(int faderIndex, float faderError, float faderPosition)
{
  float pTerm, dTerm, iTerm, plantDriveInput;
  // calculate the proportional term
  pTerm = pGain[faderIndex] * faderError;   
  // calculate the integral state with appropriate limiting
  iState[faderIndex] += faderError;
  if (iState[faderIndex] > iMax[faderIndex]){
    iState[faderIndex] = iMax[faderIndex];
    }
  else if (iState[faderIndex] < iMin[faderIndex]){
    iState[faderIndex] = iMin[faderIndex];
  }
  iTerm = iGain[faderIndex] * iState[faderIndex];  // calculate the integral term
  dTerm = dGain[faderIndex] * (faderPosition - dState[faderIndex]);
  if (abs(faderPosition - dState[faderIndex]) > maxD){
    maxD=abs(faderPosition - dState[faderIndex]);
  }
  dState[faderIndex] = faderPosition;

  plantDriveInput = pTerm + iTerm - dTerm;
  if (plantDriveInput > 4096) {
    plantDriveInput=4096;
  }
    if (plantDriveInput < -4096) {
    plantDriveInput=-4096;
  }
  plantDrive[faderIndex]=plantDriveInput;
}

elapsedMicros sinceFaderRead;                         // timer for fader check
unsigned int  faderReadInterval=1000;                 // interval in microseconds for checking fader position(update)
elapsedMicros sinceTouchRead;                         // timer for touch read
unsigned int  touchReadInterval=5000;                 // interval in microseconds for reading fader touch
elapsedMillis sinceLastCommand;                       // timer for time-out of PIF after last command
unsigned int  commandTimeOutInterval=500;             // interval for PID time-out in milliseconds
int     faderWiperPin[8]={32,31,39,20,21,15,65,64};   // analog in pin for fader wipers
int     faderTouchPin[8]={1,0,16,17,18,19,22,23};     // touchRead pins for fader touch
int     faderMotorUpPin[8]={29,9,7,5,3,14,36,38};     // motor up PWM pin
int     faderMotorDownPin[8]={30,10,8,6,4,2,35,37};   // motor down PWM pin
int     faderValue[8];                                // fader value ranging 0 to 1023
int     faderTarget[8];                               // fader target value ranging 0 to 1023
int     faderTouch[8];                                // fader touch reading
boolean faderPidOn[8];                                // status of PID
int     faderTouchThreshold=3000;                     // threshold value for touchRead
boolean faderTouched[8];                              // boolean indicating if fader is touched

ResponsiveAnalogRead analog[8]{ResponsiveAnalogRead(32, true),ResponsiveAnalogRead(31, true),
                               ResponsiveAnalogRead(39, true),ResponsiveAnalogRead(20, true),
                               ResponsiveAnalogRead(21, true),ResponsiveAnalogRead(15, true),
                               ResponsiveAnalogRead(65, true),ResponsiveAnalogRead(64, true)};

// I2C communication
// Command definitions
#define TARGET    0x10              // All faders to target value as fast as possible. PID state is cleared with each command.
#define FOLLOW    0x20              // Faders follow value, last byte in message is used to determine which motors should move.
                                    // PIDs will time-out after last command.

// Function prototypes
void receiveEvent(size_t count);
void requestEvent(void);
#define PANEL_ADDR 0x66              // I2C address, should be selectable by jumper using leftover pins.
#define MESSAGE_LEN 17
byte faderValueData[MESSAGE_LEN];    // 16 bytes for values, 1 byte for touch
byte faderTargetData[MESSAGE_LEN];   // 16 for target values, 1 byte for indicating which faders should be moved.
volatile uint8_t received;
volatile uint8_t cmd;
byte operatingMode = TARGET;


void setup()
{  
  
  //initialize faders and analog reference 
  analogReference(EXTERNAL);
  analogWriteResolution(12);
  for (int i=0; i<8; i++){
    pinMode(faderMotorUpPin[i], OUTPUT);
    pinMode(faderMotorDownPin[i], OUTPUT);
    analogWriteFrequency(faderMotorUpPin[i],14648.437);  // 14648.437 ideal frequency for 180MHz 12bit PWM
    analogWriteFrequency(faderMotorDownPin[i],14648.437);  //14648.437 ideal frequency for 180MHz 12bit PWM
    faderTouched[i]=false;
    faderValueData[i]=0;
    faderTarget[i]=500;
    faderPidOn[i]=false;
  }    
       
  readFaders();
  // set PID tuning parameters
  for (int i=0;i<8;i++){
    pGain[i]=10;
    iGain[i]=1;
    dGain[i]=50.00;
    iMin[i]=-1500;
    iMax[i]=1500;
  }
  
  // Setup for Slave mode pins 33/34, external pullups, 400kHz
  Wire.begin(I2C_SLAVE, PANEL_ADDR, I2C_PINS_33_34, I2C_PULLUP_EXT, 400000);
  // register events
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  cmd = 0;    // incoming command operating mode
}

void loop()                     
{
  // check elapsedMicros and millis timers
  // faders
  if (sinceFaderRead >=faderReadInterval) {
    sinceFaderRead = sinceFaderRead-faderReadInterval;
    readFaders();
    
    // always update PID for timing consistency
    for (int i=0;i<8;i++){
        UpdatePID(i,faderTarget[i]-faderValue[i],faderValue[i]);
      }
      
    // loop through faders and move where necessary
    for (int i=0;i<8;i++){
      if (!faderTouched[i] && faderPidOn[i]){
        if(plantDrive[i]>0 && faderValue[i] <=1022){
          analogWrite(faderMotorDownPin[i],0);
          analogWrite(faderMotorUpPin[i],plantDrive[i]);
        } else if (plantDrive[i] <=0 && faderValue[i] >=1){
          analogWrite(faderMotorUpPin[i],0);
          analogWrite(faderMotorDownPin[i],-plantDrive[i]);
        }
      } 
      else if(!faderPidOn[i]){
          analogWrite(faderMotorDownPin[i],0);
          analogWrite(faderMotorUpPin[i],0);
        }
    }
  }
  
  //  separate touchRead timer 
  if (sinceTouchRead >= touchReadInterval){
    sinceTouchRead = sinceTouchRead - touchReadInterval;
    readTouch();
  }
  
  // command time-out  
  if (sinceLastCommand >= commandTimeOutInterval){
    for (int i=0;i<8;i++){
      faderPidOn[i]=false;
    }
    sinceLastCommand = 0;
  }
  
}

// read fader analog values and update faderValue array
void readFaders() {
  for (int i=0; i<8; i++) {
    analog[i].update();
    faderValue[i] = analog[i].getValue();
  } 
}

// read fader touch
void readTouch() {
  for (int i=0; i<8; i++) {
    faderTouch[i]= touchRead(faderTouchPin[i]);
    if (faderTouch[i]>faderTouchThreshold){
      faderTouched[i]=true;
    } else if (faderTouch[i]<=faderTouchThreshold){
      faderTouched[i]=false;
    }
  } 
}

// handle Rx Event (incoming I2C data)
void receiveEvent(size_t count) {
  size_t idx;
  int incomingTargetValue[8];
  boolean incomingFaderMove[8];
  if(count)
  {
    // grab command
    cmd = Wire.readByte();
    switch(cmd)
    {
    case TARGET:
      if (operatingMode==FOLLOW){
        // set PID tuning parameters
//        for (int i=0;i<8;i++){
//          pGain[i]=20.00;
//          iGain[i]=0.5;
//          dGain[i]=40.00;
//        }
        operatingMode=TARGET;
      }
      break;
    case FOLLOW:
      if (operatingMode==TARGET){
        // set PID tuning parameters
//        for (int i=0;i<8;i++){
//          pGain[i]=20.00;
//          iGain[i]=0.5;
//          dGain[i]=40.00;
//        }
        operatingMode=FOLLOW;
      }
      break;
    }
    idx = 0;
    while(Wire.available()) faderTargetData[idx++] = Wire.readByte();
          
    // Process data
    for (int i=0;i<8;i++){
      // combine bytes back to integers and put in temporary array
      incomingTargetValue[i]= faderTargetData[(i*2)];
      incomingTargetValue[i]= incomingTargetValue[i] << 8 | faderTargetData[(i*2)+1];
      // fill faderPidOn boolean array with last byte
      incomingFaderMove[i] = 1 & faderTargetData[16] >> i;
      // clear PID states if PID is switched on or if mode is TARGET
      if ((incomingFaderMove[i] && faderPidOn[i]!=incomingFaderMove[i]) || operatingMode==TARGET){
        dState[i]=faderValue[i]; 
        iState[i]=0; 
      }
      faderPidOn[i]=  incomingFaderMove[i];
      // update fader target
      faderTarget[i]=incomingTargetValue[i];
    }
    // reset timer
    sinceLastCommand=0;
  }
}

// handle Tx Event (outgoing I2C data)
void requestEvent(void)
{
  faderValueData[16]=0;
  for (int i=0;i<8;i++){
    // split value integers over two bytes in array
    faderValueData[(i*2)]=(faderValue[i] >> 8) & 0xFF;
    faderValueData[(i*2)+1]=faderValue[i] & 0xFF;
    // fill last byte in array with touch boolean array
    faderValueData[16] |= faderTouched[i] << i;
  }
  Wire.write(faderValueData, MESSAGE_LEN); // fill Tx buffer (send full mem)
}

Next up is the implementation of FOLLOW mode over I2C, this should not require any changes to the panel code other than PID tuning.

Any suggestions for improvements are very much appreciated.

Kind regards,

Gerrit
 
Thanks for the tip, I'll change the code. It could be that even int is sufficient for this purpose, I'd have to try that as I do not have the experience to judge this up front.

On Teensy 3.5 & 3.6, float and integers are approximately the same speed. Only double is slow.

There are some ways for integer math to be significantly faster, but they involve extremely difficult optimization techniques. Usually that level of effort isn't worthwhile except for special signal processing libraries.
 
On Teensy 3.5 & 3.6, float and integers are approximately the same speed. Only double is slow.

There are some ways for integer math to be significantly faster, but they involve extremely difficult optimization techniques. Usually that level of effort isn't worthwhile except for special signal processing libraries.

Thank you, good to know.

King regards,

Gerrit
 
Hello,
I try to build a surface contrôle with motorfader.
Can you post the schematic of your circuit, it will help me.
Thanks
 
Hello,
I try to build a surface contrôle with motorfader.
Can you post the schematic of your circuit, it will help me.
Thanks

To drive the motors I used a L293B chip and implemented the schematic in the datasheet:

L293B-schematic.png

You have to copy the schematic on the left side to the right. I used 1N4007 diodes, which probably overkill, which I had a bunch of. As you can see in an earlier post everything is build on stripboard so there is no schematic of the whole thing. The connection are shown in this pinout diagram:

MotorfaderPanelTeensy.jpg

As an external voltage reference I used an AD780, this is definitely overkill but it was the only one I could find that would put out 3V, work with 5V and was through hole. The external reference may not be necessary but I thought it was better to be safe than sorry. The AD780 is connected as shown in the datasheet:

AD780-schematic.png

I build this panel for use in a, yet to develop, midi sequencer because as far as I know such a device does not exist. If you're building a standard DAW controller surface, I would think twice before starting such a project. It will be next to impossible to build something for less than what is commercially available.

Kind regards,

Gerrit
 
Thank you for the quick reply.
I dont want to make a complete DAW, just motorfaders and some buttons, just for fun.
I never used external voltage reference before, you connect the AD780's Vout to Teensy AREF and to the + pin of the fader ?
Do you connect AGND to GND ?
Last question :
What power supply do you use ? for motors and Teensy ?

Thank you !
 
Thank you for the quick reply.
I dont want to make a complete DAW, just motorfaders and some buttons, just for fun.
I never used external voltage reference before, you connect the AD780's Vout to Teensy AREF and to the + pin of the fader ?
Do you connect AGND to GND ?
Last question :
What power supply do you use ? for motors and Teensy ?

Thank you !

Just for fun is a perfectly valid reason as far as I'm concerned :)

As for your questions:

Yes, the AD780 out is connected to the Teensy AREF and + pin of the fader. Remember to first set the reference to external in your code before connecting the external reference.
Yes, AGND is connected to GND

I use a 10V 50W supply for the faders and a 5V supply for the Teensy (DC-DC converter of the 10V supply). I did not yet check the power supply lines with a scope to see if there's any interference, it could be a good idea to use a completely separate 5V supply for the Teensy. I measured a peak current of just under 4A when all 8 faders start moving at full speed.

Kind regards,

Gerrit
 
I am working on a similar project and this is very helpful. I am fairly new to Arduino and have yet to use teensy and have extensive C/C++ experience. But in reading the code listed above I understand it pretty well but am confused by the analog input pins used. The code indicates fader 5 wiper is pin 21 , fader 6 wiper is 15 OK. But fader 7 is pin 65 and fader 8 is pin 64. The pin diagram shows fader 7 on pin 21 which is also fader 5. Fader wiper 8 is pin 64 but the diagrams says fader 8 is pin 22 which is touch 7.

It looks to me like pin 22 and 23 are dual use but you do not specify any external logic to manage this. How can you connect 2 faders to the same pin or a touch and fader to one pin?

Maybe this is me being a teensy newbe, but how does software pin 64 and 65 map to physical pin 22 and 21?

Thanks,
Mark
 
I am working on a similar project and this is very helpful. I am fairly new to Arduino and have yet to use teensy and have extensive C/C++ experience. But in reading the code listed above I understand it pretty well but am confused by the analog input pins used. The code indicates fader 5 wiper is pin 21 , fader 6 wiper is 15 OK. But fader 7 is pin 65 and fader 8 is pin 64. The pin diagram shows fader 7 on pin 21 which is also fader 5. Fader wiper 8 is pin 64 but the diagrams says fader 8 is pin 22 which is touch 7.

It looks to me like pin 22 and 23 are dual use but you do not specify any external logic to manage this. How can you connect 2 faders to the same pin or a touch and fader to one pin?

Maybe this is me being a teensy newbe, but how does software pin 64 and 65 map to physical pin 22 and 21?

Thanks,
Mark

Fader 7 and 8 in the diagram refer to the inner pins on the teensy next to the ones on the edge (22 and 21), these inner pins have number 65 and 64.

Kind regards,

Gerrit
 
Fader 7 and 8 in the diagram refer to the inner pins on the teensy next to the ones on the edge (22 and 21), these inner pins have number 65 and 64.

Kind regards,

Gerrit

Thanks Gerrit. Been away for a while and am not working on this again. I am using motorized faders removed from a tascam dm-24. Not sure what they are. I decided to us a teensy 3.5 but I want to control more faders so I am using a PCA9685 pulse with modulator board running on the i2s bus. Each board controls 16 pwm pins. I plan on controlling 20 faders on a single teensy(without touch) with 3 of these boards daisy chained . Initial testing and initial pid tuning looks good - sending midi over usb both ways with 1 fader.

My final project I plan on having 34 faders with 4 buttons with leds on each (total of 128 buttons and 128 leds) using 2 teensies. I will update occasionally as I make progress.

Mark
 
Thanks Gerrit. Been away for a while and am not working on this again. I am using motorized faders removed from a tascam dm-24. Not sure what they are. I decided to us a teensy 3.5 but I want to control more faders so I am using a PCA9685 pulse with modulator board running on the i2s bus. Each board controls 16 pwm pins. I plan on controlling 20 faders on a single teensy(without touch) with 3 of these boards daisy chained . Initial testing and initial pid tuning looks good - sending midi over usb both ways with 1 fader.

My final project I plan on having 34 faders with 4 buttons with leds on each (total of 128 buttons and 128 leds) using 2 teensies. I will update occasionally as I make progress.

Mark

That's an elaborate setup. Are you sure you can do without touch sensing? How are you going to prevent the fader working against the user? Also I find it important to be able to set a value without moving the fader.

I'm currently working on my DAW plugin controller. The motor faders are on the back-burner for now, I will get back to that when my I finished the controller.

Kind regards,

Gerrit
 
I may add touch in the future. But I will be using the this for live mixing console that does not need automation. Motor faders will be used for total recall of snap shots and for switching between fader layers. I have used Tascam DM-24 (touch sensitive), Yamaha Promix-01(not touch sensitive) and Behringer BCF2000(not touch sensitive) as control surfaces for this and touch sensitivity was never an issue either way. Now if I decide to use time code synchronization for complex shows or use it as a DAW I will definitely need it. But for now it does not matter.
 
Making progress. I have tested 17 motor faders, 18 rotary encoders with push buttons and 24 push buttons with leds. Will be expanding to 96 buttons with leds. Then with a second teensy will control 16 more faders with 33 rotary encoders. Probably take me a couple more months to complete. Using the faders, buttons and metal work from 2 (junked out) dm-24's.
 
Making progress. I have tested 17 motor faders, 18 rotary encoders with push buttons and 24 push buttons with leds. Will be expanding to 96 buttons with leds. Then with a second teensy will control 16 more faders with 33 rotary encoders. Probably take me a couple more months to complete. Using the faders, buttons and metal work from 2 (junked out) dm-24's.
Good to hear you're making progress. I would be interested to know what kind of precision and repeatability you're getting with the motorfaders.
 
hi gerrit
im trying to build this project for 8 fader MIDI controlling for now i have teensy connected to 1 Alps 100mm fader for test
im using only one teensy for usb midi controlling andi dont know how write a code but i try to use some of codyfaders code from github and to make some changes. for now i made midi in and out work but the motor is not responding well (going forever to up or down way)
i can see in ur video thaht te pid controling is great.
do u have this code with usbmidi controlling?
or may u have any tip for me how can i add usbmidi controling to your pid controlling code?
tnx
rota
 
hi gerrit
im trying to build this project for 8 fader MIDI controlling for now i have teensy connected to 1 Alps 100mm fader for test
im using only one teensy for usb midi controlling andi dont know how write a code but i try to use some of codyfaders code from github and to make some changes. for now i made midi in and out work but the motor is not responding well (going forever to up or down way)
i can see in ur video thaht te pid controling is great.
do u have this code with usbmidi controlling?
or may u have any tip for me how can i add usbmidi controling to your pid controlling code?
tnx
rota

I tried that code too with the same result, the fader is jumping up and down. I guess the simplistic approach used in that code only works if you reduce the power to the fader so it will never overshoot its target.
Here's the sketch for the fader panel: View attachment SPS-8_FaderPanel.ino
The panel is controlled over I2C by another Teensy. The faders are not used for a midi controller but for a sequencer (ARP style with presets). Here's the code for the sequencer: View attachment SPS-8_Master_180712.zip.
Here's a picture of the sequencer under construction:

sequencer-test-setup.jpg

The final version will have 16 steps (two panels), four channels and 16 patterns per channel.

Another project of mine emulates a Mackie control and extension unit:

Zeus-DPC-Lexicon-front.jpg

Here's the code: View attachment Zeus-DPC.ino

Controlling motorfaders is far from trivial, you definitely need to be able to write some code yourself to get them to do what you want. What kind of midi data should control the faders? What is it you want to achieve?
 
I tried that code too with the same result, the fader is jumping up and down. I guess the simplistic approach used in that code only works if you reduce the power to the fader so it will never overshoot its target.
Here's the sketch for the fader panel: View attachment 14578
The panel is controlled over I2C by another Teensy. The faders are not used for a midi controller but for a sequencer (ARP style with presets). Here's the code for the sequencer: View attachment 14579.
Here's a picture of the sequencer under construction:

View attachment 14580

The final version will have 16 steps (two panels), four channels and 16 patterns per channel.

Another project of mine emulates a Mackie control and extension unit:

View attachment 14581

Here's the code: View attachment 14582

Controlling motorfaders is far from trivial, you definitely need to be able to write some code yourself to get them to do what you want. What kind of midi data should control the faders? What is it you want to achieve?

tnx for your fast reaply
i just wanna controll 8 midi motorized fader in protools
i see in your code that the #define FOLLOW that is the incoming controling value and i wonder if:
#define FOLLOW 0x7F from the midi out can be work on the fader?
 
Back
Top