1<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>Making a 3d scanner for under $20</title><link rel="icon" href="/favicon.png"/><meta name="author" content="Cyrus Roshan"/><meta name="description" content="My hackathon project, a 3d scanner made out of cardboard"/><meta property="og:title" content="Making a 3d scanner for under $20"/><meta property="og:type" content="article"/><meta name="og:description" content="My hackathon project, a 3d scanner made out of cardboard"/><meta name="image" property="og:image" content="https://blog.cyrusroshan.com/post-images/showcases/spin-to-win.jpeg"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:site" content="@cyrusroshan"/><meta name="twitter:creator" content="@cyrusroshan"/><meta name="twitter:title" content="Making a 3d scanner for under $20"/><meta name="twitter:description" content="My hackathon project, a 3d scanner made out of cardboard"/><meta name="twitter:image" content="https://blog.cyrusroshan.com/post-images/showcases/spin-to-win.jpeg"/><link rel="stylesheet" href="/css/[email protected]"/><meta name="next-head-count" content="17"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin=""/><link rel="preload" as="style" data-href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Source+Serif+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&family=EB+Garamond:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,500;1,600;1,700;1,800&display=swap"/><link rel="stylesheet" data-href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Source+Serif+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&family=EB+Garamond:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,500;1,600;1,700;1,800&display=swap"/><style data-emotion-css=""></style><style> 2 * { 3 box-sizing: border-box; 4 } 5 body { 6 background-color: #0e707e; 7 padding: 0; 8 margin: 0; 9 } 10 </style><link rel="preload" href="/fonts/Charter/webfonts/charter_regular-webfont.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/Charter/webfonts/charter_bold-webfont.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/Charter/webfonts/charter_italic-webfont.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/Charter/webfonts/charter_bold_italic-webfont.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/ia-writer-quattro/Static/iAWriterQuattroS-Bold.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/ia-writer-quattro/Static/iAWriterQuattroS-BoldItalic.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/ia-writer-quattro/Static/iAWriterQuattroS-Italic.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/ia-writer-quattro/Static/iAWriterQuattroS-Regular.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/ia-writer-quattro/Variable/iAWriterQuattroV-Italic.ttf" as="font" crossorigin=""/><link rel="preload" href="/fonts/ia-writer-quattro/Variable/iAWriterQuattroV.ttf" as="font" crossorigin=""/><style> 11 @font-face{ 12 font-family: 'Charter'; 13 src: url('/fonts/Charter/webfonts/charter_regular-webfont.eot'); 14 15 src: url('/fonts/Charter/webfonts/charter_regular-webfont.eot?#iefix') format('embedded-opentype'), 16 url('/fonts/Charter/webfonts/charter_regular-webfont.woff') format('woff'), 17 url('/fonts/Charter/webfonts/charter_regular-webfont.ttf') format('truetype'), 18 url('/fonts/Charter/webfonts/charter_regular-webfont.svg#webfont') format('svg'); 19 20 format('truetype'); 21 font-weight: 400; 22 font-style: normal; 23 } 24 25 26 @font-face{ 27 font-family: 'Charter';
28 src: url('/fonts/Charter/webfonts/charter_bold-webfont.eot'); 29 30 src: url('/fonts/Charter/webfonts/charter_bold-webfont.eot?#iefix') format('embedded-opentype'), 31 url('/fonts/Charter/webfonts/charter_bold-webfont.woff') format('woff'), 32 url('/fonts/Charter/webfonts/charter_bold-webfont.ttf') format('truetype'), 33 url('/fonts/Charter/webfonts/charter_bold-webfont.svg#webfont') format('svg'); 34 35 format('truetype'); 36 font-weight: bold; 37 font-style: normal; 38 } 39 40 41 @font-face{ 42 font-family: 'Charter'; 43 src: url('/fonts/Charter/webfonts/charter_italic-webfont.eot'); 44 45 src: url('/fonts/Charter/webfonts/charter_italic-webfont.eot?#iefix') format('embedded-opentype'), 46 url('/fonts/Charter/webfonts/charter_italic-webfont.woff') format('woff'), 47 url('/fonts/Charter/webfonts/charter_italic-webfont.ttf') format('truetype'), 48 url('/fonts/Charter/webfonts/charter_italic-webfont.svg#webfont') format('svg'); 49 50 format('truetype'); 51 font-weight: 400; 52 font-style: italic; 53 } 54 55 56 @font-face{ 57 font-family: 'Charter'; 58 src: url('/fonts/Charter/webfonts/charter_bold_italic-webfont.eot'); 59 60 src: url('/fonts/Charter/webfonts/charter_bold_italic-webfont.eot?#iefix') format('embedded-opentype'), 61 url('/fonts/Charter/webfonts/charter_bold_italic-webfont.woff') format('woff'), 62 url('/fonts/Charter/webfonts/charter_bold_italic-webfont.ttf') format('truetype'), 63 url('/fonts/Charter/webfonts/charter_bold_italic-webfont.svg#webfont') format('svg'); 64 65 format('truetype'); 66 font-weight: bold; 67 font-style: italic; 68 } 69 70 71 @font-face{ 72 font-family: 'Quattro'; 73 src: local('Quattro'), url('/fonts/ia-writer-quattro/Static/iAWriterQuattroS-Bold.ttf') format('truetype'); 74 font-weight: bold; 75 font-style: normal; 76 } 77 78 79 @font-face{ 80 font-family: 'Quattro'; 81 src: local('Quattro'), url('/fonts/ia-writer-quattro/Static/iAWriterQuattroS-BoldItalic.ttf') format('truetype'); 82 font-weight: bold; 83 font-style: italic; 84 } 85 86 87 @font-face{ 88 font-family: 'Quattro'; 89 src: local('Quattro'), url('/fonts/ia-writer-quattro/Static/iAWriterQuattroS-Italic.ttf') format('truetype'); 90 font-weight: 400; 91 font-style: italic; 92 } 93 94 95 @font-face{ 96 font-family: 'Quattro'; 97 src: local('Quattro'), url('/fonts/ia-writer-quattro/Static/iAWriterQuattroS-Regular.ttf') format('truetype'); 98 font-weight: 400; 99 font-style: normal; 100 } 101 102 103 @font-face{ 104 font-family: 'Quattro'; 105 src: local('Quattro'), url('/fonts/ia-writer-quattro/Variable/iAWriterQuattroV-Italic.ttf') format('truetype'); 106 font-weight: 300 700; 107 font-style: italic; 108 } 109 110 111 @font-face{ 112 font-family: 'Quattro'; 113 src: local('Quattro'), url('/fonts/ia-writer-quattro/Variable/iAWriterQuattroV.ttf') format('truetype'); 114 font-weight: 300 700; 115 font-style: normal; 116 } 117 </style><noscript data-n-css=""></noscript>
117<script defer="" crossorigin="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script>
117<script src="/_next/static/chunks/webpack-f5884cdb8fdc0822.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/framework-314c182fa7e2bf37.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/main-ac92f1018a62db48.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/pages/_app-012ecb4247b9174b.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/e8df7cac-21b5e5d43903d97a.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/b5f2ed29-004880ae1756aa88.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/75fc9c18-546a41d87ada497a.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/5241-e1c692af38d9cc06.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/8102-3c8bb89c5de765da.js" defer="" crossorigin=""></script>
117<script src="/_next/static/chunks/pages/post/%5Bid%5D-1c9fad4fb9aef967.js" defer="" crossorigin=""></script>
117<script src="/_next/static/b2v3BGFw9dHacc7buszmk/_buildManifest.js" defer="" crossorigin=""></script>
117<script src="/_next/static/b2v3BGFw9dHacc7buszmk/_ssgManifest.js" defer="" crossorigin=""></script>
117<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Source+Serif+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900&family=EB+Garamond:ital,wght@0,400;0,500;0,600;0,700;0,800;1,400;1,500;1,600;1,700;1,800&display=swap"/></head><body><div id="__next"><style data-emotion="css 98vyad">.css-98vyad{border-top:12px solid #00C3DE;border-bottom:12px solid #00C3DE;background-color:rgb(255, 247, 232);height:100vh;width:100%;position:fixed;top:0;left:0;}</style><div class="css-98vyad eh2jo50"></div><style data-emotion="css gtzoyu">.css-gtzoyu{left:0;top:0;width:100%;height:100%;position:absolute;}</style><div class="css-gtzoyu eh2jo51"><style data-emotion="css 1fboyyj">.css-1fboyyj{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;background-color:#FDFDFD;border-top:12px solid #012da5ff;border-bottom:4px solid #012da5ff;}</style><div class="css-1fboyyj eh9azmg3"><style data-emotion="css 11vwusn">.css-11vwusn{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;width:100%;gap:32px;padding:24px;padding-bottom:12px;padding-top:12px;}@media screen and (max-width:500px){.css-11vwusn{-webkit-box-pack:space-around;-ms-flex-pack:space-around;-webkit-justify-content:space-around;justify-content:space-around;}}</style><div class="css-11vwusn eh9azmg0"><style data-emotion="css q0as51">.css-q0as51{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;font-family:monospace;font-weight:600;font-size:20px;margin:0;padding:0;}@media screen and (max-width: 500px){.css-q0as51{font-size:20px;}}</style><h3 class="css-q0as51 eh9azmg2"><style data-emotion="css 1lnhynx">.css-1lnhynx{color:'#0e2d81ff';text-decoration-color:#bbbbbb;}</style><a href="/" class="css-1lnhynx eh9azmg4">[home]</a></h3><h3 class="css-q0as51 eh9azmg2"><a href="/latest" class="css-1lnhynx eh9azmg4">[latest]</a></h3><h3 class="css-q0as51 eh9azmg2"><a href="https://cyrusroshan.com/" class="css-1lnhynx eh9azmg4">[about]</a></h3><style data-emotion="css 1a2yelx">@media screen and (max-width:500px){.css-1a2yelx{display:none;}}</style><div style="margin-left:auto" class="css-1a2yelx eh9azmg1"><h3 class="css-q0as51 eh9azmg2"><a href="https://blog.cyrusroshan.com" class="css-1lnhynx eh9azmg4">blog.cyrusroshan.com</a></h3></div></div></div><style data-emotion="css wzjm59">.css-wzjm59{padding:6%;padding-top:0;margin-top:80px;}@media screen and (max-width:500px){.css-wzjm59{padding:0;}}</style><div class="css-wzjm59 eh2jo52"><style data-emotion="css ojjup3">.css-ojjup3{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-bottom:60px;}</style><div class="css-ojjup3 e1w64hg30"><style data-emotion="css 17e3wdn">.css-17e3wdn{max-width:850px;width:100%;position:relative;}</style><div class="css-17e3wdn e1w64hg31"><style data-emotion="css 13hdmki">.css-13hdmki{z-index:100;position:absolute;top:0;left:0;padding:20px;padding-left:24px;padding-right:24px;pointer-events:all;width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;-webkit-box-pack:end;-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;gap:8px;}</style><div class="css-13hdmki e1bm441m2"><style data-emotion="css 1hyvr7q">.css-1hyvr7q{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:4px;-webkit-align-items:flex-end;-webkit-box-align:flex-end;-ms-flex-align:flex-end;align-items:flex-end;}</style><div class="css-1hyvr7q e1bm441m0"><style data-emotion="css 1iwplfp">.css-1iwplfp{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-family:'Quattro';color:grey;font-size:14px;margin:0;}</style><p class="css-1iwplfp e1bm441m4">05 April 2016</p><p class="css-1iwplfp e1bm441m4">No. <!-- -->4</p></div></div><style data-emotion="css to9gli">.css-to9gli{position:relative;border:2px solid #654c15;border-radius:8px;background-color:#FDFDFD;padding-left:min(120px,10%);padding-right:min(120px,10%);padding-bottom:64px;box-shadow:3px 5px 5px 2px hsl(40deg 31% 60%);pointer-events:all;}@media screen and (max-width:500px){.css-to9gli{border-radius:0;}}@media screen and (max-width:390px){.css-to9gli{padding-bottom:40px;}}</style><div class="css-to9gli eh2jo53"><style data-emotion="css 1v21tyn">.css-1v21tyn{line-height:1.6;}.css-1v21tyn h1,.css-1v21tyn h2,.css-1v21tyn h3,.css-1v21tyn h4,.css-1v21tyn h5,.css-1v21tyn h6{margin-bottom:0;line-height:initial;}</style><div class="css-1v21tyn e2dthv61"><style data-emotion="css urtojf">.css-urtojf{padding-top:120px;}@media screen and (max-width:390px){.css-urtojf{padding-top:110px;}}</style><div class="css-urtojf e2dthv60"><style data-emotion="css 1gqui9x">.css-1gqui9x{color:#111111;font-size:44px;font-weight:600;font-family:Lora,Quattro;}@media screen and (max-width: 500px){.css-1gqui9x{font-size:32px;}}</style><h1 style="margin-top:0;margin-bottom:12px" class="css-1gqui9x evim1t92">Making a 3d scanner for under $20</h1></div><style data-emotion="css 1immo82">.css-1immo82{height:6px;background:#00C3DE;}</style><div class="css-1immo82 epzua1f0"></div><div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At this Spring's HackPrinceton, my friend <a href="http://yarabarla.com/">AK</a>
117 and I built a fast and efficient 3d scanner out of spare parts. I think it's very cool.</p> 118<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"> 119<iframe title="YouTube video player" width="480" height="300" src="https://www.youtube.com/embed/6dSABwcAYv8?rel=0&showinfo=0" frameBorder="0" allowfullscreen=""></iframe> 120</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The final product. The slower the motors run, the more accurate the scan.</span></div></span></div> 121<p class="css-wurtue evim1t98">Both the <a href="https://www.devpost.com/software/spin-to-win">project submission</a> and the <a href="https://github.com/CyrusRoshan/Spin-to-Win">source code</a> are online.</p> 122</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="how-does-it-work" class="css-1oc01jt evim1t94">How does it work?</h2> 123<p class="css-wurtue evim1t98">For measurement, we used a reflective IR LED. More detail on this later, but basically I'm using it here as a close-range distance measurement tool.</p> 124<!-- --> 125<p class="css-wurtue evim1t98">In order to measure a 3d surface, two other components come into play, each adding a separate dimension to the scan. The first is a vertical shaft which raises and lowers the reflective IR LED. The second is a DC motor, which rotates the scanned object, allowing the scanner to measure its sides.</p> 126<!-- --> 127</div><div><h2 id="scan-accuracy" class="css-1oc01jt evim1t94">Scan accuracy</h2> 128<p class="css-wurtue evim1t98">You're probably wondering how accurate this project's scans actually were. It's literally a <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">ten-cent RIR LED on a stick</em>, held together by cardboard.</p> 129<p class="css-wurtue evim1t98">I wondered that too, as we were building it. I hadn't seen examples of reflective IR LEDs being used for measuring distance before. And even though it showed promising results when I tested it before starting, I couldn't be sure how accurate it was, given that the data was definitely not a linear function of distance.</p> 130<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 131<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 132<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/spin-to-win/images/papercone.png" class="css-1k43lf1 ef55ps60"/> 133</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">A scan of a paper cone</span></div></span></div> 134<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 135<img src="/images/post/spin-to-win/images/paperconewithhand.png" class="css-1k43lf1 ef55ps60"/> 136</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">The same paper cone, but a judge we were demoing to wanted to wave his hand between the cone and the scanner for a bit while it was running.</span></div></span></div> 137<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 138<img src="/images/post/spin-to-win/images/papercylinder.png" class="css-1k43lf1 ef55ps60"/> 139</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">
139A scan of a slightly deformed paper cylinder.</span></div></span></div> 140</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">Some example scans generated when plotting the raw data through Wolfram</span></div></span></div> 141<p class="css-wurtue evim1t98">As it turns out, the scans were <em class="css-5hfsd2 e1mpr5v81">pretty darn accurate</em>. In fact they were so clean, we had a judge doubt that the data was live. He waved his hand in between to see, and you can see the results above (middle picture, compared to the original on left).</p> 142</div><div><h2 id="is-it-really-under-20" class="css-1oc01jt evim1t94">Is it really under $20?</h2> 143<p class="css-wurtue evim1t98">Yup. I source most of my electronics from Aliexpress, so that helps. Here's the breakdown:</p> 144<ul> 145<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Reflective IR LED - 10 cents</li> 146<li class="css-1650jxb e1mpr5v80">DC motor - $3</li> 147<li class="css-1650jxb e1mpr5v80">Breadboard - $3</li> 148<li class="css-1650jxb e1mpr5v80">Continuous rotation servo - $7</li> 149<li class="css-1650jxb e1mpr5v80">Arduino clone - $3 to $10</li> 150<li class="css-1650jxb e1mpr5v80">USB A Male <-> USB B Male adapter - Free (usually included with the Arduino, even cheap ones)</li> 151<li class="css-1650jxb e1mpr5v80">Plastic gears - $3 for a bag, probably $0.20 for parts used</li> 152<li class="css-1650jxb e1mpr5v80">Cardboard - Free</li> 153<li class="css-1650jxb e1mpr5v80">Electrical tape, wires, resistors - around $2 worth of parts</li> 154</ul> 155<p class="css-wurtue evim1t98">And this isn't even pricing at scale, or with efficient use of parts (e.g. using a PCB instead of breadboard + wires).</p> 156</div><div><h2 id="ideation-process" class="css-1oc01jt evim1t94">Ideation process</h2> 157<p class="css-wurtue evim1t98">Akhilesh and I flew into Philadelphia early, so we went to a Public Library to kill time before the hackathon started. He goes to the bathroom, and comes out wondering how hard it'd be to scan his poop. I look at my kit and see if we have the parts. And here we are.</p> 158</div><div><h2 id="prototype-process" class="css-1oc01jt evim1t94">Prototype process</h2> 159<p class="css-wurtue evim1t98">After some fairly basic tests, I decided that a Reflective IR LED was probably our best bet as a scanner. Our alternative was an ultrasonic rangefinder, and I didn't think it'd have enough granularity at low distances to work as a close-range 3d scanner.</p> 160<p class="css-wurtue evim1t98">Next, we needed to move the object or the scanner such that the entire object could be scanned. We focused on the vertical dimension first. I tried using a pulley-like system with a DC motor, and of course without a smooth pulley it'd occasionally slow or snag, and we couldn't get a consistent speed.</p> 161<p class="css-wurtue evim1t98">Looking for an alternative, I looked in my tackle box of hardware and found a rack to use in a rack and pinion gearing, and that actually worked perfectly, once we secured it into place. I attached the RIR LED, and also put a cylinder of electrical tape on it to try and make it pick up less noise, which actually worked pretty well.</p> 162<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 163<iframe title="YouTube video player" height="300" src="https://www.youtube.com/embed/fmdrBJvw8gc?rel=0&showinfo=0" frameBorder="0" allowfullscreen=""></iframe> 164</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">Testing out the rack-and-pinion gearing for vertical scanner movement</span></div></span></div> 165<p class="css-wurtue evim1t98">Then we tried making a flat base and attaching it to a dc motor. We first tried taping a few pieces of cardboard together and using the hole in a zip tie to attach it to the dc motor and hold it in place. It didn't work; it ended up too wobbly to actually get any decent measurements on, though.</p> 166<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 167<iframe title="YouTube video player" height="300" src="https://www.youtube.com/embed/kzbxL6kLE_0?rel=0&showinfo=0" frameBorder="0" allowfullscreen=""></iframe> 168</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">Rotating the base was the easiest way to get an even scan, but attaching the base wasn't easy.</span></div></span></div> 169<p class="css-wurtue evim1t98">We were lucky, though: the dc motor I used had basically the exact same diameter as one of the gears in the gear set, so we were able to tape
169cardboard circles to the gear in order to provide a larger base, and this gave us less wobble than our earlier design.</p> 170<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 171<iframe title="YouTube video player" height="300" src="https://www.youtube.com/embed/jmB9qMBHB-o?rel=0&showinfo=0" frameBorder="0" allowfullscreen=""></iframe> 172</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">Fairly stable and ready to scan!</span></div></span></div> 173<p class="css-wurtue evim1t98">Once we got this working, we also needed to hold the rack and pinion together using a bunch of zip ties, cardboard, and duct tape. The motor also broke apart a couple times, requiring the metal inside to be repositioned. And of course, we needed to calibrate everything, to get near-usable results!</p> 174</div><div><h2 id="calibration-process" class="css-1oc01jt evim1t94">Calibration process</h2> 175<p class="css-wurtue evim1t98">In this process, we figured out a function to convert the Reflective IR LED's raw analog output to units of distance. We also figured out the function to get vertical distance (vertical scanner movement) and degrees of rotation (horizontal base rotation) as a function of time.</p> 176<p class="css-wurtue evim1t98">Figuring out position of the z-axis was simple, we just measured the distance/time to get the speed of the motor when moving vertically, which given the initial value of 0 (measuring starting at the object's base), gives the z position as a function of time.</p> 177<p class="css-wurtue evim1t98">To find the angle of rotation, I measured the length of time it took for 10 rotations (to reduce error from starting/stopping time) and divided by 10.</p> 178<p class="css-wurtue evim1t98">To find the distance from the object to the scanner, we needed to fit the data given by the reflective IR LEDs. And for that we needed
178some data points to get a curve best fit. Using Chrome dev tools as a substitute for a ruler, I recorded the scanner's analog output values, while moving a piece of cardboard away, centimeter by centimeter.</p> 179<p class="css-wurtue evim1t98">With this data, we were able to estimate the function best fit using Wolfram alpha:</p> 180<p class="css-wurtue evim1t98">$$$ f(x) = -600 + \frac{19169 \times x}{30} + \frac{30433 x^2}{360} - \frac{1751 x^3}{16} + \frac{4009 x^4}{144} - \frac{727 x^5}{240} + \frac{89 x^6}{720} $$$</p> 181<p class="css-wurtue evim1t98">Glad we didn't have to calculate that by hand. Unfortunately Wolfram didn't give us the inverse, which we needed (in a scan, we have raw analog values and want estimated distance). So I just plugged in the range of input values, which is a limited range of ints (0-2048), and made a lookup table instead.</p> 182<p class="css-wurtue evim1t98">Combining these functions, we were able to determine y/z coordinates given distance and time. (Remember, our scanner rotates and moves up at the same time, so it's moving in a spiral shape.)</p> 183<p class="css-wurtue evim1t98">And with this, we could generate point clouds (seen above in earlier sections)! From this, you can estimate the shape of the object, and generate a STL file to send to your 3d printer, in order to print the object you just scanned!</p> 184</div><div><h2 id="want-to-build-it-yourself" class="css-1oc01jt evim1t94">Want to build it yourself?</h2> 185</div><div><h2 id="caveats" class="css-1oc01jt evim1t94">Caveats</h2> 186<p class="css-wurtue evim1t98">Want to build this on your own? It's very cool, and very cheap! But if you're planning on using it for anything serious, note a couple caveats:</p> 187<p class="css-wurtue evim1t98">You'll probably need 3d-printed parts for it to be calibrated well. (Though it's fun project to make by hand though, and the experience and results were pretty rewarding.) It's also not that great at scanning anything too glossy (shiny plastic/metal).</p> 188</div><div><h2 id="details-you-might-find-useful" class="css-1oc01jt evim1t94">Details you might find useful</h2> 189<p class="css-wurtue evim1t98">All data is passed via USB from the Arduino to the laptop, where all of the processing is done in Node. It's much faster that way, and you can do whatever you want with it from there.</p> 190<p class="css-wurtue evim1t98">Data is sent from the Node instance to the Wolfram notebook through.... the wondrous OS X clipboard (last minute features, what can I say). It takes a long time for Wolfram Notebook to graph the data, but I think it's just slow frontend javascript, not optimized for large datasets. It might be faster on other software.</p> 191<p class="css-wurtue evim1t98">I don't have any good pictures of the circuit, but the only complicated part is wiring the Reflective IR LEDs, which you can do like this:</p> 192<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"> 193<img src="/images/post/spin-to-win/images/tcrt.jpg" alt="Example TCRT5000 breadboard layout" class="css-1k43lf1 ef55ps60"/> 194</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">The circuit we used was something like this one</span></div></span></div> 195<p class="css-wurtue evim1t98">Thankfully no signal amplifiers are needed (I didn't have any), and the wiring for the servos and dc motor are also pretty standard. Have fun!</p></div></div><style data-emotion="css f70kdd">.css-f70kdd{background-color:rgb(255, 247, 232);border:2px solid #111111;border-radius:4px;margin-top:24px;padding:12px;padding-top:20px;padding-bottom:20px;margin-bottom:1rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.css-f70kdd #spacing{width:100%;height:10px;}.css-f70kdd input{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;line-height:1.25rem;border-radius:0.25rem;width:100%;display:block;border:1px solid gray;padding:1rem;}.css-f70kdd input[type='submit']{color:#FDFDFD;background-color:#751506;}.css-f70kdd form{width:100%;max-width:400px;text-align:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;
195-webkit-justify-content:center;justify-content:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}</style><div class="css-f70kdd e1ggha271"><form action="https://buttondown.email/api/emails/embed-subscribe/croshan" method="post" target="popupwindow" class="embeddable-buttondown-form"><span class="css-wurtue evim1t97">Want an email when new posts come out?<br/>(Roughly twice a year)</span><div id="spacing"></div><input type="hidden" name="tag" value="end"/><style data-emotion="css s38o0y">.css-s38o0y{font-size:10px;width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:8px;}@media (min-width:600px){.css-s38o0y{-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:0px;}.css-s38o0y #email{-webkit-flex:1;-ms-flex:1;flex:1;border-top-right-radius:0;border-bottom-right-radius:0;border-right:0px;}.css-s38o0y #submit{-webkit-flex:0.5;-ms-flex:0.5;flex:0.5;border-top-left-radius:0;border-bottom-left-radius:0;border-left:0px;}}</style><div class="css-s38o0y e1ggha270"><input placeholder="Type your email..." type="email" name="email" id="email"/><input id="submit" type="submit" value="Subscribe"/></div></form></div></div></div></div></div></div></div>
195<script id="__NEXT_DATA__" type="application/json" crossorigin="">{"props":{"pageProps":{"post":{"rawText":"---\ntitle: 'Making a 3d scanner for under $20'\ndate: 2016-04-05T12:16:16+02:00\ndescription: 'My hackathon project, a 3d scanner made out of cardboard'\ntags: ['technical', 'hardware', 'hackathon', 'walkthrough']\nlatex: true\ntoc: true\ndraft: false\nfavorite: true\naliases:\n - /2016/04/05/Spin-to-Win-a-3d-scanner-for-under-20.html # hn submission\n---\n\nAt this Spring's HackPrinceton, my friend \u003ca href=\"http://yarabarla.com/\"\u003eAK\u003c/a\u003e and I built a fast and efficient 3d scanner out of spare parts. I think it's very cool.\n\n\u003ccentered-content caption=\"The final product. The slower the motors run, the more accurate the scan.\"\u003e\n\n\u003ciframe title=\"YouTube video player\" width=\"480\" height=\"300\" src=\"https://www.youtube.com/embed/6dSABwcAYv8?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nBoth the \u003ca href=\"http://www.devpost.com/software/spin-to-win\"\u003eproject submission\u003c/a\u003e and the \u003ca href=\"https://github.com/CyrusRoshan/Spin-to-Win\"\u003esource code\u003c/a\u003e are online.\n\n# How does it work?\n\nFor measurement, we used a reflective IR LED. More detail on this later, but basically I'm using it here as a close-range distance measurement tool.\n\n\u003c!-- add picture of reflective IR LED --\u003e\n\nIn order to measure a 3d surface, two other components come into play, each adding a separate dimension to the scan. The first is a vertical shaft which raises and lowers the reflective IR LED. The second is a DC motor, which rotates the scanned object, allowing the scanner to measure its sides.\n\n\u003c!-- add labeled image --\u003e\n\n# Scan accuracy\n\nYou're probably wondering how accurate this project's scans actually were. It's literally a _ten-cent RIR LED on a stick_, held together by cardboard.\n\nI wondered that too, as we were building it. I hadn't seen examples of reflective IR LEDs being used for measuring distance before. And even though it showed promising results when I tested it before starting, I couldn't be sure how accurate it was, given that the data was definitely not a linear function of distance.\n\n\u003ccentered-content size=\"size3 mobileSize1\" caption=\"Some example scans generated
195when plotting the raw data through Wolfram\"\u003e\n\u003ccentered-content caption=\"A scan of a paper cone\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/papercone.png\"\u003e\n\u003c/centered-content\u003e\n\u003ccentered-content caption=\"The same paper cone, but a judge we were demoing to wanted to wave his hand between the cone and the scanner for a bit while it was running.\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/paperconewithhand.png\"\u003e\n\u003c/centered-content\u003e\n\u003ccentered-content caption=\"A scan of a slightly deformed paper cylinder.\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/papercylinder.png\"\u003e\n\u003c/centered-content\u003e\n\u003c/centered-content\u003e\n\nAs it turns out, the scans were _pretty darn accurate_. In fact they were so clean, we had a judge doubt that the data was live. He waved his hand in between to see, and you can see the results above (middle picture, compared to the original on left).\n\n# Is it really under $20?\n\nYup. I source most of my electronics from Aliexpress, so that helps. Here's the breakdown:\n\n- Reflective IR LED - 10 cents\n- DC motor - $3\n- Breadboard - $3\n- Continuous rotation servo - $7\n- Arduino clone - $3 to $10\n- USB A Male \u003c-\u003e USB B Male adapter - Free (usually included with the Arduino, even cheap ones)\n- Plastic gears - $3 for a bag, probably $0.20 for parts used\n- Cardboard - Free\n- Electrical tape, wires, resistors - around $2 worth of parts\n\nAnd this isn't even pricing at scale, or with efficient use of parts (e.g. using a PCB instead of breadboard + wires).\n\n# Ideation process\n\nAkhilesh and I flew into Philadelphia early, so we went to a Public Library to kill time before the hackathon started. He goes to the bathroom, and comes out wondering how hard it'd be to scan his poop. I look at my kit and see if we have the parts. And here we are.\n\n# Prototype process\n\nAfter some fairly basic tests, I decided that a Reflective IR LED was probably our best bet as a scanner. Our alternative was an ultrasonic rangefinder, and I didn't think it'd have enough granularity at low distances to work as a close-range 3d scanner.\n\nNext, we needed to move the object or the scanner such that the entire object could be scanned. We focused on the vertical dimension first. I tried using a pulley-like system with a DC motor, and of course without a smooth pulley it'd occasionally slow or snag, and we couldn't get a consistent speed.\n\nLooking for an alternative, I looked in my tackle box of hardware and found a rack to use in a rack and pinion gearing, and that actually worked perfectly, once we secured it into place. I attached the RIR LED, and also put a cylinder of electrical tape on it to try and make it pick up less noise, which actually worked pretty well.\n\n\u003ccentered-content caption=\"Testing out the rack-and-pinion gearing for vertical scanner movement\"\u003e\n\n\u003ciframe title=\"YouTube video player\" height=\"300\" src=\"https://www.youtube.com/embed/fmdrBJvw8gc?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nThen we tried making a flat base and attaching it to a dc motor. We first tried taping a few pieces of cardboard together and using the hole in a zip tie to attach it to the dc motor and hold it in place. It didn't work; it ended up too wobbly to actually get any decent measurements on, though.\n\n\u003ccentered-content caption=\"Rotating the base was the easiest way to get an even scan, but attaching the base wasn't easy.\"\u003e\n\n\u003ciframe title=\"YouTube video player\" height=\"300\" src=\"https://www.youtube.com/embed/kzbxL6kLE_0?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nWe were lucky, though: the dc motor I used had basically the exact same diameter as one of the gears in the gear set, so we were able to tape cardboard circles to the gear in order to provide a larger base, and this gave us less wobble than our earlier design.\n\n\u003ccentered-content caption=\"Fairly stable and ready to scan!\"\u003e\n\n\u003ciframe title=\"YouTube video player\" height=\"300\" src=\"https://www.youtube.com/embed/jmB9qMBHB-o?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nOnce we got this working, we also needed to hold the rack and pinion together using a bunch of zip ties, cardboard, and duct tape. The motor also broke apart a couple times, requiring the metal inside to be repositioned. And of course, we needed to calibrate everything, to get near-usable results!\n\n# Calibration process\n\nIn this process, we figured out a function to convert the Reflective IR LED's raw analog output to units of distance. We also figured out the function to get vertical distance (vertical scanner movement) and degrees of rotation (horizontal base rotation) as a function of time.\n\nFiguring out position of the z-axis was simple, we just measured the distance/time to get the speed of the motor when moving vertically, which given the initial value of 0 (measuring starting at the object's base), gives the z position as a function of time.\n\nTo find the angle of rotation, I measured the length of time it took for 10 rotations (to reduce error from starting/stopping time) and divi
195ded by 10.\n\nTo find the distance from the object to the scanner, we needed to fit the data given by the reflective IR LEDs. And for that we needed some data points to get a curve best fit. Using Chrome dev tools as a substitute for a ruler, I recorded the scanner's analog output values, while moving a piece of cardboard away, centimeter by centimeter.\n\nWith this data, we were able to estimate the function best fit using Wolfram alpha:\n\n$$$ f(x) = -600 + \\frac{19169 \\times x}{30} + \\frac{30433 x^2}{360} - \\frac{1751 x^3}{16} + \\frac{4009 x^4}{144} - \\frac{727 x^5}{240} + \\frac{89 x^6}{720} $$$\n\nGlad we didn't have to calculate that by hand. Unfortunately Wolfram didn't give us the inverse, which we needed (in a scan, we have raw analog values and want estimated distance). So I just plugged in the range of input values, which is a limited range of ints (0-2048), and made a lookup table instead.\n\nCombining these functions, we were able to determine y/z coordinates given distance and time. (Remember, our scanner rotates and moves up at the same time, so it's moving in a spiral shape.)\n\nAnd with this, we could generate point clouds (seen above in earlier sections)! From this, you can estimate the shape of the object, and generate a STL file to send to your 3d printer, in order to print the object you just scanned!\n\n# Want to build it yourself?\n\n# Caveats\n\nWant to build this on your own? It's very cool, and very cheap! But if you're planning on using it for anything serious, note a couple caveats:\n\nYou'll probably need 3d-printed parts for it to be calibrated well. (Though it's fun project to make by hand though, and the experience and results were pretty rewarding.) It's also not that great at scanning anything too glossy (shiny plastic/metal).\n\n# Details you might find useful\n\nAll data is passed via USB from the Arduino to the laptop, where all of the processing is done in Node. It's much faster that way, and you can do whatever you want with it from there.\n\nData is sent from the Node instance to the Wolfram notebook through.... the wondrous OS X clipboard (last minute features, what can I say). It takes a long time for Wolfram Notebook to graph the data, but I think it's just slow frontend javascript, not optimized for large datasets. It might be faster on other software.\n\nI don't have any good pictures of the circuit, but the only complicated part is wiring the Reflective IR LEDs, which you can do like this:\n\n\u003ccentered-content caption=\"The circuit we used was something like this one\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/tcrt.jpg\" alt=\"Example TCRT5000 breadboard layout\"/\u003e\n\u003c/centered-content\u003e\n\nThankfully no signal amplifiers are needed (I didn't have any), and the wiring for the servos and dc motor are also pretty standard. Have fun!\n","postId":"spin-to-win","markdown":{"content":"\nAt this Spring's HackPrinceton, my friend \u003ca href=\"http://yarabarla.com/\"\u003eAK\u003c/a\u003e and I built a fast and efficient 3d scanner out of spare parts. I think it's very cool.\n\n\u003ccentered-content caption=\"The final product. The slower the motors run, the more accurate the scan.\"\u003e\n\n\u003ciframe title=\"YouTube video player\" width=\"480\" height=\"300\" src=\"https://www.youtube.com/embed/6dSABwcAYv8?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nBoth the \u003ca href=\"http://www.devpost.com/software/spin-to-win\"\u003eproject submission\u003c/a\u003e and the \u003ca href=\"https://github.com/CyrusRoshan/Spin-to-Win\"\u003esource code\u003c/a\u003e are online.\n\n# How does it work?\n\nFor measurement, we used a reflective IR LED. More detail on this later, but basically I'm using it here as a close-range distance measurement tool.\n\n\u003c!-- add picture of reflective IR LED --\u003e\n\nIn order to measure a 3d surface, two other components come into play, each adding a separate dimension to the scan. The first is a vertical shaft which raises and lowers the reflective IR LED. The second is a DC motor, which rotates the scanned object, allowing the scanner to measure its sides.\n\n\u003c!-- add labeled image --\u003e\n\n# Scan accuracy\n\nYou're probably wondering how accurate this project's scans actually were. It's literally a _ten-cent RIR LED on a stick_, held together by cardboard.\n\nI wondered that too, as we were building it. I hadn't seen examples of reflective IR LEDs being used for measuring distance before. And even though it showed promising results when I tested it before starting, I couldn't be sure how accurate it was, given that the data was definitely not a linear function of distance.\n\n\u003ccentered-content size=\"size3 mobileSize1\" caption=\"Some example scans generated
195when plotting the raw data through Wolfram\"\u003e\n\u003ccentered-content caption=\"A scan of a paper cone\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/papercone.png\"\u003e\n\u003c/centered-content\u003e\n\u003ccentered-content caption=\"The same paper cone, but a judge we were demoing to wanted to wave his hand between the cone and the scanner for a bit while it was running.\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/paperconewithhand.png\"\u003e\n\u003c/centered-content\u003e\n\u003ccentered-content caption=\"A scan of a slightly deformed paper cylinder.\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/papercylinder.png\"\u003e\n\u003c/centered-content\u003e\n\u003c/centered-content\u003e\n\nAs it turns out, the scans were _pretty darn accurate_. In fact they were so clean, we had a judge doubt that the data was live. He waved his hand in between to see, and you can see the results above (middle picture, compared to the original on left).\n\n# Is it really under $20?\n\nYup. I source most of my electronics from Aliexpress, so that helps. Here's the breakdown:\n\n- Reflective IR LED - 10 cents\n- DC motor - $3\n- Breadboard - $3\n- Continuous rotation servo - $7\n- Arduino clone - $3 to $10\n- USB A Male \u003c-\u003e USB B Male adapter - Free (usually included with the Arduino, even cheap ones)\n- Plastic gears - $3 for a bag, probably $0.20 for parts used\n- Cardboard - Free\n- Electrical tape, wires, resistors - around $2 worth of parts\n\nAnd this isn't even pricing at scale, or with efficient use of parts (e.g. using a PCB instead of breadboard + wires).\n\n# Ideation process\n\nAkhilesh and I flew into Philadelphia early, so we went to a Public Library to kill time before the hackathon started. He goes to the bathroom, and comes out wondering how hard it'd be to scan his poop. I look at my kit and see if we have the parts. And here we are.\n\n# Prototype process\n\nAfter some fairly basic tests, I decided that a Reflective IR LED was probably our best bet as a scanner. Our alternative was an ultrasonic rangefinder, and I didn't think it'd have enough granularity at low distances to work as a close-range 3d scanner.\n\nNext, we needed to move the object or the scanner such that the entire object could be scanned. We focused on the vertical dimension first. I tried using a pulley-like system with a DC motor, and of course without a smooth pulley it'd occasionally slow or snag, and we couldn't get a consistent speed.\n\nLooking for an alternative, I looked in my tackle box of hardware and found a rack to use in a rack and pinion gearing, and that actually worked perfectly, once we secured it into place. I attached the RIR LED, and also put a cylinder of electrical tape on it to try and make it pick up less noise, which actually worked pretty well.\n\n\u003ccentered-content caption=\"Testing out the rack-and-pinion gearing for vertical scanner movement\"\u003e\n\n\u003ciframe title=\"YouTube video player\" height=\"300\" src=\"https://www.youtube.com/embed/fmdrBJvw8gc?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nThen we tried making a flat base and attaching it to a dc motor. We first tried taping a few pieces of cardboard together and using the hole in a zip tie to attach it to the dc motor and hold it in place. It didn't work; it ended up too wobbly to actually get any decent measurements on, though.\n\n\u003ccentered-content caption=\"Rotating the base was the easiest way to get an even scan, but attaching the base wasn't easy.\"\u003e\n\n\u003ciframe title=\"YouTube video player\" height=\"300\" src=\"https://www.youtube.com/embed/kzbxL6kLE_0?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nWe were lucky, though: the dc motor I used had basically the exact same diameter as one of the gears in the gear set, so we were able to tape cardboard circles to the gear in order to provide a larger base, and this gave us less wobble than our earlier design.\n\n\u003ccentered-content caption=\"Fairly stable and ready to scan!\"\u003e\n\n\u003ciframe title=\"YouTube video player\" height=\"300\" src=\"https://www.youtube.com/embed/jmB9qMBHB-o?rel=0\u0026amp;showinfo=0\" frameborder=\"0\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/centered-content\u003e\n\nOnce we got this working, we also needed to hold the rack and pinion together using a bunch of zip ties, cardboard, and duct tape. The motor also broke apart a couple times, requiring the metal inside to be repositioned. And of course, we needed to calibrate everything, to get near-usable results!\n\n# Calibration process\n\nIn this process, we figured out a function to convert the Reflective IR LED's raw analog output to units of distance. We also figured out the function to get vertical distance (vertical scanner movement) and degrees of rotation (horizontal base rotation) as a function of time.\n\nFiguring out position of the z-axis was simple, we just measured the distance/time to get the speed of the motor when moving vertically, which given the initial value of 0 (measuring starting at the object's base), gives the z position as a function of time.\n\nTo find the angle of rotation, I measured the length of time it took for 10 rotations (to reduce error from starting/stopping time) and divi
195ded by 10.\n\nTo find the distance from the object to the scanner, we needed to fit the data given by the reflective IR LEDs. And for that we needed some data points to get a curve best fit. Using Chrome dev tools as a substitute for a ruler, I recorded the scanner's analog output values, while moving a piece of cardboard away, centimeter by centimeter.\n\nWith this data, we were able to estimate the function best fit using Wolfram alpha:\n\n$$$ f(x) = -600 + \\frac{19169 \\times x}{30} + \\frac{30433 x^2}{360} - \\frac{1751 x^3}{16} + \\frac{4009 x^4}{144} - \\frac{727 x^5}{240} + \\frac{89 x^6}{720} $$$\n\nGlad we didn't have to calculate that by hand. Unfortunately Wolfram didn't give us the inverse, which we needed (in a scan, we have raw analog values and want estimated distance). So I just plugged in the range of input values, which is a limited range of ints (0-2048), and made a lookup table instead.\n\nCombining these functions, we were able to determine y/z coordinates given distance and time. (Remember, our scanner rotates and moves up at the same time, so it's moving in a spiral shape.)\n\nAnd with this, we could generate point clouds (seen above in earlier sections)! From this, you can estimate the shape of the object, and generate a STL file to send to your 3d printer, in order to print the object you just scanned!\n\n# Want to build it yourself?\n\n# Caveats\n\nWant to build this on your own? It's very cool, and very cheap! But if you're planning on using it for anything serious, note a couple caveats:\n\nYou'll probably need 3d-printed parts for it to be calibrated well. (Though it's fun project to make by hand though, and the experience and results were pretty rewarding.) It's also not that great at scanning anything too glossy (shiny plastic/metal).\n\n# Details you might find useful\n\nAll data is passed via USB from the Arduino to the laptop, where all of the processing is done in Node. It's much faster that way, and you can do whatever you want with it from there.\n\nData is sent from the Node instance to the Wolfram notebook through.... the wondrous OS X clipboard (last minute features, what can I say). It takes a long time for Wolfram Notebook to graph the data, but I think it's just slow frontend javascript, not optimized for large datasets. It might be faster on other software.\n\nI don't have any good pictures of the circuit, but the only complicated part is wiring the Reflective IR LEDs, which you can do like this:\n\n\u003ccentered-content caption=\"The circuit we used was something like this one\"\u003e\n\u003cimg src=\"/images/post/spin-to-win/images/tcrt.jpg\" alt=\"Example TCRT5000 breadboard layout\"/\u003e\n\u003c/centered-content\u003e\n\nThankfully no signal amplifiers are needed (I didn't have any), and the wiring for the servos and dc motor are also pretty standard. Have fun!\n","data":{"title":"Making a 3d scanner for under $20","date":"2016-04-05T12:16:16+02:00","description":"My hackathon project, a 3d scanner made out of cardboard","tags":["technical","hardware","hackathon","walkthrough"],"latex":true,"toc":true,"draft":false,"favorite":true,"aliases":["/2016/04/05/Spin-to-Win-a-3d-scanner-for-under-20.html"]},"mermaidImages":{}},"type":"post","date":"2016-04-05T12:16:16+02:00","url":"/post/spin-to-win","hasLatex":true,"postIndex":3},"totalPosts":22},"__N_SSG":true},"page":"/post/[id]","query":{"id":"spin-to-win"},"buildId":"b2v3BGFw9dHacc7buszmk","runtimeConfig":{"SITE_URL":"https://blog.cyrusroshan.com"},"isFallback":false,"gsp":true,"scriptLoader":[]}</script>
195<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"fcfeb33890e04e2790b899381c747c48","spa":2}' crossorigin="anonymous"></script>
195 196</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.