Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

(solved)could use help with POV-clock code (trouble with even starting correct timing......)

Status
Not open for further replies.

fezder

Well-Known Member
Right, topic says quite well trouble now, i managed to start using that BLDC motor from computer hdd, and now came the part i've been waiting for....sort of, because i just don't have much coding experience at all, but i've progressed at least hehe...
But, issue now is, for start, how can i calculate correct timing when to flash led's, even one colour for now like say in 90 degrees section/place? no need to jump to fancy clock hands yet, i think i'll get the hang of that once i understand how this timing must be done. So i do have reliable trigger to tell micro (arduino uno) when rounds come and go, tested it for 120 rounds per second and was reliable.

Now then, the code i have putted together: actually it's just fan rpm counter but i figured it would be great foundament to start building.
that led is purely for debugging purposes....as well as serial

What i'm thinking is that i should write the code like so that arduino calculates degrees/second from RPM value and from there the correct delay needed from new rotation-start?

Now, i dont't ask the answer, more likely clue/hint so i can think, like a bone to a blind dog: can smell but can't see it, if you see my meaning...
C:
int const ledPin = 13;
int half_revolutions = 0;
int state = LOW;
int rpm = 0;

unsigned long lastmillis = 0;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0, rpm_fan, FALLING);
  pinMode (ledPin, OUTPUT);
  }






void loop(){


if (millis() - lastmillis == 1000){ //Uptade every one second, this will be equal to reading frecuency (Hz).

detachInterrupt(0);//Disable interrupt when calculating

rpm = half_revolutions * 60; // Convert frecuency to RPM, note: this works for one interruption per full rotation. For two interrups per full rotation use half_revolutions * 30.

Serial.print("RPM =\t"); //print the word "RPM" and tab.
Serial.print(rpm); // print the rpm value. Serial.print("\t Hz=\t"); //print the word "Hz".

half_revolutions = 0; // Restart the RPM counter
lastmillis = millis(); // Uptade lasmillis
attachInterrupt(0, rpm_fan, FALLING); //enable interrupt
}
}

// this code will be executed every time the interrupt 0 (pin2) gets low.

void rpm_fan()

{
  digitalWrite (ledPin, state);
  (state = !state);
  half_revolutions++;
}
 
Last edited:
You don't need to no how many rpms it's doing just where the leds are. Best way I found to do is to use a led ir and pototrasnsistor. Then I made graft to plot the leds then its just a matter
of turning the leds on where you want them to show.
 
You don't need to no how many rpms it's doing just where the leds are
well now, that's true! i'm currently using an opto-pair to detect each round, but, it still troubles me that won't even slightest change in rpm cause unreadable display? i mean when leds are not in sync with disc groove? or then i just didn't understood what you meant by ''making graft to plot the leds'' (language barrier...sorta?)
 
and just to make sure, here's my setup

Prototype.jpg
 
Hi Atte, I haven't done anything like this for decades! I've not had my coffee yet but I'll try to offer some insight.

As I remember, you need to know 2 things primarily:

The rpm of the motor driving your clock, this is fixed right at the beginning and doesn't need to change.
You also need to know where 360/ 0 degrees is so that you can end and begin your LED pattern cycle.

You can use your little slot opto to detect the 360/ 0 degrees. At each transition through 360/ 0 degrees, you end one cycle of LED pattern and begin outputting it again, updated obviously to reflect any changes. In the case of a clock, the pattern is going to change with each second or minute or hour etc. For that matter, you can display just about anything else your mind can create, running text, geometric patterns etc. You can even get fancy and use RGB LED's for multiple colour displays, dimming/ fading effects etc, really the sky is the limit :)

Timing is obviously critical for POV to be effective, so you need to know where the LED's are in degrees relative to where you are in your code timing wise.

So take your motor rpm and divide that by 60, calculate to find the time taken for one revolution of the motor spindle, then calculate how long it takes for 1 degree of movement, so divide your answer by 360. You'll then need to correlate that answer with your chip's clock/ instruction execution time to figure out how many instruction cycles relate to each degree of motor movement and write your timing and LED pattern code appropriately.

I'll try and work a quick example of what I'm going on about:

Let's say we have our motor running at a steady 3000 rotations per minute and we are using a PIC micro running with a 20Mhz clock

We need to know how many rotations per second:
3000/60 = 50 rotations per second

We now need to figure out how long 1 complete rotation takes:
1/50 = 0.02 secs

We now need to calculate how long 1 degree of motor movement takes:
0.02/360 = 0.00005555555 secs

We now need to know how many instructions can be processed for each degree of movement so we can update our LED patterns etc:
PIC running at 20Mhz / 4 for pipelining (Fosc/4) = 5Mhz

