Reflectance Colorimeter
We calculate the final price from your selected file. You review and accept it before payment.
Saved on this device.
A device that precisely recognizes and accurately compares colors using reflected light and an 8-channel spectrometer.
- Rating
- 0 / 5
- Likes
- 19
- Downloads
- 9
- Makes
- 0
- Views
- 288
- Reviews
- 0
Updated at source:
Model information
- Source
- Printables
- Category
- Electronics
- License
- CERN Open Hardware Licence Version 2 - Strongly Reciprocal
This is a DIY colorimeter, a device that can be used to recognize the color of a thing, wall paint, paintings, textiles, 3D-printing filament (swatches) and many more things. It is the kind of device that was mentioned in Prusas blog post about full spectrum printing and typically cost ~200€ for a cheap one, more like 2000€ for a professional one. I used mine a lot to analyze natural dyes and using them on 3D-printed objects (using the spectral data the device offers, too).
How it works
Very simply put: The device shines a bright light onto a surface at an angle and analyzes the light that gets scattered off it with a spectral sensor. That is compared to what a "white" reference sample looks like and is used to approximate a rough spectrum and calculate the color a human eye would see.
Why shine at an angle? So we don't just measure the light reflected off it. Reflected light (input angle ~ output angle) mostly has the spectrum (and therefore color) of the light source. Explicitly looking from another angle gives us only the true body color of the sampled surface.
Why compare against a white reference? This eliminates the unknown spectrum of the light source, the complicated influences the devices geometry has on the illumination and the unknown sensitivity of the sensor itself (mostly). More on the sensor later.
Why use a spectral sensor and not an RGB sensor instead? RGB only covers a small area ("gamut") of the visible light. Looking at multiple points of the spectrum instead of just 3 allows us to cover a wider area.
Instead of RGB, the device uses the CieLab color space as output. The L*, a* and b* coordinates are non-linearly scaled to represent the color perception of the human eye. Equal distances in either coordinate should register as an equal difference in perceived color. RBG is displayed, too, wherever that's possible.
The sensor
The main component of the device is the Adafruit AS7341, a digital 8-channel spectrometer board. It uses narrow band spectral filters on 8 individual photodiodes to measure different components of visible light. On top of that comes a measurement in the near infrared (NIR), plus an unfiltered one (clear). From these 10 channels the visible spectrum of the incoming light can be roughly interpolated. It is good enough for smooth spectra, but can be off for "spikey" spectra that fall outside the narrow measurement bands.
The light source
In order to see light scattered at every visible wavelength, we need a smooth light source that gives a sufficient amount of light over the entire visible spectrum. This device uses a Nichia Optisolis LED which is rated at 95 CRI and comes extremely close to the spectrum of black body radiation at 3000K (warm white). It actually doesn't matter which LED is used exactly, as the device only cares about the difference between the light coming off a white sample and that of the actual sample, both reduced by what the sensor sees from an ideal black (dark) sample, the reflectance. But a single Optisolis is not that expensive (1€) to justify using something less.
Other components
The device uses a Waveshare ESP32-C3 Zero to read the data off the spectrometer, react to the user pressing buttons, calculating and storing the results. It also has BLE to transfer the data to a smartphone. A 0.96" SSD1306 oled display (which are dirt cheap) is used to display stuff to the user. An optional (but strongly recommended) 700nm NIR filter (anything between 4.5mm to 10mm round or rectangular will do, at most 1mm thick) reduces the amount of NIR light that is messing with the other channels. Polarization filter plastic foil (a few € for an A4 sheet, enough to outfit 100s of such colorimeters) can help further reduce specular light from very glossy samples that will reflect in all sorts of directions.
Additional utilities
A beam trap is necessary to verify you don't get any internal reflections in your device and to quantify the spectrometer noise. I used an IKEA ENKELSPARIG stainless steel bottle, some black fabric and a printed adapter that reduces the opening to 22.5mm. I consistently read all zeros on the "dark" measurement, which means the beam trap works perfectly, the geometry of the measurement tip is good at not reflecting light back at the sensor itself, and the sensor is not seeing any ghosts.
You need a good white reference. If you can get some cheap spectralon online that is the preferred solution, but some flat wound PTFE tape does also work, so long as you use polarization filters: It's glossy, and way more perpendicularly than parallelly.
Limitations by design
The device has no battery and needs an external USB power source (powerpack, plug, mobile phone, computer...) to work. Working with batteries (especially LiPos) is tricky and introduces security concerns. It also makes it harder to connect the device via USB (e.g. to flash new software to it or transfer data) because of multiple voltage sources present.
Right now this has another consequence: This version does not yet feature a constant current sink. Different USB power sources have slightly different voltages and will drive the LED differently. If have a series of plans to improve on this, but for now that means that you need to do a white reference measurement whenever you change your power supply. It's not a big inconvenience, as you should do that anyways whenever you start a measurement series and - ideally - a few times in between, to be able to counter voltage drift or changes in internal temperature of the device.
Building one
If you are interested in building one of these for yourself, be advised that this requires more than just accurately printing some parts. You'll need to
Assemble quite a few components and post-process them if there are printing artifacts
Put in lots of tiny M2 heat-set inserts, a few in a little difficult position (at least in the current version)
Solder wires to breakout-boards
Solder half a dozen JST-PH sockets and 3 smaller electrical components to a tiny 6x10 perfboard and connect them with each other. (This will get a lot easier once I get around to designing a proper PCB board one can just order)
Flash an ESP32 with some firmware (which I have already written).
Generally: The current device is a (well usable) prototype. You should expect some less-than-perfectly documented assembly steps and some details I will gloss over in the instructions. Please let me know if anything needs clarification, something is completely missing or something seems stupid (it's well possible that it is). Writing documentation and instructions is hard. Expect some tinkering. The current design is just the latest state of an iterative design process, with some of the features no longer in use. Some earlier design decisions have come into conflict with later improvements. I have a long list of things I need to work over, but I wanted to document the current state and put the device "as is" out there. I plan to make further improvements to it, that will probably gradually update every piece of the device over time.
Tools & consumable materials
3D printer (duh)
soldering iron, solder, soldering equipment, blank wire, coated wire (helpful)
heat set insert tip for soldering iron (optional, but recommended)
soldering paste (for attaching the SMD LED onto the star PCB, but it can be done without)
cutting plotter (only if you want to have polarization filters, optional)
multimeter (for finding shorts and the like)
breakout board (in case you want to test things before everything comes together)
wire stripper
tweezers
screwdriver matching the M2 cap screws you use
a USB-C cable that supports data transfer (many USB-charger cables won't do)
BOM
Electronics
Part | Qty | Price estimate | Remarks and alternatives |
|---|---|---|---|
Adafruit AS7341 | 1 | ~15€ | Adafruit AS7343 should fit exactly, but requires some software changes and calibration Other AS7341 breakout boards will need changes to the SensorHolder part and potentially the LowerCase part |
Waveshare ESP32-C3 Zero | 1 | ~10€ | Cheaper ESP32-C3 Zero boards exist from other vendors. Their pinout varies a bit but shouldn't matter too much since it's all connected via wires anyways. The EspHolder part might need a remix. |
SSD1306 oled display | 1 | ~3€ | There is a lot of variants of this board on the market. The display is always the same, but the breakout boards have different sizes and hole positions. The one I used has a sqare 26x26mm board and a 2mm hole in each corner. If you get a different board, you will need to adjust the DisplayFitting and DisplayHolder parts. |
Nichia NF2L757GT-F1 Optisolis | 1 | ~1€ | Any other high CRI (80+) LED will do. Make sure it comes on a star PCB or that you get a matching one. I also tried with an Nichia NS2W/L757AT (CRI 80), worked fine. |
LED star PCB board for Nichia 757 (only if your LED doesn't come on one already) | 1 | ~1€ | Any other thin and flat board that is not too large can be made fit. You might need to change the LedHolder part in that case though. |
JST-PH 4pin socket | 4 | 1€ all | |
JST-PH 2pin socket | 3 | 1€ all | |
JST-PH cable (4 pins | 4 | 1€ each | Only need a few centimeters of cable from the plug. |
JST-PH to JST-SH cable (STEMMA QT to STEMMA / Qwiic) | 1 | 1€ each | Optional. Should only be about 5cm long. If you get this, you need one JST-PH 4-pin cable less, and you don't need to solder to your Adafruit AS7341 at all. |
JST-PH cable (2 pins) | 3 | 1€ each | Only need a few centimeters of cable from the plug. |
100 Ohm resistor | 1 | cents | To limit the current to the LED |
Perfboard | 1 | cents | 2.54mm pitch, 2x8cm (cut down to 6x10 pins) |
Tactile Push Button Switch | 2 | cents | 6x6x3.5mm, actuator 4mm, normally open (NO) |
Filament
Part | Qty | Price estimate | Remarks and alternatives |
|---|---|---|---|
Matte black filament | 15g | ~0.50€ | Needs to be black and as matte as possible to avoid light contamination for the optical relevant parts |
Arbitrary filament | 30g | ~1€ | For the upper parts of the device that don't need defined optical properties |
Fasteners
Part | Qty | Price estimate | Remarks and alternatives |
|---|---|---|---|
M2x4 cap screw | 2 | hex or star socket | |
M2x6 cap screw | 11 | hex or star socket | |
M2x8 cap screw | 12 | hex or star socket | |
M2x4 heat set inserts | 21 |
Others
Part | Qty | Price estimate | Remarks and alternatives |
|---|---|---|---|
PTFE sealing Tape | 1 | 2€ | Decent white reference, but with varying quality and anisotropy |
ColorChecker Card | 1 | 70€ | optional. I do without. If you want the best possible White reference and defined colors to calibrate your instrument, this is a straightforward way to do so. |
IKEA ENKELSPARIG | 1 | 5€ | For the beamtrap. Any other bottle will do, but you'll need to design an adapter for the colorimeter that fits tightly |
Black fabric | 30x30cm | e.g. Jersey. To cover the inside of the beam trap with it | |
700nm IR-cut filter | 1 | ~5€ for 2 | optional, but recommended. Needs to cover a 4.5mm hole and fit into a 11x11mm square hole, being less than 1mm thick. |
polarization filter foil | smallest you can get | 5€ for A4 | optional. You need to cut 2 very small (about 2x1cm) pieces from it. Doable with nail scissors, but I prefer the cutting plotter. |
Printing
All parts are optimized for FDM printing. No clue if SLA will cause any trouble, but I don't think there is anything really difficult to print in these models. I printed everything with a 0.4mm nozzle, at 0.2mm layer height. Some of the very tiny parts can be printed with a smaller nozzle, but it shouldn't be necessary.
I used PHA filament for every part of my device. The stuff is relatively difficult to print with, it warps, has adhesion issues, is a little soft right after printing and doesn't print as crisp and exact like e.g. PETG. Overhangs are a nightmare. If this prints nicely in PHA, you can get it to print in whatever else.
The ESP sometimes heats up to 60° C when using BLE. Just to be on the safe side I would not use PLA.
Assembly
Lower Case & Tip
Start with the lower parts of the device (tip and all the "Lower Case" parts). You only need one filter centering piece for the LED and sensor position, even if you don't use an IR-filter (yet).
Before you begin the assembly, you should start wiring the LED and AS7341 up.
If your LED doesn't come on a star PCB yet: You need to solder it onto one. The "proper" way to do that is to use soldering paste and a soldering heat gun. If you've got access to that: put some soldering paste on the LED pads of the PCB, put the LED on it (correct orientation!) and then move the heat gun at an appropriate temperature for your solder in a circle around it until the paste melts. Don't overheat the LED.
But you can also solder the LED on without a heat gun: Use a soldering iron with a fine tip and a tiny amount of solder wire to pre-tin one of the LED pads on the PCB. Add some flux on the tin, put the LED on it, and then heat the pad from the side until the LED sinks in. Then solder on the other pad from the side. Make sure the LED does not get too hot. Put the PCB on something metal to let the heat get away.

With the LED on the star PCB: Take one of the JST-PH cables and cut it off at 5cm after the plug. Strip about 5mm of insulation from the ends of each wire, twist the strands per wire, and pre-solder them lightly. Convention for the rest of this document: looking on the plug from where the wires enter it, with the "notches" of the plug pointing "up", the wires are numbered from left to right. Solder wire 1 to one of the - pads, and wire 2 to one of the + pads. Make sure you use 2 pads that have exactly one pad in between them. That's it for the LED.

If you have the JST-PH to JST-SH cable: Just plug in the JST-SH plug into one of the Stemma QT ports of the AS7341.
If you don't: Shorten one JST-PH 4-pin cable to about 4cm. Then solder the wires 1-4 of it to GND, Vin, SDA and SCL. This should be consistent to the Adafruit STEMMA pinout.
The Lower Case Body needs a number of heat set inserts inserted, 2 on the bottom and 2 on the top. The top ones are a bit recessed, and might be difficult to put in using the soldering iron insert tips. You can just put the inserts in the holes using the tweezers and then gently (!) put the soldering iron tip (normal one or insert one) on the top at a comfortable angle. Let the insert sink in on its own. The holes are deliberately sized a little larger than would be optimal for a tight fit to make insertion easier, but these screws don't hold any weight anyways.


If you have a NIR-filter: Place the filter over the sensor canal hole (the one in the center). Put a fitting centering piece on top of it, to keep it in place. If your filter is 9.5mm or 4.65mm in diameter and 0.55mm thick, I've got you covered, otherwise, you'll have to design your own centering piece. Don't put pressure on glass filters!


Next comes the sensor holder. Make sure the centering piece goes into the recess at its underside, that the light holes are oriented correctly and nothing slips out of position. If your filter is made of glass and some edge or corner presses on it, it will break. If everything sits correctly, put the AS7341 on top, facing down. The LED on the board should shine into the hole on top (we'll actually not use it at all, but that's what the hole was originally meant for). Put in 2 M2x8 and tighten gently. Make sure nothing slips out of place while doing so.


Put an LED filter centering piece into the angled receptacle. I don't have use for this filter position at the moment, so I don't put an actual filter there. The centering piece is nonetheless necessary for the correct height. Put the LED filter holder piece on top in the correct orientation.


Now put in the star PCB with the LED on it facing into the hole. Make sure the wires are in the top position, going through the recesses on both sides. Slide in the LED bracket. Screw in two more M2x8 through the brackets screw holes directly into the plastic underneath. If the holes are a bit too tight, you might need to widen them somehow.


If you want to use polarization filters, and you have access to a cutting plotter, use the dxf files to have them quickly and precisely made for you. Resist the temptation to orient the two almost-semicircles into one big almost-circle. Make sure to orient the pieces at 90° to each other (like a C and a U). Otherwise, the filters won't work.
Without a plotter, you can print the SVGs onto paper (mind the orientation!), use paper clips to secure the filter foil onto it and cut them out with nail scissors or a hobby knife.
Insert two M2x6 from the bottom through the tip. Place the filters on the upside of the tip. Make sure the orientation is correct: If you move any of the filters over the other (without turning them) the overlap should look black. If that doesn't work, try flipping one filter upside down. Put the larger filter over the screws and the smaller one over the plastic pins.
Make sure that the foils cannot move at all. You can carefully glue the filters to the tip in the corner outside the screws and pins (and print yourself a second tip for when you don't want to use polarization filters) if you want.


Attach the tip to the underside of the lower case.

Congratulations, this completes the assembly of the lower case, the part of the device that is actually doing all the interesting stuff.
Lid
This is the place the display and the "Mode button" goes into. So we start again with wiring up these components.

For the display you may first need to remove the row of pins these usually come with. The easiest way is to use small cutting pliers to cut through the black plastic between the pins, then carefully fix the display board in place and use a soldering iron to heat up each pin one after another until the tin melts and then quickly pull it out with pliers. Make sure not to damage the delicate display glass, the flexible cable on the side of the board, or any of the tiny components on the backside of the display board. Don't overheat the board.
Remove all the solder from the holes using a desoldering pump or desoldering wick. Then cut another JST-PH 4 pin cable with 3cm remaining and solder wires 1-4 to GND, VDD, SCK/SCL and SDA in that order.
Cut off another JST-PH 2-pin cable with about 4cm remaining wires and solder them to two of the legs of one of the 6x6x3.5mm pressure switches. Make sure you use 2 legs that are actually going through the switch with a multimeter, they should only be electrically connected when the button is pressed down. An easy way to attach wire to the legs is to fold the legs around the twisted, but untinned wire with pliers (like a primitive crimp). Then heat the leg and wire up with a soldering iron and add a drop of tin.
On to the assembly: We start with the "Lid" part and add 4 heat set inserts.

Then, insert the DisplayFitting part into the big recess in the lid. Put the display board on top facing down.
These SSD1306 0.96" boards unfortunately come in all manners of sizes, depending on the manufacturer. I designed the DisplayFitting and DisplayHolder for a board that is 26x26mm big, with a 2mm hole in each corner. If your display has different dimensions, you'll need to change these two parts.


Next, put the DisplayHolder on top and secure it with two M2x6 screws. Make sure the pressure is only applied to the mounting holes and the actual glass display is not pressed on.

Insert the pressure switch through the hole next to the display. Secure it with the ModeButtonHolder and two M2x6 screws.



This completes the Lid assembly.
The Upper Case
This is the middle section of the device, that contains the ESP microcontroller, all the wiring and another button.
Lets start with the wiring again. The ESP is connected with 2 JST-PH 4-pin cables. Reminder to our convention: Looking on the plug from where the wires enter it, with the "notches" of the plug pointing "up", the wires are numbered from left to right. Cut off the first one ("ESP A") at 2.5cm and solder the wires 1-4 to GPIO0, 3V3, GND and 5V0. Cut off a second cable ("ESP B") at 3.5cm and solder wires 1-4 to GPIO3, GPIO9, GPIO7 and GPIO6. If you use another ESP32-C3 Zero board than me (the one from Waveshare) make sure that the GPIO pin wire 2 is connected to is the strapping pin to put the ESP into flashing mode. That will make it easier to load firmware onto the device, if you don't want to have to stick a needle through the pinhole in the side of the device every time you want to do so (if these even fit with your board).
Now comes the most involved soldering task: The perfboard. It serves as a distribution hub for the I2C bus, button signals and LED driver. It is a bit of a pain to assemble, as the available space is very limited. I hope you will manage nonetheless. I am not great at soldering, and I needed a failed first attempt before I came up with the current design.

This uses one wire bridge on the top side of the perfboard (where all the JST-PH sockets are) and a couple of wires on the underside. It does need wires bridging over wires but never bridges over bridges. You can use thin flexible silicone insulated wire or enameled wire (this exists both as versions where you need to strip the insulation first where you want to solder and such where the insulation will dissolve on its own at soldering temperatures).
For the Optisolis LED I use 100Ohm for the resistor R. It gives me some ~25mA of LED current, which is less than half its maximum current and is plenty bright. If you use another LED, make sure to choose a resistor that will put the current draw into the same ballpark region at 5V, so that the device doesn't overheat.
One important detail: JST-PH uses 2mm pitch (distance between pins), whereas perfboards traditionally use 2.54mm pitch. The 2 pin sockets will fit nonetheless, but 4 pin sockets need some careful bending of the outer legs. It is not ideal, but better than switching to larger connectors.


After the soldering, use a multimeter and test all the pins for connectivity and (even more important) those pins for non-connectivity that shouldn't be connected! It seems like a tedious task, but it's better than frying your ESP. If your multimeter can do it, let it make sounds whenever it detects a connection.
Last but not least: Prepare the second pressure switch just like the Mode button. The JST-PH cable shouldn't be longer than 2.5cm.
With that out of the way, on to the assembly:
We start with inserting 13 (!) M2 heat set inserts into the UpperCase part.

First comes the Trigger assembly. That is the big button that starts measurements. Insert TriggerOuter from the outside and put TriggerInner from the inside and connect them with 2 M2x6 screws.


Then, insert the pressure switch and fix the TriggerHolder behind it with 2 M2x4 screws.


On the left of the trigger, put the ESP against the wall, with the USB-C port into the prepared hole. Put the EspHolder part on top and fix with an M2x6 screw.


On the opposite side, slide the Perfboard into the slot in the bottom and align the attachment holes with the inserts. Use 2 M2x6 screws to attach it.


Last step: Slide in the "BlankAccessoryBoard" into the slot on the back of the device.

That completes the assembly of the Upper Case.
Plugging it together
Start by plugging the ESP A and ESP B cables into the Perfboard. Make sure not to mix them up, ESP A goes into the upper socket, ESP B into the lower one. Up is where the trigger is. The length difference in the cables should make the right order obvious.
Next, plug in the trigger. Use tweezers to make it easier to reach into the case. Don't mix up the trigger and mode connector, your usability will suffer.
Then continue with the Lower Case. It's heavier and angled, to going with it first is easier than the other way around. Plug in the sensor cable first, then continue with the LED cable.
Last comes the Lid. The cables are short, but if they were longer, it'd be difficult to close it up. Plug in the mode button cable into the mode connector first, then plug in the display.
In the end, your view should be something like this:


Attach both the Lid and the Lower case with 4 M2x8 screws each.
First test and flashing of the firmware
The Colorimeter does not come with a battery of its own. You need to plug it into a USB power source.
Once you do, 2 visible things should happen:
The LED should turn on. If will be very bright.
The screen will turn on and show you "snow".
That is everything you should be able to observe for now (except potential smoke if you misconnected something).
If you plug in the device into a computer with a data-capable USB cable (many charger cables can't do that anymore nowadays), it will be detected as a JTag Serial USB device (used for debugging and sending console output over). If you hold down "Mode" while plugging in the device, you should get an additional/different device. That is what you need to do instead of pressing the "boot" hardware button on the ESP if you want to load firmware onto it.
With that, head over to the repository where the code is hosted in to get information on how to flash some actual firmware onto it. A manual on how to use it and the further development of hardware and software will be available there, too.