:: spoke n' light ::

overview | sketches | prototype-I | prototype-II | prototype-III

The purpose of this first prototype is to clear as many uncertainties as possible, to make sure that I "hit walls" early enough and map the main hardware and software problems involved in this project.

PICing it. This initial version (rld_01.c) was written for a display stick containing 8 LEDs. Hardware interrupt INT0 is connected to the magnetic switch and ticks every time the wheel completes a full rotation. Two timers (timer1, timer3) are used for calculating the elapsed time between two complete rotations and the time between LED state changes. This version is very limited in that it can only control 8 LEDs, it is "black & white" (each LED can be either on or off at any given position) and the states are hard-coded. More to come...

The Hall Effect Switch. I hooked up a hall effect sensor to the circuit. For this test, the magnet was mounted on the wheel and the hall sensor on the bike's frame. Obviously, in the final setup this will have to be the other way around (as the sensor will have to be on the wheel).

The wheel was turned in various speeds (movie). A modified version of rld_01.c mentioned above was used to send to the serial output the time between every two consecutive "ticks" of the hall sensor. I recorded two sets of data, in which the wheel starts from a stationary state, is accelerated and then naturally slows down to a complete stop. The plot of those two datasets is given below (x-axis represents sample number, y-axis is the number of clock ticks between two spins, blue and red graphs are the two datasets).

The good news: no switch "bouncing" and no missed cycles. At first, I thought the "teeth" in the plot are cycles which were missed by the hall sensor. But if that was the reason, the height of jump would have to be twice the value before the jump. So after plotting both datasets on the same gird, I figured those jumps occur at regular places. Another interesting observation is that the size of the error is around 65536 clock ticks -- which means that for some reason we are experiencing an "extra" clock tick in some cases. Plotting dataset 1 with a graph representing the values of dataset 1 modulo 65536 shows that the errors occur when the value modulo 65536 is very high...

Interrupt within an interrupt. Looking again at the code, it seems like the cause of the problem is in the magnetic_isr() routine. The wrong readings could be a result of a timer1 overflow occurring while the following lines are executed:

timer1val = get_timer1();
timer1val32 = make32 (overflows, timer1val);

In theory, the compiler is supposed to disable all interrupts while executing interrupt service routines. Is that not happening? To check this out in a more precise way, I will add a disable_interrupts(GLOBAL) statement in the interrupt service routine and simulate hall sensor pulses in regular intervals to see if the bug is solved.

Test Images. The first three test images which I plan to run on the bike are shown below. The result will probably be much dimmer in the periphery, as the first version of the controlling software does not allow for PWM. In addition, those images were generated from 16-bits long vectors, whereas the first version of the bike will only have 8 bits. Left column shows source image, right column shows simulated result.

Keep it simple. After I found myself writing the controller code with two timers and one interrupt, fighting with synchronization issues and using semaphores, I decided to rewrite the code in a simpler way. The second version of the rotating led display (rld_03.c) has a main loop which handles the timing of whole rotations as well as changing the state of the LEDs along the spin. It is much simpler than the first version and more accurate, as the two timers are computed on the same basis. To test it, I used a slightly different version (rld_02.c) which "records" the timing information to RAM and dumps it to the serial port afterwards. The fact that no serial communications takes place while the program is actually collecting data makes it much more accurate. To test this version, I used another PIC which simply "pulsed" the main PIC in regular intervals, as if the magnetic switch was pulsing it.

Timing is everything. The first rotation tests showed that the speed of rotation can reach as many as 10 rotations per second. Multiplying this figure by a probable resolution of 90 positions per spin, we get almost 1000 LED state changes per second! This pretty much renders irrelevant any solution that uses shift registers or LED drivers, as those chips rely on serial communication and usually take about 500ns to update the display. One possible solution would be to use two sets of shift registers and use something similar to "double buffering" to prepare the next state in the "background" and switch between the sets of registers on the spot. The first version, however, will simply use a PIC to control each LED. A few more wires (as can be seen below), but no timing issues...

Current concerns. There are enough output pins on a 18F452 PIC to drive 32 LEDs, but having each LED draw 30mA of current means that almost a whole ampere of current must flow through the PIC when all LEDs are on... This would fry the PIC on the spot. So I ended up using arrays of transistors to drive the LEDs -- adding an additional set of wires to the device. Finally, I mounted the device on the bicycle and tested it.

First results on bike. As can be seen in the pictures below, the results are not yet perfect. The test pattern can be seen in the image, but since I did not take into account the "black spot" in the middle of the display, the image is somewhat distorted. Four possible ways to fight this problem are (1) reduce the size of the black spot (by placing more LEDs closer to the center of rotation); (2) take into account the presence of the black spot when calculating the vectors in MatLab; (3) use images that have little information in the center; (4) use animations to move images across the "screen" so that the black spot covers a different area of the image along the time.

Continue to Prototype II >>