Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

3D Printer Calibration via a Camera-Based Virtual Encoder

Calibration of the motion axes of a 3D printer (steps/mm, backlash, and XY skew / orthogonality) without a dial indicator and without an encoder - using a single camera and a chessboard target as a virtual encoder. The result is validated by running an elliptical toolpath and measuring the deviation from ground truth.

Clone:

git clone https://github.com/ZaydZaidan/3D-Printer-Calibration-Using-Virtual-Encoder.git

Start here: docs/00_handoff_guide.md - a step-by-step handoff guide with the expected output of every stage.


Key Results

Machine calibration (linear test, 10 mm commanded move, 10 valid samples out of 40 trials):

Metric Baseline After calibration Improvement
X axis error 0.0463 mm 0.0071 mm 84.6 %
Y axis error 0.0550 mm 0.0054 mm 90.2 %
Y drift while moving X 0.0937 mm 0.0043 mm 95.4 %
X drift while moving Y 0.0898 mm 0.0036 mm 96.0 %

Starting parameters: steps/mm X 80, Y 80; backlash comp 0; skew comp 0. Final parameters: steps/mm X 79.72, Y 80.40; backlash X 13.3 µm, Y 31.4 µm; skew -9.2 µm/mm (X-on-Y), 9.213 µm/mm (Y-on-X) - about ±0.52°.

Elliptical toolpath evaluation (RMSE against ground truth):

Metric Baseline After calibration
RMSE X 76.91 µm (std 5.33) 34.42 µm (std 1.61)
RMSE Y 65.29 µm (std 4.67) 30.75 µm (std 1.30)
RMSE total 100.89 µm (std 7.00) 46.17 µm (std 1.68)

Total trajectory accuracy improvement: 54.24 %. Every number above was regenerated by re-running the notebooks in this repository, not copied from the thesis manuscript.

About the final values - important. 79.72 / 80.40 is not the result of a single calculation. The calibration is an iterative loop: each round, the newly recommended parameters are written back into the machine, a fresh dataset is captured, the error is measured again, and so on until the error stops moving (steady state) and has fallen to the order of the measuring instrument's own measurement error. The chain: 80.00 (baseline) -> 79.6314 (round-1 recommendation) -> several intermediate rounds -> 79.72 (final). So if you run the notebooks on the included dataset and get a recommendation of 79.6314, that is not a bug - it is round one, not the final value. Full procedure: docs/00_handoff_guide.md Step 2b.

Measurement error (validation against a dial indicator, 0.5 mm commanded move, 5 iterations): the mean absolute difference between the virtual-encoder reading and the dial indicator is 4.96 µm (X axis combined) and 7.81 µm (Y axis combined) - inside the ±10 µm resolution of the dial indicator itself.


