New Drivetrain Update (working!)

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.

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;
  }
}
1 Like

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

Hi Rob. I’m hoping to scan at 24fps. Fingers crossed! The final speed will be determined by the camera and processing capabilities of the hard drive it’s writing to.

I disagree with them re: archival too! It’s all a matter of what you’re going for. Digitizing is never a permanent solution no matter how high the resolution.

Kinograph is meant to be upgradable, as you point out. 4K camera? Sure! Add it on! That’s the beauty of open source!

Glad you found us. Looking forward to checking out your photos (I’m catching up on posts today).

Matthew

@matthewepler is that 24fps telecine or intermittent capture?

I was trying to do some research on the fastest scanner out there, and there wasn’t any information easily available. I saw up to 100 fps, but I’m not certain how that is related to capture quality.

Do you know what is currently the fastest scan available @ 4k?

I’m not sure who has the fastest machine at 4K. It’s been a couple years since I did a survey of the available machine out there.

Let me know if you find out!