All I’m trying to accomplish here is to demonstrate what one can do with the LEDs to create a believable police/fire emergency lightbar. The car itself is a mess (see below). My intent is not to show a finished model car. This is only a demo for the LEDs. Only the forward facing LEDs are implemented. You can think of the car as a holder for the LEDs. Period. The LEDs over-power the ambient lighting so that not much car detail is visible.
My camera does not do justice to these LEDs. I tried many camera settings and LED intensity levels. Nothing comes close to seeing this car in person. Every step of this project has been nothing but a big hassle. I’m really disappointed in the final result. The video is actually my first test shot. Even though it’s really too bright for the camera, it’s the best for the beacons and headlights. Just imagine that you are looking at the car in heavy fog. I just want this project over and done with, so there are none of my planed music and editing. Please excuse the camera adjustments during the video.
I know people are going to have suggestions and criticisms. That’s great. There are things in the patterns I would like to change, but at some point you just have to go with what you have. If I didn’t, you would never see a video because I would be playing with patterns forever myself. So any suggestions or criticisms are welcome.
The Crown Victoria
This car is s 1/18 die-cast Motormax decorated for the San Gabriel Police. I apologize for any deviation in installation and operation of the lights from San Gabriel Police practice. This car has been a pain in the ass to build. I had to grind out a lot of metal to fit my PCBs for the headlights and taillights (taillights not implemented in the video). The poorly drilled headlight openings and poorly done grill cut-outs are noticeable but not too bad, I hope. As mentioned above, the car is just an LED holder and nothing more. It doesn’t even have the interior installed. I will get a new car if I do a build using new PCBs. Also, glass, or something, would be great for the headlights, taillights, and roof-mounted light bar. The plastic creates too much distortion. That’s why I left the headlight bezels off.
LEDs are the SK6812. These are smaller versions (3.5mm x 3.5mm) of the popular WS2812b LED. This part is a little faster than the WS parts, otherwise its operation is pretty much identical. The SK6812 is a surface mount device. I solder them using a simple hot plate with a 1x4x4 aluminum block to even out the heat spread. I guesstimated the “heat ramp” and used a tell-tale (PCB with solder but no components) to see when the solder flowed. Crude, but I haven’t damaged very many parts if any. I’ve seen no part failures after they work the first time — reliability seems high.
The LEDs are wired as a single string. The first LED is the left headlight (from the driver’s perspective). The chain then runs to the right headlight, up to the right side of the lightbar, and ends at the left-most LED on the lightbar. Some details about driving these LEDs are found below in the The Code section.
But I would now like to editorialize a little bit. These are serial LEDs. They are not addressable LEDs. There is nothing like an address associated with these devices. This applies to SK6812, WS2812b, WS2812, or WS2811, etc. These devices ONLY receive a serial DATA stream. The data they receive and use for their PWM driver comes from the Din pin. That pin is driven by the Atmega328p, in this case, or from the preceding LED in the serial chain of LEDs. When an LED receives its 24 bits of color/intensity/PWM data, it latches it internally and then it passes all further data that comes in on its Din pin out on its Dout pin. Nothing like an address is received. The physical position in the serial string of LEDs determines which data is used.
And there is also another miss-conception about the data. Many people seem to think that a string of these LEDs form a giant shift register. That may be true in one sense but not literally. The first 24 data bits sent are used by the first LED. The second 24 bits sent are used by the second LED. The data is not shifted through each LED from first-to-last so that the first data ends up in the last LED. Another miss-conception I’ve seen is that the blue color is sent first. Green is sent first and blue is sent last. There! Thanks for letting me rant.
Parts Is Parts
I learned that I’m not a good judge of how big PCB assemblies are going to actually turn out to be. It’s more like crossing your fingers and hoping for the best. But I have learned what it’s going to take to create a usable set of PCBs to make this a viable project. I guess that’s why you do prototypes. My plans were foiled by the SK6812 footprint. It’s similar to a DFN. This makes it very hard to solder kluge wires. I found this out when I tried my plan for the Alley lights. I was going to saw half way through a 2-light PCB (successful), bend it 45 degrees while maintaining the back side power traces (successful), and then restoring the Din to Dout connection (failed). That’s why there are no Alley lights on the roof mount lightbar.
So what is required is a much thinner and flexible PCB. All this dictates a re-thinking of the PCB sizes I will need. I’ve pretty much settled on the following:
- 2-light LED (headlights, taillights, grill lights, backup lights)
- 4-light LED (push-bar lights, package-tray lights)
- 10-light LED (front and back lightbar lights) (…or a single 20-light PCB, maybe)
The 2-light and 10-light (maybe 20-lite) are going to have to be built on thin, flexible PCB material. It’s the only thing that will work in the roof-mount, and, for the 2-light, it will greatly help in the installation at the headlights and taillights where the chassis mounting posts are located.
UPDATE: I’m thinking of going to the APA102-2020. These will allow easier installation, a more densely populated lightbar, and should be very nice for 1:24 scale. We’ll see how those go with the thin PCB materials.
I‘m not releasing the code at this time. That’s because I’m still working on it. The patterns are created by configuring each LED. The plan is to have a user interface that will allow easy configuration. Also, all the patterns in video are on the ATmega328p at the same time. There are no edits. The program just plays a continuous loop. In the video, the first two patterns are the last two patterns. There are about 68 patterns (some sequences use multiple patterns). The memory is essentially full. When I add the Alley lights, and the additional 26 LEDs for the back of the car, the number of patterns will be cut in half, or more. And then the user interface support is not even designed yet. And I”ve found that a brightness control would be a nice feature. Therefore, I’m thinking of moving to a teensy. So, the code is going to change radically anyway.
Development began using the Arduino IDE and environment. The first thing that dropped out of consideration was the FastLED “library”. I was going to study it but just its size ruled it out. I want as much Flash space as possible for my code. FastLED is written to serve a wide range of LED types and applications. It’s great for getting something going on any type of serial LED string you may have. But that is not an advantage for me. I have a narrow, very specific set of requirements. I use one type of LED. I use them in an application where the characteristics of the “blinking” are very well defined and specific. A general purpose “library” cannot begin to be as efficient as a purpose designed C++ class. The only functionality of the FastLED “library” I required was the actual data driver. That was replaced with an assembly language driver 74 bytes long.
I was also going to use the millis function to create timing. However, I found that it interfered with the LED driver. The interrupts required by millis could occur at any time causing a premature load of the LEDs before all data had been sent. That caused flashing lights and only the first few LEDs worked correctly. And disabling interrupts during LED data transmission messed-up millis itself! So millis was quickly replaced with my own ISR to generate timing events. It is much simpler and does a couple of operations that I do need. And I don’t have to use any math to figure out how much time has elapsed between events. So millis was out!
These decisions left no reason to continue to use the Arduino environment at all. So this code is “bare-metal” ATmega328P. Development was done using vim, avr-gcc, and avrdude. Much easier to use anyway (except for moving the chip back and fourth for burning). Anyway, I much prefer having a makefile to control my code generation.
So, my current thinking on the code is that, by far, most of the people building emergency vehicles are not coders. They just want lightbars to put on their cars. If I release the code, you would have to cross your fingers and hope that someone would develop a product (because I would not). If no one else made it into a product, you could have the code, but you would be stuck with the LED arrangement and light patterns as released. That most likely would not fit your particular build. So, at this time, I think I’ll proceed as described above and try to release a product that non-coders can use. Making flash patterns will be no more than filling in a WEB style form. There will be a few different LED groupings on PCBs, a way to plug them together, and you should be able to configure your particular LED arrangements. Amyway, that’s the plan as of now. We’ll see how it goes
I‘m just glad this project has reached this point. It has been doubly hard with all the other problems in my family. I see a lot of comments in the media about how 2016 sucks. I can tell you this has been the worst year of my life.