IR - Detecting Speed of the Disc

A "new fashioned" televisor, using an Arduino to drive the motor and display.

Moderators: Dave Moll, Andrew Davie, Steve Anderson

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Sat Mar 11, 2017 12:53 pm

... aaaannnddddd it's working!

Edit - but I did it a bad way. The correct way is described here.

Here is the setup code to get a comparator interrupt running with the IR sensor connected to analog pin A0 for AIN1 and using the internal reference voltage for AIN0.

Code: Select all
 // start interrupt for IR

  ACSR &= ~(1<<ACIE);         // disable interrupts on AC

  //  Connect ADC multiplexer to the negative input to the Analog Comparatpr
  ADCSRA &= ~(1<<ADEN);       // turn off ADC
  AC_REGISTER |= (1<<ACME);        // Enable multiplexer, so we can select analog pin to AIN1. See chap 23.2 ATmegaU32

  ACSR &= ~(1<<ACD);          // switch on the AC
  ACSR |= (1<<ACBG);          // set Internal Voltage Reference (1V1) for AIN0

  ADMUX &= ~31;
  ADMUX |= ((1<<MUX0)|(1<<MUX1)|(1<<MUX2));               // set analog comparator negative input to ADC0 (A0)
  AC_REGISTER &= ~bit(MUX5);
 
  ACSR &= ~(1<<ACIS0);        // falling trigger
  ACSR |= (1<<ACIS1);

  ACSR |= (1<<ACIE);          // re-enable interrupts on AC
  SREG |= (1<<SREG_I);        // GLOBALLY enable interrupts
   


I can now detect the RPM of the disc - not long now until I hook up the PID to control the speed and we should have a non-moving image.
The step after that will be to sync the pulses from the video and then we'll have a locked frame. But first, the PID controlling speed....
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Sat Mar 11, 2017 1:21 pm

Wahoo!

The PID worked the very first time I tried it, and although my RPM calculation isn't quite right, I just found a value for the PID which kept the frame pretty stationary and then fired it up to see how well it kept the picture from rolling. At first it was jerky, but I upped the P value a lot and then - well, this is the result


youtu.be/rqCoQFBkIdI

Note - this is with a single sync hole on the disc. I have 31 of my 32 holes taped over.

This is the first time ever I've not had to manually control the disk speed to get a decent picture. Fantastic!
Next step is to fix up the RPM calculation - that's off because the prescalar I used for the PWM buggers up the system clock - bah - so I need to debugger it.
After that, I can move on to reading the analog NBTV video signal and processing that for the sync pulses.
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Sat Mar 11, 2017 5:38 pm

Edit: Full source code is now on GitHub. See this post.
Here's the current code for the entire televisor...

Code: Select all
// Arduino Mechanical Televisor
// Andrew Davie, March 2017

#include <PID_v1.h>

// PID: Define Variables we'll be connecting to
double Setpoint, Output;
volatile double Input;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,10,1,25, DIRECT);



volatile boolean syncHoleDetected = false;
volatile unsigned long timeDiff = 0;
volatile unsigned long lastDetectedIR = 0;


//-- Analog comparator interrupt service routine -------------------------------------------------
// Triggered by sync hole on IR sensor connected to A0 pin

ISR(ANALOG_COMP_vect) {

  syncHoleDetected = true;

  // calculate current RPM for PID - must correct for prescalar buggering up clock!

  // TODO: millis() is not returning expected value due to prescalar
  //  prolly have to use the frequency(20kHz) as an adjustment.
 
  timeDiff = millis();
  if (lastDetectedIR != 0) {
    Input = 6. * 256 * (1000./ (timeDiff - lastDetectedIR));         // current RPM
  }
  lastDetectedIR = timeDiff;
 
}

//-- end interrupt for IR



void setup() {

  //-- Comparator Interrupt  -------------------------------------------------------------------
  // start interrupt for IR

  ACSR &= ~(1<<ACIE);         // disable interrupts on AC

  //  Connect ADC multiplexer to the negative input to the Analog Comparatpr
  ADCSRA &= ~(1<<ADEN);       // turn off ADC
  ADCSRB |= (1<<ACME);        // Enable multiplexer, so we can select analog pin to AIN1. See chap 23.2 ATmegaU32

  ACSR &= ~(1<<ACD);          // switch on the AC
  ACSR |= (1<<ACBG);          // set Internal Voltage Reference (1V1) for AIN0

  ADMUX &= ~31;
  ADMUX |= ((1<<MUX0)|(1<<MUX1)|(1<<MUX2));               // set analog comparator negative input to ADC0 (A0)
  ADCSRB &= ~bit(MUX5);
 
  ACSR &= ~(1<<ACIS0);        // falling trigger
  ACSR |= (1<<ACIS1);

  ACSR |= (1<<ACIE);          // re-enable interrupts on AC
  SREG |= (1<<SREG_I);        // GLOBALLY enable interrupts

  //-- PID to calculate motor speed  ----------------------------------------------------------------

  Input = 0;                  // rpm
 
  Setpoint = 937.84;           //937.84;   // kludged "about right" rpm based on incorrect speed calculations

    // TODO: will be 750 when correct
 
  Output = 99;
 
  //tell the PID to range between 0 and the maximum for the PWM
  // This is the range mandated by the frequency setting in the PWM OCR0A
  myPID.SetOutputLimits(0, 99);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);

  //-- PWM to run the motor  -------------------------------------------------------------------

  // Only enable the pin that's being used. Here are all the options for the Micro though...
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(13, OUTPUT);

  // Setup the PWM
  // WGM02|WGM01|WGM00  = waveform generation
  //                    = fast PCM with OCRA controlling the counter maximum
  // CS01               = clock scalar /8
  // COMA               = toggle on compare match (01)

  TCCR0A = _BV(COM0A0) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
  TCCR0B =  _BV(WGM02) | _BV(CS01);

  OCR0A = 99;          // the compare limit (reduce this for higher frequency PWM)
 
  // frequency  = 16MHz/scalar/(OCR0A+1)
  //            = 16000000/8/256
  //            = 7812 Hz
 
  // if we change the scalar to 1 and OCR0A to 255...
  // frequency = 16000000/1/256
  //                 = 62.5KHz

  // if we change the scalar to 8 and OCR0A to 99...
  // frequency = 16000000/8/100
  //                 = 20KHz

  // and note, Output A is fixed frequency - use B instead
  // Output B is based on the duty cycle written to OCR0B;  i.e., (OCRB+1)/(OCRA+1)%
 
  OCR0B = 0;            // start with duty 0%

  // PWW is running at this point.
  //--end PWM -------------------------------------------------------------------
 

  // Debug console...
  Serial.begin(9600);
  while (! Serial);
}


