motorized fader controller teensy 3.6 issue

Status
Not open for further replies.
Sorry, I don't know anything about Protools or Studio One as I use Logic and Reaper.

Why do you send the same data to two controllers? Isn't that supposed to a NRPN controller where the value is split over two MIDI bytes? But like I said, I don't know how Protools is controlled. Logic uses the Mackie MCU protocol and this uses pitch bend to send the fader values.

hi gerrit
all faders moving well but i see that: when they jump to position, not all of them jump to the right place, but once they get the move commend all of them jump to the right place and start moving.
do u have any idea what parameters should i tune?
tnx
rota
 
hi gerrit
all faders moving well but i see that: when they jump to position, not all of them jump to the right place, but once they get the move commend all of them jump to the right place and start moving.
do u have any idea what parameters should i tune?
tnx
rota
I don't understand what you're saying. How can the faders jump to a position without getting a move command?
BTW I don't have a facebook account so I can't watch the video.

With regards to tuning the fader control, I'm afraid you'll really have to read the PID without a Phd article referenced in the thread to get an understanding what the parameters do and what PID control is about. It's also difficult to give any advice without knowing exactly what the problem is.
 
I don't understand what you're saying. How can the faders jump to a position without getting a move command?
BTW I don't have a facebook account so I can't watch the video.

With regards to tuning the fader control, I'm afraid you'll really have to read the PID without a Phd article referenced in the thread to get an understanding what the parameters do and what PID control is about. It's also difficult to give any advice without knowing exactly what the problem is.
U right first I'll go read the article.
I'll try to explain the problem:
I'm sending 8 faders automations move commend from the software. When I press play all the faders go the position and moving OK. But when I press stop in software and rewind to the start point of the automations all fader go to some place(a bit wronaoutomation .
Now if I'll press play again all the faders will go immediately to the right position and will start move OK again.
One more example:
If I jump in software with crouser to any point in the sequence aoutomation. The faders go something near the position point. And then if I'll press play all faders go the the right starting position and start move OK.
It looks it like some thing with the jump to start point prameters reaction of the code.
 
All so sometimes in aoutomation reading the when faders got very hard commend of hard jump
Sometimes one of the faders got crazy for a sec and then keeps go back to position and keep the right track.
 
All so sometimes in aoutomation reading the when faders got very hard commend of hard jump
Sometimes one of the faders got crazy for a sec and then keeps go back to position and keep the right track.

If it's always the same fader that's behaving badly then I would check the wiring.

Here is a video of the problem

I can't determine what the actual problem is from this video, there's too much going on. Limit it to a single fader or have all faders do exactly the same thing.
You have to take a step back and systematically check the fader control and tune the PID parameters if needed.
 
If it's always the same fader that's behaving badly then I would check the wiring.



I can't determine what the actual problem is from this video, there's too much going on. Limit it to a single fader or have all faders do exactly the same thing.
You have to take a step back and systematically check the fader control and tune the PID parameters if needed.
U can see in the video that faders 1-4 found the same thing in the program that means that that send the same values but the fader controller act difrent when I'm jump to point. I test high P gain and its makes the jumps a bit better coz its higher
voltage but not solve it
 
If it's always the same fader that's behaving badly then I would check the wiring.



I can't determine what the actual problem is from this video, there's too much going on. Limit it to a single fader or have all faders do exactly the same thing.
You have to take a step back and systematically check the fader control and tune the PID parameters if needed.


i test all values in serial print and its looks ok the send value from master and the recive value in slave.
so its nothing i can think of.
maybe should i add some check error commend to check if fader is on the right value and if not to correct it?
 
here is another video of a test
here u can see im set the start point to 0 witch in my case is 1023.
like u can see the fader get the movement commend ok but when i jump to start u can see in serial print that the value that the master send (faderTarget[1]) is 1008.
in first try its not send the commend coz my mac work hard to send midi and read serial but in second try u can see the problem.
the fader trying rich ther but is stops somewhere is the middle(every time in a bit different place).
allso if u look carefully u can see that when i press play the fader go quickly all the way down (to 1008) and complete the movement by go up.
 
Last edited:
Which fader control mode do you use? TARGET or FOLLOW? Have you tried the other mode to see what the difference is?

