If you already have a camera then this project will cost less than $50 to complete. If you like to shop on AliExpress you can probably build it for around $30. If you like to support your local middleman, more power too you, but it will cost a little more. The giant screw shown above was made from a regular drywall screw captured using this scanner and a Nikon DSLR.

Desktop 3d scanning has made great leaps in recent years but it still has great limitations. Scanner hardware is built around a specific scan volume and resolution. You can get decent results, but only if your object fits that sweet spot. If your object is too small, or too detailed or your scanner is just having a bad day your scan will look like a potato. Luckily there is another approach. Photogrammetry uses a set of regular 2d photographs taken from all angles around an object. If a point on an object can be seen in at least three pictures then its location can be triangulated and measured in three dimensions. By identifying and calculating the location of thousands, or even millions of points the software can build up an extremely accurate reproduction. Unlike a hardware based scanner there are no size or resolution limitations to this process. If you can photograph an object you can 3d scan it. It works from molecules to galaxies, or it would if they would ever approve my Hubble time.

The limiting factor with photogrammetry is the quality of the photographs and thus the skill of the photographer. Photos must be well exposed and in razor sharp focus. They must also be spaced around the object so they capture every part to be scanned and they overlap enough that the software can figure out where each shot belongs. With large objects this can be done manually with some practice, but it is virtually impossible to do it well with a small object. This scanner automates the process.

Step 1: How It Works

A high quality photogrammetry scan requires high quality photos of the subject from all angles. The easiest approach for scanning small things is to rotate the subject while photographing it. This scanner uses a stepper motor controlled by an arduino board. The stepper turns the object by a fixed amount and then an infra red LED fires off fiendishly clever series of blinks which mimics the camera's wireless remote. The camera being rather gullible and wishing to please takes the picture.

An lcd display shield with a set of buttons allows the user to control the arduino. Using the buttons the user can select the number of pictures to be taken per revolution. The scanner can run in automatic mode where it takes a picture, advances the stepper and repeats until it has completed a whole revolution. There is also a manual mode where each push of the button takes a picture, advances the stepper and waits. This is useful for scans where each picture needs to be framed and focused manually.