void loop() {
     
  if (syncHoleDetected) {
    Serial.print("RPM=");
    Serial.println(Input);
    syncHoleDetected = false;
  }

  myPID.Compute();
  OCR0B = Output;         // PWM value for motor control
 
}
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Sat Mar 11, 2017 6:57 pm

I transferred the IR circuit from the prototype board to a hardwired board. A bit ridiculous really - the only components it has on it are two resistors. The rest is just wires coming and going. Still, it's easy to use - just plug stuff in. Tested and functional. I swapped the original 150 ohm resistor for a 180 ohm one per earlier calculations.

irboard.jpg
irboard.jpg (204.2 KiB) Viewed 6948 times


I tried to draw a neater circuit diagram for future reference...

ircircuit2.jpg
ircircuit2.jpg (193.71 KiB) Viewed 6948 times



For future reference, the IR signal (orange wire) is connected to A0
The 5V wires - green to GND pin, yellow to 5V pin
To the motor board from the Arduino, grey is PWM signal from pin 3
Purple is the GND

Once I figure out all the external bits, it's actually going to be a minimal thing really, and I might make a single board version.
Only new thing I can think of is driving the LED array and that will need another transistor type thing and a resistor or two.
I also want to see if I can consolidate the power so that we have JUST the DC12V requirement, and then I can power the motor, Arduino and LEDs from the one source. Maybe.
That's for later.
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Mon Mar 13, 2017 11:17 am

The comparator interrupt can be set up in a number of ways. I chose the wrong way. The problem is that the ADC selector is multiplexed, and that selector can be used for either comparator pin select OR for ADC pin select. Not both. Fortunately, the comparator can be used in a different way without using the ADC selector, as I have discussed here. So, my immediate job is to get the IR sensor comparator switched over to the correct way and confirm it working via the disc speed lock to RPM once again. I'll tackle that today.
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Mon Mar 13, 2017 12:31 pm

Made the changes. Much simpler. Works!

Moved the IR input to pin 7 (PE) and changed the code as per below. The code doesn't play with the ADC multiplexer at all - leaves it alone so if it's needed can be setup/configured elsewhere. Nice to have something go to plan first time :)

Code: Select all
void setupIRComparator() {
  ACSR &= ~bit(ACIE);         // disable interrupts on AC
  ACSR &= ~bit(ACD);          // switch on the AC
  ACSR &= ~bit(ACIS0);        // falling trigger
  ACSR |= bit(ACIS1);
  ACSR |= bit(ACIE);          // re-enable interrupts on AC
  SREG |= bit(SREG_I);        // GLOBALLY enable interrupts
}
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Re: IR - Detecting Speed of the Disc

Postby Andrew Davie » Sat Apr 08, 2017 10:33 pm

Been a frustrating weekend so far. My motor stopped spinning. I was plugging things in and out, and the signal wire on the IR sensor board had come loose. I reconnected it, but televisor not working. I spent some time diagnosing, and confirmed the IR was indeed giving a valid detection pulse on the sync hole flyby and that the wire from the IR board to the arduino was OK. So then I went into the software and started tinkering there but I couldn't think of anything I'd changed. So before I got too deep into that, I switched the Arduino for my spare - and - all working perfectly.

So, somehow I screwed up the analog comparator pin on the Arduino. I suspect I've knocked the hodgepodge of wires somehow, pulling on the signal wire with suffient force to not only pull it out of the snap connector, but also to damage/break the comparator pin gizzards on the Arduino.

The reason the motor didn't spin - the comparator wasn't triggering, so the interrupt wasn't running, so the code which sets the motor speed was never being called.
User avatar
Andrew Davie
"Gomez!", "Oh Morticia."
 
Posts: 1590
Joined: Wed Jan 24, 2007 4:42 pm
Location: Queensland, Australia

Previous

Return to Andrew Davie's Arduino Televisor

Who is online

Users browsing this forum: No registered users and 4 guests

cron