1 degree of motor movement/instruction execution time:
55.55555/5000000 = 111.1111 instructions per 1 degree of motor movement.

So using a PIC with a 20Mhz Fosc, you can squeeze in 111 instructions for each degree of motor movement. Plenty of time to update LED patterns and do other housekeeping stuff etc.

As for using an Arduino, I have very little experience with the platform, so can't really help you with that, but with timing being so critical, I would think you would be better off using a bare chip and writing tight code to begin with, especially if you plan on doing other fancy stuff with colour etc.

I hope some of that helps :)
 
The rpm of the motor driving your clock, this is fixed right at the beginning and doesn't need to change.
hmm, perhaps i should fix this first hand so i can focus only where leds should flash
 
Almost certainly. You must know the RPM of the motor spindle you are using before you can calculate anything else. The cheap fan driven POV type display examples that are littered throughout the internet rely on the fan rotating at the manufacturers claimed RPM, however, you will notice that for the most part they are often very slightly off in terms of display stability. This I suspect is partly due to the eye naturaly following the light direction but primarily because the fans are not running at the claimed speed, maybe a little faster or slower depending on manufacturing batch tolerances, how new the fan is, quality of bearings etc etc. With a BLDC motor though, you can very tightly control the rotational speed, as you normally have some form of reference signal available back from the motor that you can phase lock your drive circuit to. If you want the clock display to be super stable in position, it might be worth putting some effort into tightly controlling the motor speed. As has already been pointed out, beware that excessive speeds of a HDD platter, particularly outside of the air controlled environment of the HDD enclosure, can cause it to suddenly shatter. You will not be able to run it safely at the original HDD speed outside of it's enclosure, so you will need to dial it back until you are just beyond the point of the eye detecting flicker. Also, even assuming you do manage to run it at that speed, you need to ensure that your clock electronics and mechanical fastening thereof, can also withstand the forces applied as it rotates.
Just food for thought...
 
That's all in how you look at this cause you can A fine where the disk is at then let it light based on that because as you'll see the rpm will change and your timing will get off if you use the motor speed with out just catching it movement every revolution. That way you can speed up or slow down the speed of the motor and still see the display
 
Like this motor at say 120 rpm just saying. You base your figures on that as fixed math. Motor spins 121 rpm you display looks bad. But you catch the true revolution of the disk and use that it don't matter how fast or slow it spins you'll still see the display
 
now then, have made quite progress, i can actually control where lights show up....but before i continue, i encountered quite annoying bug: possibly in my code is something riled up, it somehow either misses round/s or something similar, this photo is from output pin that drives darlington array (uln2003) that i use to control led strip. as you can see it's not even close regular: long sections off. input signal is good, tested it without arduino and no unregular flicker. this happens more often in this higher (40-60hz) region
NewFile1.jpg

code i have put together this far
C:
#include <Servo.h>
Servo esc;
int throttlepin = 0;   //analog input pin for potentiometer (as voltage divider/reference)
int inPin = 2;         // the number of the input pin
int outPin = 13;       // the number of the output pin

int state = HIGH;      // the current state of the output pin
int reading;           // the current reading from the input pin
int previous = LOW;    // the previous reading from the input pin
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0;         // the last time the output pin was toggled
long previousmillis = 0;
long starttime;
long elapsedtime;



void setup()
{
  esc.attach(9);
  pinMode(inPin, INPUT);
  pinMode(outPin, OUTPUT);
}

void loop()
{
  int throttle = analogRead(throttlepin);
  throttle = map(throttle, 0, 1023, 0, 179);
  esc.write(throttle);

  reading = digitalRead(inPin);
if (reading == HIGH && previous == LOW)
{
if (state == HIGH)
starttime = millis();
}
previous = reading;
elapsedtime = millis () - starttime;
if (elapsedtime ==0 && elapsedtime <=4.17)           //turn led on between 0-4.17ms
{
  digitalWrite (outPin, HIGH);
  }
  if (elapsedtime >=5)                               //turn led off at 5ms
  {
  digitalWrite (outPin, LOW);
  }
  }
 
Last edited:
Like this motor at say 120 rpm just saying. You base your figures on that as fixed math. Motor spins 121 rpm you display looks bad. But you catch the true revolution of the disk and use that it don't matter how fast or slow it spins you'll still see the display

I see where you're coming from and that's doable, but it complicates matters somewhat because you would then also need to time each revolution and then compensate for motor variation in your LED display code. This can easily be achieved in hardware, much more effectively, by using a phase locked loop control for the motor driver, leaving you to only concentrate on the LED display aspect of the project. The motor has to be driven by some method in any case, so why not just use a decent motor driver to begin with and save the headache that trying to perform software compensation brings. Not to mention that it also steals away valuable instruction execution time from the processor that could be put to better use in that fancy multi-colour pattern you want to display etc :)
 