Pipeline

 [1] CAMERA calibration
     EDLines -> line screening -> subpixel corner refinement -> corner sorting (homography)
     -> cv2.calibrateCamera -> intrinsic matrix K + distortion coefficients D
     (output: data/processed/camera_calibration/*.csv)
                     |
                     v
 [2] MACHINE calibration (per-axis linear test)
     Dataset from automated_linear_test.py, starting parameters 80/80/0/0
     -> solvePnP per image -> dX/dY, backlash, skew
     -> firmware recommendations M92 (steps/mm), M425 (backlash), M852 (skew)
                     |
                     v
 [2b] Apply the recommendation, capture a new dataset, measure again
      -> repeat until the error reaches steady state
                     |
                     v
 [3] Run the elliptical toolpath with the new parameters
     -> record video of the calibrated toolpath (baseline toolpath recorded earlier)
                     |
                     v
 [4] Virtual Encoder
     Every video frame: detect the target -> solvePnP -> tvec
     -> position relative to the first valid frame -> trajectory X(t), Y(t) in mm
     -> export CSV
                     |
                     v
 [5] Trajectory evaluation
     Ground truth = 2 intersecting ellipses (45 deg and 135 deg), forward + backward
     Nearest neighbour (cKDTree) -> RMSE X, Y, total in micrometres (µm)
     Baseline vs calibrated -> percentage improvement

 [6] Measurement error (separate experiment, validated with a dial indicator)
     Baseline parameters, commanded move reduced to 0.5 mm
     -> compare the virtual-encoder reading against the dial indicator

Notebooks and Scripts

Stage File Input Output
1 01_camera_calibration/camera_calibration.ipynb chessboard images camera_matrix.csv, dist_coeffs.csv, camera_params.csv, reprojection_rmse.csv
2 02_machine_calibration/machine_calibration.ipynb K/D + oriy/fwd/bck dataset M92/M425/M852 recommendations, visualization_*.png
3 03_virtual_encoder/virtual_encoder.ipynb pose_video_XX.avi trajectory CSV + comparison figures
4 04_trajectory_evaluation/trajectory_evaluation.ipynb two trajectory CSVs evaluation figures, RMSE in µm, % improvement
6 06_measurement_error/plot_measurement_error.py dial_vs_ve.csv 4-panel figure + MAE table

Supporting files:

  • config_paths.py - every dataset path lives here. Check your data with python config_paths.py.
  • calibration_pipeline.py - the corner-detection functions (EDLines, screening, subpixel refinement, sorting) shared by all notebooks.
  • 05_data_acquisition/ - scripts that require the machine and camera (see the README there).

Getting the Data

The raw data (images, videos, raw CSVs - about 1.9 GB) is not committed to git because of GitHub's 100 MB per-file limit. It is available here:

Google Drive: https://drive.google.com/drive/folders/1-t_4XDX1aLUvNeTrkfXd1f1-iWcVR9tP?usp=sharing

The folder is named raw and contains the full contents of data/raw/.

Download it and place the folder as data/raw/ inside your clone. Then verify with python config_paths.py - every line should read OK.

Expected contents, useful for checking that nothing is missing after downloading:

Folder Files Size
camera_calibration 107 19.2 MB
circular_baseline 20 4.3 MB
circular_calibrated 33 8.4 MB
linear_baseline_x 120 22.0 MB
linear_baseline_y 120 22.0 MB
linear_calibrated_x 120 22.4 MB
linear_calibrated_y 120 21.4 MB
measurement_error 361 68.2 MB
noise_static_capture 24 4.2 MB
video_baseline_x 21 1016.0 MB
video_baseline_y 1 35.6 MB
video_calibrated_x 11 573.1 MB
video_calibrated_y 1 38.9 MB
video_kalibrasi_x 3 104.2 MB
Total 1062 1960 MB

measurement_error holds six subfolders: x/y_machine_movement (120 + 120), x/y_camera_calibration (54 + 31), and x/y_dial_gauge (18 + 18 dial indicator photos).

noise_static_capture holds the 24 stills of the stationary capture sequence described in data/MANIFEST.md section 3.1. It is needed by 07_paper_figures/verify_environmental_noise.py, which re-derives the environmental-noise figure from the raw images.

The mapping between the original folder names in the thesis and the names used here is in data/MANIFEST.md.


Folder Structure

Folder Rapih Code & Data Thesis/
|- README.md
|- config_paths.py                  <- all dataset paths (run it to check your data)
|- calibration_pipeline.py          <- shared corner-detection functions
|- requirements.txt
|- 01_camera_calibration/camera_calibration.ipynb
|- 02_machine_calibration/machine_calibration.ipynb
|- 03_virtual_encoder/virtual_encoder.ipynb
|- 04_trajectory_evaluation/trajectory_evaluation.ipynb
|- 05_data_acquisition/                <- requires the machine and camera
|- 06_measurement_error/plot_measurement_error.py   <- dial indicator vs virtual encoder
|- 07_paper_figures/                <- the scripts that draw every paper figure
|- Overleaf Latex Paper/            <- the manuscript (LaTeX) + REVISION_NOTES.md
|- data/
|  |- MANIFEST.md                   <- original folder name -> repo name mapping
|  |- raw/                          <- raw data + video (1.9 GB, NOT in git)
|  \- processed/                    <- output of each stage (in git)
|- figures/                         <- per-trial evaluation plots
|  \- paper/                        <- every figure used in the paper (PNG + PDF)
\- docs/
   |- 00_handoff_guide.md                 <- HANDOFF GUIDE (start here)
   |- 01_code_audit.md              <- audit of the original code + cleanup plan
   |- 02_file_roles.md              <- role of every research file
   \- 03_results_and_data_locations.md   <- result numbers and data locations

Manuscript figures

figures/paper/ holds the exact figure files that go into the paper (PNG + PDF), and 07_paper_figures/ holds the scripts that produce them. Each script takes its numbers from the tables of the thesis and writes into figures/paper/:

Script Produces
07_paper_figures/plot_axis_iterations.py x_axis_iterations, y_axis_iterations, mae_summary
07_paper_figures/plot_trajectory_rmse.py trajectory_rmse_iterations_final, trajectory_summary_bars_final
07_paper_figures/plot_environmental_noise.py environmental_noise_with_std (legend revised: SD of the readout, not of |delta|)
06_measurement_error/plot_measurement_error.py 1_4_position_comparison_combined

07_paper_figures/verify_environmental_noise.py re-derives the environmental-noise values from the raw stills instead of trusting the hard-coded array, and prints both statistics definitions side by side. Run it (python verify_environmental_noise.py) to audit that figure.

The three plot_*.py files are faithful copies of the author's original plotting code from After Lulus Paper/code/: data, layout and labels are untouched — only the comments were translated and the output folder redirected into the repo. All 14 files in figures/paper/ were regenerated from these scripts (they were pixel-for-pixel identical to the originals at the time of the copy).

Two of them were then revised deliberately and no longer match the original renders: environmental_noise_with_std (the legend reports the SD of the readout instead of the SD of the absolute deviations) and 1_4_position_comparison_combined (panel annotation MAE instead of Mean Diff). Both were re-rendered at 300 dpi. Details in Overleaf Latex Paper/REVISION_NOTES.md and docs/03_results_and_data_locations.md section 6.


The manuscript

Overleaf Latex Paper/ is the current manuscript as a self-contained LaTeX project: main_new.tex (monolithic), Bibliography.bib, IEEEtran.cls, the eleven figures it includes in images/, and main_new.pdf built from that source. To rebuild the PDF:

pdflatex main_new.tex && bibtex main_new && pdflatex main_new.tex && pdflatex main_new.tex

REVISION_NOTES.md in the same folder lists every value that was checked against the raw data and corrected, with the derivation of each new number: the dial-gauge comparison is reported as a mean absolute discrepancy (4.96 / 7.81 µm) rather than the magnitude of a mean offset; the stationary-noise numbers use a single definition (mean absolute deviation 2.58 / 4.97 µm, SD of the repeated readout 2.63 / 3.44 µm); the distortion vector lists all five calibrated coefficients including k3 = -5.0330; and the uncertainty budget was rebuilt (u_c 6.23 / 6.79 µm, U 12.46 / 13.57 µm at k = 2).

The manuscript supersedes the older thesis chapter under Semester 8/Template_Skripsi_latex/. Where the two disagree, the manuscript and this repository are authoritative.


Running

pip install -r requirements.txt
python config_paths.py          # check that every dataset is found

cv2.ximgproc (EdgeDrawing) is only available in opencv-contrib-python, not in plain opencv-python. Versions used in this research: Python 3.11.9, opencv-contrib-python 4.12.0.88, numpy 2.2.6, scipy 1.17.1, pandas 3.0.2, matplotlib 3.10.8.

Run each notebook from inside its own folder so that config_paths.py at the repo root can be found.

Pick the test mode with an environment variable, without editing any notebook:

set KALIBRASI_MODE=baseline        # Windows   (baseline | calibrated | measurement_error)
export KALIBRASI_MODE=baseline     # Linux / macOS
Mode Dataset steps/mm target
calibrated (default) linear_calibrated_x/y 79.72 / 80.40 10 mm
baseline linear_baseline_x/y 80 / 80 10 mm
measurement_error measurement_error/*_machine_movement 80 / 80 0.5 mm

Detailed per-stage instructions, expected outputs, and known limitations are in docs/00_handoff_guide.md.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages