New Drivetrain Update (working!)


#1

Hi all,

I got the new drivetrain working. There are three separate motors, each with its own PID loop for feedback. I got both the motor model and PID loops in general from this very forum. Grateful to have you all here and helping me keep this project alive!

Please post any feedback or questions about what you see in the video here. There’s a lot more to be done, like the startup and end sequence. There’s also some error with the capstan motor that sends it spinning really fast if the film slips. Also, the film slips! Not sure if it’s because I don’t have enough tension, or it’s just the surface of this matte-finish PTR that isn’t sticky enough. Suggestions welcome.


#2

Also, here’s the code. It’s running on an Arduino Mega 2560.

#include <PID_v1.h>

// — limit switches — 
int l_stop = 22;
int l_start = 24;
int r_stop = 26;
int r_start = 28;

// — potentiometers —
int l_pot = A0;
int r_pot = A2;

// — motors —
int l_motor_dir = 51;
int l_motor_pwm = 6;
int r_motor_dir = 52;
int r_motor_pwm = 11;
int m_motor_dir = 53;
int m_motor_pwm = 9;

// PID Variables 
double supplySetpoint, supplyInput, supplyOutput;
double takeUpSetpoint, takeUpInput, takeUpOutput;

// PID initialisation and tuning parameters
PID supplyPID(&supplyInput, &supplyOutput, &supplySetpoint,1,0.1,0.1, DIRECT);
PID takeUpPID(&takeUpInput, &takeUpOutput, &takeUpSetpoint,1,0.1,0.1, DIRECT);

// Capstan variables
float targetRPM = 2 * 60; // 2 rotations ~13frames (26fps) * 60 seconds
int encoderPin1 = 3;
float PULSES_PER_ROTATION = 200.0;
float currRPM = 0.0;
long prevTime = 0;
int counter = 0;
int COUNTER_MAX = 3;
float capstanMotorSpeed = 0;

void setup()
{
  Serial.begin(115200);
  
  // changes internal comparator clocks, reduces motor "whine" sound
  TCCR2B = TCCR2B & B11111000 | B00000001;    // pins 9/10 (capstan motor on pin 9) PWM frequency of 31372.55 Hz
  TCCR1B = TCCR1B & B11111000 | B00000001;    // pins 11/12 (takeUp motor on pin 11) PWM frequency of 31372.55 Hz
  TCCR4B = TCCR4B & B11111000 | B00000001;    // pins for (6/7/8 supply motor on pin 6) PWM frequency of 31372.55 Hz

  // Initialize supply (left) motor
  pinMode(l_pot, INPUT);
  pinMode(l_motor_pwm, OUTPUT);
  pinMode(l_motor_dir, OUTPUT);
  digitalWrite(l_motor_dir, LOW);

   // Initialize takeUp (right) motor
  pinMode(r_pot, INPUT);
  pinMode(r_motor_pwm, OUTPUT);
  pinMode(r_motor_dir, OUTPUT);
  digitalWrite(r_motor_dir, LOW);

  // Initialize capstan (middle) motor
  pinMode(m_motor_pwm, OUTPUT);
  pinMode(m_motor_dir, OUTPUT);
  digitalWrite(m_motor_dir, LOW);

  // Initialize RotaryEncoder
  pinMode(encoderPin1, INPUT); 
  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  attachInterrupt(digitalPinToInterrupt(encoderPin1), updateEncoder, FALLING);

  // initialize PID variables
  supplyInput = analogRead(l_pot);
  supplySetpoint = 140;
  takeUpInput = analogRead(r_pot);
  takeUpSetpoint = 152; 

  //turn PIDs on
  supplyPID.SetMode(AUTOMATIC);
  takeUpPID.SetMode(AUTOMATIC);
}

void loop()
{
  // Read the hubs
  int supplyPotVal = analogRead(l_pot);
  int takeUpPotVal = analogRead(r_pot);

  // Update PIDs
  supplyInput = supplyPotVal;
  takeUpInput = takeUpPotVal;

  // Adjust supply and takeUp motors
  supplyPID.Compute();
  takeUpPID.Compute();
  if (supplyInput < supplySetpoint) {
      analogWrite(l_motor_pwm, supplyOutput);
  }
  if (takeUpInput < takeUpSetpoint) {
      analogWrite(r_motor_pwm, takeUpOutput);
  }

  // Adjust capstan - PID not implemented yet. To-Do. 
  if (currRPM < targetRPM) {
      capstanMotorSpeed = capstanMotorSpeed + 0.1;
  } else if (currRPM > targetRPM) {
      capstanMotorSpeed= capstanMotorSpeed - 0.1;
  }
  analogWrite(m_motor_pwm, capstanMotorSpeed);

  delay(10);
}


// Was originally using a rotary encoder on the capstan motor to get feedback
// for thePID. It was producing unreliable results so I bypassed it in the loop() above. 
// Eventually the input to this PID will be the sprocket holes, detected by reflective sensors or 
// equivalent. 
void updateEncoder(){
  counter++;
  if (counter >= COUNTER_MAX) {
  long now = millis();
  long timeDelta = now - prevTime;
  currRPM = (60000 / (timeDelta * (PULSES_PER_ROTATION / COUNTER_MAX))) ;
  prevTime = now;
  counter = 0;
  }
}

#3

Hi Matthew,
That film is moving pretty fast. Is that the speed at which you will be able to scan? I’m very impressed.I purchased a film gate that I will use for my Kinograph. I posted some photos on the Forum. I am leaning towards a single frame capture machine at this point. One thing I have noticed in the forums people comment that the DIY machines won’t be good enough for archival work. I disagree, it would seem that once the film mechanism is perfected then professional results could be attainable with better cameras and optics.
Rob Teed
Railyard Productions