hmm, i think i know why it misses pulses: i should use interrupts instead of digitalRead
using a phase locked loop control for the motor driver
somehow this sounds either complex or expensive :eek:
 
I didn't see your picture till I got home your doing a slot in the platter type pov not a bunch of leds spinning on a disk. I wonder how a timing light on a car worked LOL Oh it lights when the sparkplug it's hooked on fires. You see the mark on the pulley even if the motor is missing the mark still shows.
don't think there's "phase locked loop control for the motor driver" there. Then you have the nob that changes the dwell ? what happens then Oh the mark shows up in a new spot.
So the dumb timing tool can do that wonder what a Arduino can do if you
Code:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
we see the mark all we need to no..... how long we wait fire are light the mark moved.
 
hmm, i think i know why it misses pulses: i should use interrupts instead of digitalRead

somehow this sounds either complex or expensive :eek:

It's quite often built in to the driver chip, but requires a signal be brought back from the motor to the driver chip. BLDC motors very often have an onboard frequency generator, which amounts to nothing more really than a pcb printed coil around the outside edge and a little magnet that is part of the spindle platen. That signal is then coupled back to the motor driver to allow the motor driver to maintain the set speed. There are other ways to do so though. You already have your little slot opto on there for example, so you could just directly read the spindle rpm and adjust your motor driver accordingly, that would also provide closed loop control :)

For the sake of getting the project running to begin with though, you might want to just set a fixed speed for the motor and concentrate on the LED display aspect of it, once you have that working as you want, then turn your attention to refining how the motor is controlled and display is stabilised :)
 
Last edited:
not a bunch of leds spinning on a disk.
i'm planning to do it this manner too after this project :) would give bigger range of visual effects available like scrolling text
"phase locked loop control for the motor driver" there.
oh no, no control, only variable speed control via potentiometer
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);
i had in mind using interrupts but to me it's bit confusing, but the way i see it, interrupts interrupt code when they detect change? unlike digitalwirte that is constantly checked?
You already have your little slot opto on there for example, so you could just directly read the spindle rpm and adjust your motor driver accordingly, that would also provide closed loop control :)
yeah, i was thinking also of using that, instead of back-emf
set a fixed speed for the motor
speaking of this, i made an circuit around 555, and this works better than arduino-control

thanks for your help, both of you, thus far!
 
Use
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) to catch when your disk passes nothing else it doesn't stop your main loop but you can't read milis in the isr so all you want is to know it happen then out side of the isr offset when to light a led. Millis uses interrupts to so you can't read millis inside your isr. And set your variables volatile.
 
Here something I did it could do a lot of cool stuff but I lost the parts to it when I moved
 
Woa, that's cool! i started now making just normal sketch which calulates time between interrupts, as you said, millis cannot be used inside ISR, so i must use it inside loop?
C:
int pin = 13;
volatile int state = LOW;

void setup() {
    pinMode(pin, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(2), blink, FALLING);
}

void loop()
{
//timing calculation here?
}

void blink() {
  digitalWrite(pin, state);
    state = !state;
}
 
Last edited:
That's right millis can't be used in the isr.
And really all you want is to no it happen
Don't for get that variables have to be volatile just set a flag.
Volatile int disklocation or something
And make sure millis variable is volatile.
 
this had best success thus far when using interrupt, it does make that strange flicker, but that i think is due at least CHANGE trigger on interrupt
But, when i place FALLING, it blinks only every-other, so it misses one rotation and i can't figure out (yet) why...

C:
int const outpin = 13;
int state = LOW;
int reading;
int previous = LOW;
volatile long time = 0;
volatile long previousmillis = 0;
volatile long starttime;
volatile long elapsedtime;

void setup() {
    pinMode(outpin, OUTPUT);
    attachInterrupt(digitalPinToInterrupt(2), blink, CHANGE);
}

void loop()
{
  reading = state;
if (reading == HIGH && previous == LOW)
{
if (state == HIGH)
starttime = millis();
}
previous = reading;
elapsedtime = millis () - starttime;
if (elapsedtime ==0 && elapsedtime <=4.17)           //turn led on between 0-4.17ms
{
  digitalWrite (outpin, HIGH);
  }
  if (elapsedtime >=5)                               //turn led off at 5ms
  {
  digitalWrite (outpin, LOW);
  }

  }


void blink() {
  digitalWrite(outpin, state);
    state = !state;
    Serial.println(elapsedtime);
}
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top