
3D Scanner
Introduction[]
It is a simple Arduino-based gadget which automates images taking for photogrammetry (3D scanning from many images). It slowly spins a round platform using a stepper motor, and regularly triggers a camera shutter and optionally an external flash. In particular, it can be used with Canon DSLRs running Magic Lantern firmware in a Full Resolution Silent Picture (electronic shutter) mode - with an external flash.
The gadget uses a small Nokia LCD (~3$ on ebay) and a 4x4 keypad (1$). Internal components include Arduino Nano with a mini USB connector (~4$), DRV8825 Stepper Motor Driver (1.40$), and two optocouplers.
Everything (including all the connectors, LCD, driver, Arduino) is attached directly to the PCB I designed using free program KiCAD, and manufactured at allpcb.com . (I still have 6 extra copies of the PCB - let me know if you need one.)
The schematic:
http://mashchenko.ca/pub/3D_scanner.pdf
Comments: instead of A4988 stepper motor driver, I am now using a drop-in replacement which works much better (more reliable stepping, and twice smaller steps - 32 microsteps vs 16) - DRV8825. Also, it wasn't the best idea to use pin 13 of Arduino Nano to read the keypad - with a cheap membrane keypad it doesn't work (because of the internal LED, and high resistance of the membrane keys). My workaround was to remove the internal LED ("L") with pliers. Another solution would be to use a better keypad (with low resistance). The best solution would be to use another pin, instead of pin 13. Finally, I mistakenly mounted the LCD upside down on the PCB - not really a problem, as the LCD library I am using allows one to flip the image.
The board works well with +12V input power and a typical NEMA17 motor (with <6 Ohm resistance per coil, and 1-1.5A per coil). I am using this motor: https://www.aliexpress.com/item/Free-shipping-1PCS-Nema17-Stepper-Motor-42-motor-Nema-17-motor-42BYGH-1-7A-17HS4401-motor/32667831438.html .
The PCB (Gerbers files):
http://mashchenko.ca/pub/Gerbers2.zip
The software is available on github:
https://github.com/pulsar123/3D_scanner
3D-printable enclosure:
https://www.thingiverse.com/thing:2746830
For this enclosure one has to use 8-pin stackable headers ( https://www.ebay.ca/itm/400985245785 ), to raise the LCD to the front panel.
User interface[]
There is no menu to browse - all the functions are immediately accessible via single key presses. The meaning of the keys is as follows:
- 1/2: Decrease / increase the time between shots dt_shots, s (saved to EEPROM, to the current memory register)
- 3/A: Decrease / increase the number of shots per rotation N_shots (saved to EEPROM, to the current memory register)
- 4/5: Decrease / increase the memory register index (saved to EEPROM)
- 6/B: Decrease / increase the number of additional shots extra_shots (saved to EEPROM, to the current memory register) - I think this parameter is useless, so I plan to remove it
- 7/8: Decrease / increase the level of backlighting (saved to EEPROM)
- 9/C: Decrease / increase flash_delay parameter, ms (only when compiled with DEBUG defined)
- * / D: rewind / fast forward
- 0: Make a test shot (no rotation)
- #: Start / stop the shooting sequence
Three parameters (time between shots, shots per rotation, additional shots) are saved to the current memory register (0...9) every time you change its value. Switching between memory registers via 4/5 keys lets you instantly switch between different saved combinations of these three parameters.
Most of the functions generate a help message at the bottom, which stays there for 2s. Rewind / fast forward are displayed as <-- and -->, respectively, as long as the motor moves. The movements happen at a fixed acceleration/deceleration rate (determined by the parameter T_ACCEL_S in three_d_scanner.h file), up to a maximum rotation speed of SPEED_MAX_RPM (in the same file).
Pressing "#" initiates the shooting sequence. The motor starts moving right away, and the first shot is taken dt_shots seconds later. The last shot is taken at the end, when the motor stops.
Shooting[]
The 3.5mm stereo audio connector mounted on the PCB has the tip connected to the flash control's optocoupler, and the sleeve - to the camera control's optocoupler. You'll need a small adapter to connect this to your camera and (optionally) flash. There could be different scenarios:
Canon DSLRs[]
With Canon DSLRs, the best approach is to install a third party firmware Magic Lantern, and use it's Full Resolution Silent Picture (electronic shutter) mode. (If you don't want to use Magic Lantern and its electronic shutter feature, follow the "Other cameras" section below.) This will save the shutter life of your camera, which can be quite important in photogrammetry (often one needs to take hundreds of photos for a single object's 3D scan). With FRSP the actual camera exposure is ~1/4s, so one needs a fairly dark room plus an external flash (or flashes) to eliminate the motion blur of the rotating object. It helps that one needs fairly large f-number (f/16 - f/22) to get a decent depth of field.
It is very convenient to use RF-controlled Yongnuo flashes (I am using YN-560 III) with one RF controller (YN-603) attached to the 3D scanner. For that one needs the following adapter ("to rail" means "to the 3D scanner"; "to camera" can be a 2.5mm stereo socket, in which case one can use a Yongnuo shutter cable for your specific camera model, e.g. this one):
I used a flash hot shoe from an old Canon film camera to make my adapter.
By default, the 3D scanner is set to operate a Canon DSLR using the FRSP feature. Every time a picture is taken, the following events take place:
- The camera AF pin (corresponds to the shutter button's half-press) is engaged. This initiates the FRSP image taking.
- 1.1s (parameter FLASH_DELAY in three_d_scanner.h) later, the flash is triggered, by briefly (0.1s - DT_FLASH parameter) engaging the flash pin.
- 0.9s later (or 2s since the beginning - parameter DT_AF), the camera AF pin is disengaged. This ends the FRSP image taking.
- At least 6s (dt_shots parameter set from the gadget's keypad) since the beginning, the procedure can be repeated.
These timings work perfectly (each shot is properly exposed by the flash) for two different cameras I tried - 50D and 6D. For this to work, the camera has to be set to Manual mode, exposure time should be at least 1/4s (or perhaps 0.3s -0.5s for other cameras), and Exposure override has to be enabled in the Magic Lantern menu (otherwise the f-number chosen will be ignored, and all shots will be taken with a wide open aperture). One twist: for the very first FRSP shot (triggered when you still see the menu on your camera's display), standard flash delay setting doesn't work, and the shot doesn't get properly exposed. My workaround - at the beginning I half-press the camera's shutter button for >1s (this takes an unexposed shot), and once the camera's screen turnss black I press the start ("#") button on the scanner's controller. This ensures that all the images you requested will be properly exposed. When processing the images, I simply delete the very first (unexposed) shot.
For other Canon cameras, you might need to fine-tune the FLASH_DELAY parameter. To simplify the process, one can recompile the Arduino code with the DEBUG parameter enabled in three_d_scanner.h . After that, the gadget's keys 9/C can be used to change the FLASH_DELAY parameter on the fly (this doesn't get saved to EEPROM!), while taking FRSP shots with an external flash, until proper flash exposure is achieved. Once the good value of FLASH_DELAY is found, it needs to be programmed into the Arduino code (FLASH_DELAY value in three_d_scanner.h - the units are microseconds).
You might also need to play with the DT_AF parameter, and dt_shots parameter, to make this work for your particular camera model. For Canon 50D and 6D, dt_shots should be at least 6.0s; with shorter values some shots will not be exposed. That means that the fastest rate of taking images using FRSP with these cameras is one every 6 seconds.
Other cameras[]
The 3D scanner will work with any other camera, as long as its shutter can be triggered via a wired (or perhaps IR/RF) controller. In the simplest case, the external flash can be attached to the camera (not to the 3D scanner). You can set DT_AF to 200000 us (0.2s) and FLASH_DELAY to 100000 (0.1s), and that will let you use dt_shots as short as 0.2s (five frames per second) - as long as your camera (and most importantly - flashes) can handle such a framerate. (Be aware that the higher the framerate is, the faster the object's rotation is, so the motion blur can become an issue at some point.) The 3D scanner's camera pin should be connected to your camera's shutter pin (not AF pin) in this scenario.
If your camera is a Nikon DSLR, a convenient way to attach the camera is via a 3.5mm male-2.5mm female adapter and a corresponding Yongnuo shutter cable (e.g. this one).
Tests[]
This is a scan of a ~20cm tall statue, using three different camera angles (horizontal - 0 dgr, 30 dgr, and 60 dgr), 50 shots per angle (150 shots in total). I used Canon 6D with 50mm f1.8 STM lens. To view the wrl file you can install Cortona3D viewer.