I'm sorry but I can't help you with the tuning other than giving some general advice. It took me some time to get it right for my setup and it still needs some finetuning. You need to get an understanding of how the parameters interact with each other by experimenting. I would start with concentrating on the control of the faders without any DAW control by writing some test functions like I did with the one that cycles through some values which is shown in one of the videos. The point is to check for overshoot (combination of p and d term) when the fader has to move a large distance on the one hand and check that the fader is able to move a little (p and i term) on the other.
 
Which fader control mode do you use? TARGET or FOLLOW? Have you tried the other mode to see what the difference is?

I'm sorry but I can't help you with the tuning other than giving some general advice. It took me some time to get it right for my setup and it still needs some finetuning. You need to get an understanding of how the parameters interact with each other by experimenting. I would start with concentrating on the control of the faders without any DAW control by writing some test functions like I did with the one that cycles through some values which is shown in one of the videos. The point is to check for overshoot (combination of p and d term) when the fader has to move a large distance on the one hand and check that the fader is able to move a little (p and i term) on the other.
i guess the problem is not in pid coz I try to send parameters in FOLLOW mode and its still not going to the exactly correct point when jump to start point But I'll dig it
thank you.
 
Which fader control mode do you use? TARGET or FOLLOW? Have you tried the other mode to see what the difference is?

I'm sorry but I can't help you with the tuning other than giving some general advice. It took me some time to get it right for my setup and it still needs some finetuning. You need to get an understanding of how the parameters interact with each other by experimenting. I would start with concentrating on the control of the faders without any DAW control by writing some test functions like I did with the one that cycles through some values which is shown in one of the videos. The point is to check for overshoot (combination of p and d term) when the fader has to move a large distance on the one hand and check that the fader is able to move a little (p and i term) on the other.

UPDATE:
i read the pid artical and i think i understand most of it and good thing to know a bit more about.
so i did a lot of test with the pid and my problem.
i can say that that pid work great but not with pure hard square wave jump values point and faders.
in the slave code u wrote i found that the commend of FaderPidOn is the problem for my application.
or may i say that is the speed that FaderPidOn turns to false after fader move is too quick for the fader to arrive target.
so i tryed change cmd timer and faderRead timer but nothing brings me good result
i figure out that when i delete out the FaderPidOn from the if commend that operates the motors then the faders moving very well to target. but the motors keeps work constantly and oscillate when near to target or not exactly on target and its make the system unstable obviously.
soo... i write an small Debug void thats run in 50000 micro interval and check if faderTarget equal faderValue and if not the faderPidOn = true; thats working very nice and that the only solution i found till now. i guess ill give it a bit more fine tuning when i have some more time but now its doing the job.
here is a demo of 16 faders in software and a demonstration of jumping 8 faders left and back right.
here i can see that all faders rich the target:


and here is the slave code with my Extra Debug void:
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 sinceFaderDebug;                         // timer for fader check
unsigned int  faderDebugInterval= 50000; 
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]={0,1,16,17,18,19,22,23};     // touchRead pins for fader touch
int     faderMotorUpPin[8]=  {10,29,5,7,3,14,35,37};     // motor up PWM pin
int     faderMotorDownPin[8]={9,30,6,8,4,2,36,38};   // 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=4800;                     // 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]=0.5;
    iGain[i]=20;
    dGain[i]=2.00;
    iMin[i]=-1500;
    iMax[i]=1500;
  }
  
  // Setup for Slave mode pins 33/34, external pullups, 1MHz
  Wire.begin(I2C_SLAVE, PANEL_ADDR, I2C_PINS_33_34, I2C_PULLUP_EXT, 1000000);
  // register events
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  cmd = 0;    // incoming command operating mode
}

void loop()                     
{
    if (sinceFaderDebug >=faderDebugInterval) {
    sinceFaderDebug = sinceFaderDebug-faderDebugInterval;
    
    Debugfader();
    }
  // 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 (!faderTouched[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();
   //Serial.println(faderValue[1]);

  
  } 
}

// 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];
      //Serial.println(faderTarget[1]);

    }
    // 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)
}
void Debugfader(){
 for (int i=0;i<8;i++){
  if(faderTarget[i] != faderValue[i]){
    faderPidOn[i] = true;
  }
  }
}
 
Last edited:
Status
Not open for further replies.
Back
Top