If you've been following along with the Prism Laser Scanner, you know that moving from a wobbly galvanometer to a high-speed rotating prism introduces a whole new nightmare of optical aberrations. In my previous logs, we could clearly see massive orthogonal errors (pyramidal tilt between facets) and scan line jitter (timing differences). This is due to that each facet pair is not perfectly planar and at 90 degrees, also the mounting is not exactly at 90 degrees.
I am thrilled to report that the main technical challenge seems fixed. We can now correct for facet distortion both along (scan) and orthogonal (orth) to the scanline and create perfect exposures. The hardware might be cheap and DIY, but the correction algorithm now guarantees industrial-grade results. It allows you to use all four facets and not use additional lenses and still have top results. More proof will follow, just look at the commit history https://github.com/hstarmans/hexastorm/commits/master/ and results below to gauge the effort required.
Here is how we got there.
1. The Median Average Reference
Previously, the calibration relied on picking a single facet as the "master" reference. The problem? If that specific facet was an outlier, it skewed the entire baseline. Furthermore, the coefficients of one facet were fixed to zero, so we didn't use all coefficients.
I achieved a major stability upgrade by ditching the single-facet reference. The system now calculates a virtual "median average" across all facets. This spatial median acts as a perfect, idealized virtual facet that we use to anchor the correction math, preventing any single highly-skewed facet from throwing off the calibration table.
2. Proving Statistical Stability
To prove this wasn't just a one-off lucky measurement, I automated a baseline calibration cycle to take 10 consecutive measurements. The results show that our underlying hardware timing is remarkably stable. A challenge with my previous log is that you just look at one result. How repeatable is this?
Here is the raw statistical payload using 10 measurements per facet. Notice the standard deviations (std_um): our orthogonal jitter is hovering between 0.25 and 0.8 microns, and scan jitter is around 0.5 to 1.0 microns. We have a spot diameter of 40 microns and eccentricity of around 1.5. The spot can be made smaller and circular with cylindrical lenses so take this into account. Also, vibration artifacts can be removed further with cylinder optics.
| Facet | Scan Shift (mm) | Orth Shift (mm) | Angle (°) | Scan Std (µm) | Orth Std (µm) | Scan Spread PtP (µm) | Spot Size (µm) |
|---|---|---|---|---|---|---|---|
| 0 | 0.0229 | 0.0109 | -86.5079 | 1.063 | 0.257 | 3.118 | 40.366 |
| 1 | -0.0452 | -0.0306 | -86.3956 | 1.020 | 0.244 | 2.973 | 43.464 |
| 2 | 0.0032 | -0.0109 | -86.5607 | 0.476 | 0.257 | 1.853 | 40.266 |
| 3 | -0.0032 | 0.0569 | -86.3327 | 0.476 | 0.809 | 1.853 | 41.549 |
3. Verification: The 2D Dot Grid Simulation
To visually and mathematically prove the correction works, I wrote a routine that measures the 2D error by projecting a dot grid pattern.
Because my global shutter camera is stationary, we can't physically move the stage to expose a 2D area. I create a SVG with a dot grid, send it to the slicer using calbiration and projects it onto the camera sensor line by line. It then simulates the physical movement of the stage by stacking these individual 1D exposures into a single 2D image using a custom LaserStackSimulator class.
The routine evaluates the hardware twice: once without correction, and once with the active calibration profile fed into the slicer. It verifies if the optical correction forces the dots from all 4 facets to align perfectly. There is an algorithm which detects the centroids of the final dot pattern an matches them. It then computes the average offset.
The Results
The log output speaks for itself:
15:28:48 - INFO - Uncorrected 2D Errors (um) [Scan, Orth]: [[20.073, 11.351], [-46.93, -28.717], [2.655, -11.351], [-2.655, 59.795]] 15:28:48 - INFO - Corrected 2D Errors (um) [Scan, Orth]: [[-1.139, 0.704], [-2.443, 1.537], [2.555, -2.106], [1.667, -1.246]] 15:28:48 - INFO - --- 2D Calibration Summary --- 15:28:48 - INFO - Overall MAE Before: 22.94 um | MAE After: 1.67 um 15:28:48 - INFO - Overall Max Error Before: 59.80 um | Max Error After: 2.56 um 15:28:48 - INFO - Post-Correction Max Scan: 2.56 um | Max Orth: 2.11 um 15:28:48 - INFO - SUCCESS: 2D System calibrated to within +/- 30.0 microns.
Without correction, dots were landing up to ~80 microns away from their target (see -28 and +60 error for orthogonal error). After applying the dynamic calibration matrix, the maximum error was crushed down to 2.56 microns. The Mean Absolute Error dropped to just 1.67 microns. This engine now projects flawlessly. Results are wicked good, most likely your development chemistry will be a bigger limit than the laser head. There is a wide range of applications among other laser induced forward transfer.
Caveats & Next Steps
While the algorithm is sound, bringing this into the physical world has a few remaining challenges:
- Real-World Exposures: I still need to run test images on actual PCBs and UV-sensitive cyanotype paper to see how the sub-pixel digital correction translates to chemical exposure.
- Physical Modularity: Right now, the laser head needs to physically switch between the camera (for calibration) and the machine bed (for exposure). In the future it should be in one machine but it is now in different setups.
- Alignment Sensitivity: The calibration matrix is incredibly sensitive to changes in the pointing of the laser bundle. Even a microscopic bump while moving the head from the camera to the machine might alter the facet timing or invalidate the calibration matrix. The errors don't change a lot but it is easy to get a different labeling of the facets. This sensitivity should be reduced if we switch between setups.
In the final, integrated design, the machine will likely need to perform a rapid calibration matrix scan in situ right before an exposure begins. This should be easy as the ESP32 can connect with a camera and global shutter suffices.
The math has been conquered, More to come as we start burning actual PCBs!
Hexastorm
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.