<p>I uploaded version 1.1 on the same download page as before. It has DFR_Key included in the download package. It compiles and installs on my system using Arduino 1.6.7 (of course the old version did too). Hopefully this will fix the issue some of you have been having</p>
<p>thanks i'll try that and let you know how i get on --- I also looked at the arduino forums and it seem there has been a change in layout of the Dir structure, the libraries now go in two places one for included libraries and one for user libraries this may also be part of the problem I'll post my results when i get to them later to-day </p><p>thanks again for the great support</p><p>Brian</p>
<p>hey shapespeare, I am very new to all this. It is my first time using an arduino. I have assembled everything ok and can run the stepper motor with the controls you set up. However, I have not been able to get the ir led to get my camera to fire. I have a nikon d3400 and have set up everything accordong to your fritzing skematic(im pretty sure) but couldn't even get it to light up a normal led. Could you offer any advice? Thanks</p>
<p>Check the polarity of the LED. The shorter wire goes to ground. If they are reversed it won't work. Also make sure the led is hooked up to the same pin you initialize in the code (pin 53 by default). If that fails try hooking it up to a different pin and change the code to match. </p>
<p>Hi, congratulations for this project. I think that can be very useful to get an automated photo tasking in photgrametry purposes. Since I discovered photogrammetry I've been trying to get this.</p><p>I would like to know how should I modify the firmware so i could use it in a arduino uno. </p><p>I didn't find where is the line where the IR LED is connected to modify this.</p><p>I'm new in arduino stuff...and i feel a bit lost.</p><p>In arduino mega IR LED it's connected in 53 pin.</p><p>I Would be very grateful if someone who did this project in arduino uno could help me. </p><p>Thanks a lot.</p>
Hi, change the output pin in line 47:<br>Nikon Camera(53); //change Nikon to any other supported brand<br>
<p>Thanks PabloG134, it works on Arduino MEGA, but I couldn't get the same result doing it on Arduino UNO. If I change the line 47 for example: </p><p>Nikon Camera(13); //change Nikon to any other supported brand</p><p>The Led turns on just plugging it... </p><p>Thanks all the ways.</p>
<p>Super cool !! I wrote a new code becaused i used the AH_Polulu library and a A4988 stepper-driver. And write a reset for the stepcounter. Its a really really nice 3d-scan love it !!! If someone need the code please write me</p><p>(sorry for the bad english ......im from germany</p>
<p>hi, can you send me the code? thanks</p>
<p>Hi everybody, very impressive project can anyone send me the code with the pololu DRV8825 motor driver ? Thanks in advance </p>
<p>Genius !</p>
<p>For those of you who experience the problem when the stepper is moving too early (post-shutter wait not working): The problem is probably caused by not updating the &quot;currentTime&quot; variable before the next &quot;if&quot;statement.</p><p>Solution:</p><p>Just <em>move</em> the &quot;if (waitFlag == 2)&quot;-block under the &quot;currentTime = millis())-line, like seen below. Leave the rest untouched. <br></p><p>-------------------------------------------------------<br>currentTime = millis();<br><br> if (waitFlag == 2) // wait after triggering shutter before moving motor<br> {<br> if (currentTime - startWait &gt;= postWait) //wait time has expired<br> {<br> waitFlag = 0; //done waiting<br> }<br> }</p><p>if (waitFlag == 0) // advance stepper and start wait timer<br> {</p><p>And so on....</p><p>---------------------------------------------------------</p><p>I'm still waiting for some parts, but now it seems to work just fine!</p><p>THX to shapespeare!!!</p>
<p>THX to shapespeare and a little help from my friends!</p>
<p>Hello, </p><p>I uploaded firmware 1.1, everything seems to work fine. There is only one problem I cannot fix: the delay BEFORE triggering the shutter can be varied, butt here is no reaction in setting the delay time AFTER the trigger starts. The trigger starts at the moment, the next step starts, so the images are blurred. Same hardware and setup of the connections as in the original workshop here.</p><p>Any helo?</p>
<p>I have a KRUG SMASH fix for now if you need it. Add delay(2000); to the wait if (waitFlag == 1) section so it looks like this:</p><p>if (waitFlag == 1) // when preshutter wait expires trigger shutter<br> {<br><br> if (currentTime - startWait &gt;= preWait) //wait time has expired<br> {<br><br> Camera.shutterNow(); // trigger shutter<br> startWait = millis(); // restart wait timer<br> delay(2000);<br> waitFlag = 2; // initiate post shutter wait<br> stepCount ++; <br> }</p>
<p>Thanks ReaganPufall, this has fixed the problem. Great Support!</p><p>(Besides, I appreciate your website!)</p>
<p>Thanks for the fix. I hope this works for people.</p>
<p>Thanks a lot! Works perfectly fine!</p>
<p>Nice idea, but I see the stepper only rotates 360&deg; in only one plane. Wouldn't it be better to add a second stepper to rotate around a horizontal axis as well? If so, could the scanner software handle it? </p>
<p>The photogrammetry software will handle any set of photos you hand it. You could easily enough add another axis to the scanner hardware although it doesn't really need it. It is easy enough to reposition the camera manually between passes. If you decide to try please let us know how it works.</p>
<p>I used parts-on-hand: an Offanengo HY200 2220 0300 AS04 motor (200 steps &amp; 1.8 degrees), Arduino, Grove Shield, SeeedStudio OLED display, Adafruit Motor Shield (V1), and Nikon D70 camera.<br><br>Since I opted to go this route, I also did not have the buttons that come with the recommended LCD shield, so I just modified the code to read input from the serial monitor window. Just punch in the number corresponding to the buttons: 1 starts an automatic cycle, -1 stops it.<br><br>Works great.<br><br>Also - I think my old D70 is a little slow, and there was nothing I could do with the Pre and Post waits to get it to stop exposing the image at the same moment the motor moved, so I added a 1s delay following the shutter release command, and that worked fine. I understand the implication, but a 1s delay in reading the input is livable.<br></p>
<p>Thanks so much for this very clear explanation. I had one problem though which I have solved and I thought I might as well share my solution.</p><p>When I first hooked everything up, the buttons weren't responding, and changing the threshold as suggested in another comment on this page didn't do the trick, as it made the left key pretend to be the down key. I solved it by temporarily adding a few lines to DFR_key.cpp:</p><p>after line 2, I added:</p><blockquote>#include &lt;LiquidCrystal.h&gt;</blockquote><blockquote>LiquidCrystal lcdd(8, 9, 4, 5, 6, 7);</blockquote><p>and after l added after line 43 (_change = true;):</p><blockquote> lcdd.clear();</blockquote><blockquote> lcdd.print(_curInput);</blockquote><blockquote> delay(2500);</blockquote><p>Then I uploaded this to the arduino, and read the numbers that now appeared on the lcd when pressing the buttons. Then I changed numbers in the lines:</p><blockquote>static int RIGHTKEY_ARV = 0;</blockquote><p>to the respective numbers that had appeared on the lcd.</p><p>After removing the lines I initially added, and uploading it to the arduino again, everything worked!</p><p>-Thijmenmees</p>
<p>here is 3d scanner http://www.3dmaxprinter.com/shop/3d-scanner/3d-scanner-diy-kit-for-scanning-3d-printer-objects/</p>
Hello Shakespeare!<br>I'm trying to make the scanner but i have any problems:<br>The first problem is my english is a little poor ?<br><br>I have the mega and the lcd panel but i haven't a easydriver and the nema motor. <br>I'm trying to adapt the firmware to use a 28BYJ-48 unipolar motor and the driver usually you buy with an arduino kit. <br><br>I connect only a green led in the ir led place, i upload the firmware to the mega and i push the select button but nothing happens. <br><br>Is necessary to conect all to brights the led?<br><br>Thank you!
<p>Built the whole thing in an afternoon. Your guide was spot on for wiring and parts. My first time soldering and using an Arduino and it worked perfect on the 1st test. </p>
<p>Parts are trickling in and will be making this in the next week or 2! Can't wait to try it out. </p>
<p>Hi, first of all thanks for the sheer idea of this. i have hooked everything up with an small arduino uno and i just had to adjust the pins.</p><p>I have a question regarding the code.</p><p>You are initializing the steppermotor with 200*64 steps per Rev.</p><p>what is the meaning of the *64?</p><p>I am using a nema17 steppermotor with 50 steps in 1/8 stepping mode and i had to use 200*32... (One revolution works perfectly with this value.)</p><p>I just dont know what the value *64 is doing. Would you please explain to me?</p>
<p>Hello me you could show your connection with Arduino Uno</p>
<p>Hi, thanks for sharing. I'm trying to make this, and did get the hardware set up. Uploaded the FW and started it. But the buttons doesnt do much. Only the &quot;RIGHT&quot; button works and makes the stepper move CW. All the other buttons seems inactive. Any suggestions to what I could've done wrong? I'm using the same hardware as you. Arduino Mega 2560, LCD Keypad shield and a Smartstepper.</p>
<p>Hard to say, but I would guess your buttons are connected to different pins than mine. I would make sure the shield is lined up properly and seated firmly. If the shield was off by a row some of the buttons might still work but the LCD probably wouldn't. If the LCD is working then the shied is probably lined up correctly.</p><p>I think there is a sample sketch out there for the LCD shield which you could use to test the buttons as well.</p>
Thank You for the quick reply. I'm quite sure it's seated properly and is aligned. The 5v, ground and vin pins is matched at least. <br><br>But perhaps my display shield is another iteration with a slightly different pin layout. I'll check. :-)
<p>Hm .. the pins are exactly the same. </p><p>This code works fine: http://www.dfrobot.com/wiki/index.php?title=Ardui...</p><p>So I think it must be the values in &quot;static int RIGHTKEY_ARV = 0;&quot; because they look different. But if it update the values in the DFR.key file nothing works. Do you have any suggestions?</p>
<p>Hooray! I changed the threshold from 5 to 50, and now it reads the buttons fine!</p>
<p>Awesome. You are way deeper in the code than I ever went so I am glad you could figure it out.</p>
<p>I had the same issue (I have the same 1602 LCD from DFRobot), that is the code I used (no need to change threshold) : </p><p>in DFR_key.CPP : </p><p>&quot;if (_curInput &lt; 50) _curKey = RIGHT_KEY;</p><p>else if (_curInput &lt; 195) _curKey = UP_KEY;</p><p>else if (_curInput &lt; 380) _curKey = DOWN_KEY;</p><p>else if (_curInput &lt; 555) _curKey = LEFT_KEY;</p><p>else if (_curInput &lt; 790) _curKey = SELECT_KEY;</p><p>else _curKey = NO_KEY;</p><p>}&quot;</p><p>instead of : </p><p>&quot;if (_curInput &gt; UPKEY_ARV - _threshold &amp;&amp; _curInput &lt; UPKEY_ARV + _threshold ) _curKey = UP_KEY;</p><p> else if (_curInput &gt; DOWNKEY_ARV - _threshold &amp;&amp; _curInput &lt; DOWNKEY_ARV + _threshold ) _curKey = DOWN_KEY;</p><p> else if (_curInput &gt; RIGHTKEY_ARV - _threshold &amp;&amp; _curInput &lt; RIGHTKEY_ARV + _threshold ) _curKey = RIGHT_KEY;</p><p> else if (_curInput &gt; LEFTKEY_ARV - _threshold &amp;&amp; _curInput &lt; LEFTKEY_ARV + _threshold ) _curKey = LEFT_KEY;</p><p> else if (_curInput &gt; SELKEY_ARV - _threshold &amp;&amp; _curInput &lt; SELKEY_ARV + _threshold ) _curKey = SELECT_KEY;</p><p> else _curKey = NO_KEY;</p><p> }&quot;</p>
<p>I have the same issue with only the right button working for CW, What threshold and where did i have to change to get all the other buttons working? Thanks!</p>
<p>It works!</p>
<p>Has anyone tried this with a Raspberry Pi 2? Just curious. I'm trying to put mine together now. Also, is it possible to bypass the Easy Driver altogether? All I have is a stepper hat for the RPI 2, I'm not sure how to hook up a stepper hat and a ribbon cable/cobbler together.</p>
<p>If you have a stepper driver for the rasPi that should work fine. The design is really simple and it should be easy to make your own version with whatever hardware you have.</p>
hello there,...I am having a problem loading the firmware, it shows me a compiling error, any idea? it seams to me I am using the wrong version of arduino software to upload, which version do you recomend? thanks a lot
<p>Nice project shapespeare - thanks for sharing it. I saw in one of your comments that you made this for scanning insects. I'm aiming at digitising insects and very small plants (or parts of them) and would be keen to see how far you got with an insect. Would you be willing to share a scan of one?</p>
<p>Nothing really presentable yet, but I haven't spent much time on it. Depth of field is the big issue. Focus stacking helps but doesn't always play well with the software.</p>
<p>Hello Shapespeare,</p><p>Thank you for the amazing post and ideas shared here. I am looking to build a specific kind of scanner that can scan some images inside the mouth.</p><p>Would you be interested in doing a project ?</p><p>If yes please send me a message.</p><p>Thanks,</p><p>Karrishma</p>
<p>I'm a little overwhelmed by the different types of NEMA 17 stepper motors. Can you give some more insight to the one you are using? Someone says they are using NEMA 17HS3430. I'm just going to get one on ebay and want to know what some good minimum specs are within the NEMA 17 category.</p><p> </p>
I extremely interested in building. I got a canon digital camera, I can get parts for PI stuff over night. What I don't have is software. Can you explain what the software is doing? I kinda confused.
<p>All the firmware does is turn a stepper motor a set distance then fire the shutter and repeat. It automates the process of capturing a set of photos which you then feed to the photogrammetry software of your choice.</p>
What photo app's do you recommend? I am under a super tight budget. We have quite objects we would like to scan and convert to 3-D.<br><br>RC
<p>do I need a 2 way or 4 way macro rail for the camera?</p>
<p>A macro rail isn't necessary, but it helps a lot with framing when you are shooting a very small object. The IR led on the scanner is triggering the camera so it doesn't really matter if the camera set up isn't rock solid as long as the mirror movement doesn't make the camera bounce too much. I use the cheapest 4 way macro rail available and it works fine for this, although a better one would be more enjoyable to use.</p>
<p>If your looking to 3D scan people for 3D portraits here are some tips for the type of 3D scanner you should be looking for to get consistent quality: http://blog.twindom.com/blog/4-ways-to-get-high-quality-3d-portraits-from-your-full-body-3d-scanner</p>

About This Instructable




Bio: I make custom copper signs, metalwork and prototypes. I am one of the hosts of the "3d Printing Today Podcast", available on iTunes.
More by shapespeare:Metric Bread Make 3d Printed Topo Maps of Anywhere Create a Voronoi Version of Anything 
Add instructable to: