Arduino Controller for Automated 360° Product Photography

20,716

94

49

Introduction: Arduino Controller for Automated 360° Product Photography

About: Diploma Designer and passionate Maker. Loves the connection between Engineering and Design.

Let's build an arduino based controller that controls a steppermotor and a camera shutter. Together with a steppermotor driven turntable, this is a powerful and low cost system for automated 360° product photography or photogrammetry.
The automatic camera shutter is based on a great library from „Sebastian Setz“ and works for infrared triggered cameras of Nikon, Canon, Minolta, Olympus, Pentax, Sony.

I've prepared two versions of the controller:

  • A basic version that is operated with a simple pushbutton and a status led.
  • An advanced version that uses a 16x2 LCD + keypad shield and thus has a menu to change the variables „on the fly“ and not only in the sourcecode.

What does the controller do?

If you trigger a „photoshooting“ by pushing the button, the turntable performs a full revolution, divided into a predefined amount of steps. After each rotation step, the controller makes a short break and then triggers the camera. You will be able to change the variables of the rotation speed, the delay time and the number of steps in the source code (for simple controller version) or in the display menu (advanced controller version).

Step 1: Gather Parts and Files

Parts:

  • Arduino Uno (or similar)
  • Breadboard (halfsize breadboard fits)
  • Easydriver Stepper Motor Driver
    https://www.sparkfun.com/products/12779
  • 2X Heatsink for Easydriver (optional but HIGHLY recommended)
    https://www.sparkfun.com/products/11510You'll need thermal tape to fix the heatsink onto the chip. If you order your heatsink, make sure that termal tape is inclued or can be ordered separately.
  • Infrared LED 950nm (for IR camera trigger)
  • Resistor 220 ohms (pre-resistors for infrared-LED)
  • Piezo sound element (optional, if you want to have feedback sounds)
  • Some Jumper Wires
  • External Power Supply for Steppermotor
    I made good experiences with a 12V 1A power adapter to drive a 1A NEMA 17 Steppermotor from Trinamic. I also had a 24V 3A power adapter in use. The Easydriver board supports up to 30V and 750mA per phase. More on the easydriver-specs here: http://www.schmalzhaus.com/EasyDriver/index.html
  • Socket for steppermotor's external power supply
  • Bipolar NEMA 17 Steppermotor and Turntable e.g. the FluxGarage „Automated Turntable With Steppermotor“ Link: https://www.instructables.com/id/Automated-Turnta...

Add for basic pushbutton-controller ...

  • Pushbutton
  • Resistor 10k ohms (for the pushbutton)
  • LED (status-led)
  • Resistor 220 ohms (pre-resistors for status-LED)

... OR add for advanced controller with display+keypad menu:

Download the Arduino codes and Fritzing diagrams for basic and advanced controller:
https://github.com/FluxGarage/Controller-for-Stepp...

If you want to open the Fritzing document for the advanced controller, make sure to download and install the adafruit elements: https://blog.adafruit.com/2012/08/27/how-to-insta...


Please note:
On the pictures I'm using the FluxGarage „Tinkerer's Baseplate“ and the FluxGarage „Front Plate for 16x2 LCD + Keypad Shield“. Using those elements is optional, if you also want to use them, klick at the links for the regarding instructables.

Step 2: Assemble Circuit

Solder Easydriver board for breadboard use:
In order to use the easydriver on a breadboard, you need to solder some male pin headers on the board. The best way is to put the male pin headers into the breadboard, lay the easydriver on top and then solder the pins.

Wiring up:
Wire up the parts as shown in the regarding Fritzing graphic for the basic or advanced controller. Download the Firtzing diagrams on github, find the links in step 1.

Double check if everything is connected as follows:

  • Arduino digital pin 02 = dir pin of Easydriver
  • Arduino digital pin 03 = step pin of Easydriver
  • Arduino digital pin 09 = output for piezo
  • Arduino digital pin 12 = output for infrared LED (place 220 ohms pre resistor before led)

+ for Basic Controller:

  • Arduino digital pin 04 = input for pushbutton (place 10k ohms resistor before button ground)
  • Arduino digital pin 13 = output for status LED (place 220 ohms pre resistor before led)

+ for Advanced Controller:

  • Stack the display + keypad shield onto the arduino, actually those pins are used: Arduino analog pin A4+A5 and 5V+GND.

Connect Steppermotor:
Wiring up bipolar stepper motors (4 wires) is about connecting the two coils (A and B) of the motor to the right pins of the easydriver board.
Take a look at the graphic in the middle of this page and at the specs of your specific stepper motor:
http://www.schmalzhaus.com/EasyDriver/index.html

You can also find more information about wiring up your stepper motor and the Easydriver here: http://bildr.org/2011/06/easydriver/

Connect External Power Supply
The Easydriver board has two separate power pins on the upper right side (M+ and Ground). While the board itself gains power from the Arduino, the separate input provides power for the steppermotor. If you use a typical „out of the box“ power adapter and a socket, you should connect the „+“ wire to the „M+“ pin of the easydriver and the „-“ wire to easydriver's the „GND“ pin. Usually the „+“ is on the inner side, whereas the „-“ is on the outer side of the plug. But be careful, some power adapters allow to switch the polarity! If you wire your easydriver incorrect, it may and will probably be damaged, keep that in mind.

Step 3: Upload Sourcecode to Arduino

Download the Arduino sourcecode at Github:
https://github.com/FluxGarage/Controller-for-Steppermotor-Turntable-and-IR-Camera-Shutter

Download Arduino IDE:

https://www.arduino.cc/en/Main/Software

Download the third party libraries and copy them to your IDE's library folder:
… for the camera shutter:
https://github.com/dharmapurikar/Arduino/tree/mast...
… for the Adafruit 16x2 Display+Keypad Shield:
https://github.com/adafruit/Adafruit-RGB-LCD-Shiel...

The code is tested and works fine with the latest Arduino IDE (1.8.7 on windows) and Arduino Uno + Easydriver Stepper motor Driver + Adafruit 16x2 Display+Keypad Shield, + a Trinamic stepper motor and a Nikon D60 camera.

Adjust code to work with your specific camera:
As mentioned, I used the „multiCameraIrControl.h“ library by Sebastian Setz. To make it work for your camera, you have to delete the comment slashes before your camera manufacturer name and of course add slashes before all the other manufacturer names:

// Set Camera Type<br>Nikon D5000(12);<br>//Canon D5(12);<br>//Minolta A900(12);<br>//Olympus E5(12);<br>//Pentax K7(12);<br>//Sony A900(12);

Do the similar adjusment in the „snap“ function:

// Take a picture<br>void snap(){<br>D5000.shotNow();<br>//D5.shotNow();<br>//A900.shotNow();<br>//E5.shotNow();<br>//K7.shotNow();<br>//A900.shotNow();<br>}

Please note:
Unfortunately, I wasn't yet able to test other IR triggered cameras yet than my own Nikon D60. The camera shutter library should work with several cameras of the different manufacturers, not only the specific camera models that are mentioned in the code. It would be great if you post a comment on your experiences with your Canon, Minolta, Olympus, Pentax or Sony camera.

Step 4: Operate the Controller

What does the code respectively the controller do?
If you push the button, a „photoshooting“ is triggered. Each Photoshooting is a finite loop of the following sequence:

  1. Camera is triggered
  2. Short delay
  3. Steppermotor will rotate a predefined amount of degrees
  4. Short delay

A photoshooting is based on a set of variables that determine its exact behaviour. You can change these variables in the sourcecode (for simple controller version) or in the display menu (advanced controller version).


Operating the basic controller:

On the basic controller the Status LED shows when the system is ready to perform. The LED turns off when you start a photoshooting. You can interrupt a photoshooting by holding the button until the „interrupt sound“ appears and the turntable stops. Have a look at the video in this instructable's top section to see this in "real life".

The photoshooting's variables can be found in the code's top section, and can be changed to modify the photoshooting. Below you can see the initial values:

int shootingsteps = 20; // number of steps for a full revolution, should be 10, 20 or 40<br>float shootingspeed = 0.01; // rotation speed: any number from .01 -> 1 with 1 being fastest -
Slower is stronger (slower = better for „heavy“ objects)<br>int shootingdelay = 1000; // break in milliseconds before and after each rotation


Operating the advanced controller:

When turning the advanced controller on, a FluxGarage logosplash is shown for 4 seconds. After that, the controller is ready to perform and shows a list of the adjustable set of variables:

  • ST = Number of Steps, can be 10, 20 or 40
  • SP = Rotation Speed, can be 1-5 while 1 being slowest
  • DE = Delay before and after each step in tenth of a second, can be 5, 10, 25, 50
  • LI = Determines if the display's background light is on or off while shooting. Can be 1 = on or 0 = off

You can navigate through the variable types with the left and right buttons and change the values with the up and down buttons.
Start a photoshooting by pressing the select button and interrupt a photoshooting by holding the select button until the „interrupt sound“ appears. Have a look at the video in this instructable's top section to see this in "real life".

Step 5: Start Shooting

If you've built your own controller + turntable and your camera is in place, you're all set to start shooting ... almost. Let me share some learnings from my own experiments:

  • Use a light tent to illuminate your objects evenly. You can find lots of good tutorials here at instructables.com that show how to create a diy lightbox. Also, there are inexpensive textile light tents that can be bought in many online shops.
  • Use lightbulbs with the same color temperature (Kelvin)
  • Focus the object on the turntable manually, deactivate your camera's autofocus
  • Turn off your camera's image stabilizer, if working with a tripod
  • Select a measuring range in the background, where the shot object won't appear. By doing so, you'll avoid flickering in your image sequence. Another way is to manually set your camera's exposure times etc.
  • If you want to include your 360-Images into your website, use javascript plugins like
    „Jquery Reel Plugin“ by Petr Vostřel alias „PISI”
    http://jquery.vostrel.cz/reel
    „360 Degrees Product Viewer“ by „Codyhouse“
    https://codyhouse.co/gem/360-degrees-product-view...

This is the result of one of my shootings (created with above's setting):
http://www.fluxgarage.com/turntable_360viewer.html

Be the First to Share

    Recommendations

    • Home and Garden Contest

      Home and Garden Contest
    • Science Fair Challenge

      Science Fair Challenge
    • Origami Speed Challenge

      Origami Speed Challenge

    49 Comments

    0
    NickN78
    NickN78

    Question 21 days ago

    I recently needed to replace my power supply on my turntable, but I now notice something strange and wanted to get someone's thoughts.

    I have 3 shootingsteps 50, 100, 200.
    50 and 100 rotate counter-clockwise, but 200 rotates clockwise.
    Maybe something is weird in my code. Any suggestions, or would anyone be open to taking a look at my code?

    0
    FluxGarage
    FluxGarage

    Answer 18 days ago

    Did you try to disconnect the "direction" pin that goes from your arduino to the motor driver board?
    If you did this and the turntable is then always moving in one same direction, you can assume that, for some reason, the dir pin is pulled high or low respectively. This can be caused by your code or due to some hardware problem.

    0
    NickN78
    NickN78

    Reply 12 days ago

    I removed the Direction pin from the driver board and indeed this corrected the issue. I have a lot to learn. As long as this being disconnected isn't causing any harm I will leave for now. Thank you. Wish I was better at debugging

    0
    FluxGarage
    FluxGarage

    Reply 10 days ago

    Disconnecting this wire won't harm your driver board. The dir pin on the easydriver board expects a digital signal (high or low) - which determines the direction of rotation.
    With this pin/wire disconnected, the digital signal is low. If you want your turntable to rotate in the opposite direction, you could also manually connect it to the 5V output of your arduino. But sure, you wouldn't have the ability to control the direction with your arduino code.

    Have a look at the "Quick Pin Description" here:
    https://www.schmalzhaus.com/EasyDriver/

    0
    NickN78
    NickN78

    4 weeks ago on Step 4

    I was wondering if anyone has successfully integrated a “preview rotation” feature. One that would rotate the object a full 360 without taking photos or stopping to ensure the placement of your object to be photographed was centered properly. I’m new to coding and this seems complicated

    0
    FluxGarage
    FluxGarage

    Reply 4 weeks ago

    This is possible. To be honest, this was one of my first projects where I started to learn coding. Thus, many things could have been done more elegant. But if you just want to extend the basic controller, the following steps should work (not tested yet):

    1. Add another button to your hardware setup and connect it to arduino pin 5 (similar to the first button as shown in the pictures)
    2. Then add the code below to the sketch and upload it to your arduino.
    3. If you then push the new preview button, the turntable should perform one full preview rotation without stopping and taking pictures.

    ADD THIS TO THE HEADER SECTION:
    // Preview-Button Pin
    #define PREVBUTTONPIN 5

    ADD THIS TO THE SETUP SECTION:
    // Preview-Button Pin
    pinMode(PREVBUTTONPIN, INPUT);

    ADD THIS TO THE MAIN LOOP:
    if (digitalRead(PREVBUTTONPIN)==HIGH){
    previewRotation(); // perform one full preview revolution
    }

    ADD THIS TO THE FUNCTIONS, E.G. AT THE BOTTOM OF THE DOCUMENT:
    void previewRotation () {
    rotateDeg(360, shootingspeed);
    }

    0
    NickN78
    NickN78

    Reply 4 weeks ago

    This is incredibly helpful, as was you initial instructions for the turntable set up.
    Thank you..
    I build the advanced controller, does the change your instructions?

    Nick

    0
    FluxGarage
    FluxGarage

    Reply 4 weeks ago

    For the advanced controller, it will be a bit different. There you won't have to add an additional button. The crucial thing is to run the new function "previewRotation". With the following instructions you will replace the ability to turn off the display light during shooting with a new setting "preview mode" ("PR") on/off. So, if you go to the last menu item "PR" and set it to 1, you will run the preview mode when pressing the confirm button. If you want to do the shooting, you have to set PR back to 0.
    This could also be done more elegant with menu scrolling etc. but this is the minimal invasive approach (not tested yet, let the community know, if it worked):

    REPLACE LINE 96 WITH THIS:
    char* menunames[] = {"ST","SP","DE","PR"};

    COMMENT OUT THIS AT LINE 237:
    if (valueArray[3]==0){lcd.setBacklight(LOW);}

    REPLACE THE LAST CONDITIONAL (STARTING AT LINE 174) IN THE IF(BUTTONS) CONDITIONAL WITH THIS:
    if (buttons & BUTTON_SELECT) {
    if(valueArray[3]==1){
    previewRotation();
    }else{
    shootingstatus=1; photoshooting();}
    }

    ADD THIS TO THE FUNCTIONS, E.G. AT THE BOTTOM OF THE SKETCH:
    void previewRotation () {
    rotateDeg(360, shootingspeed);
    }

    0
    NickN78
    NickN78

    Reply 14 days ago

    Thank you for the clear instructions. Unfortunately I'm getting some errors. mainly 'initialprint' was not declared in this scope

    Here's the full error message. Any thoughts?

    Arduino: 1.8.19 (Windows Store 1.8.57.0) (Windows 10), Board: "Arduino Uno"
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino:162:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    char* menunames[] = {"ST","SP","DE","PR"};
    ^
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino:162:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino:162:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino:162:41: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino: In function 'void setup()':
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:215:3: error: 'initialprint' was not declared in this scope
    initialprint();
    ^~~~~~~~~~~~
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino:215:3: note: suggested alternative: 'initVariant'
    initialprint();
    ^~~~~~~~~~~~
    initVariant
    C:\Users\Nick\Documents\Arduino\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST\Newest_Fux_goog_20220423_works_full360_PREVIEWTEST.ino: In function 'void loop()':
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:242:9: error: 'previewRotation' was not declared in this scope
    previewRotation();
    ^~~~~~~~~~~~~~~
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:244:25: error: 'photoshooting' was not declared in this scope
    shootingstatus=1; photoshooting();
    ^~~~~~~~~~~~~
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:264:22: error: a function-definition is not allowed here before '{' token
    void initialprint () {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:289:12: error: a function-definition is not allowed here before '{' token
    void snap(){
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:300:22: error: a function-definition is not allowed here before '{' token
    void photoshooting() {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:361:20: error: a function-definition is not allowed here before '{' token
    void buttonsound() {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:366:19: error: a function-definition is not allowed here before '{' token
    void startsound() {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:373:20: error: a function-definition is not allowed here before '{' token
    void finishsound() {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:380:23: error: a function-definition is not allowed here before '{' token
    void interruptsound() {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:391:40: error: a function-definition is not allowed here before '{' token
    void playTone(long duration, int freq) {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:404:36: error: a function-definition is not allowed here before '{' token
    void rotate(int steps, float speed){
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:423:39: error: a function-definition is not allowed here before '{' token
    void rotateDeg(float deg, float speed){
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:441:20: error: a function-definition is not allowed here before '{' token
    void stopbutton () {
    ^
    Newest_Fux_goog_20220423_works_full360_PREVIEWTEST:454:1: error: expected '}' at end of input
    }
    ^
    exit status 1
    'initialprint' was not declared in this scope
    This report would have more information with

    0
    FluxGarage
    FluxGarage

    Reply 14 days ago

    Most likely this is a syntax error. Probably there is one "}" missing, that's why the IDE can't understand the function definitions.
    -> "expected '}' at end of input"

    If you find the missing "}", this will probably be the solution for most or all compiling issues.

    0
    NickN78
    NickN78

    Reply 4 weeks ago

    This is so incredibly helpful. Thank you so much.
    I haven't done any of this coding in a while, but it sounds pretty straight forward.

    Thank you!!

    0
    robdontech
    robdontech

    Question 2 months ago on Step 5

    Hi, I am a newbie to this. I wanted to ask if it is possible to replace the infra red switch with an octo insulator attached to a wcanon wired shutter control. As i understand it the shutter simply needs to be sent a signal to create a high enough voltage to trigger the switch. Is this simply a mater of replacing the led?

    0
    FluxGarage
    FluxGarage

    Answer 4 weeks ago

    With the current code, a certain bit sequence will be sent to the led pin, meaning a series of highs and lows. If you want to trigger a camera via cable, it's instead only about sending a simple high/low signal to the specific pin you want to use.
    Instead of an opto coupler, a simple diode should fit. For more information on that just have a look at step 5 of this instructable I've already posted in one of my answers above:
    https://www.instructables.com/Automatic-Camera-Shutter-Switch/

    0
    jesusmcyc
    jesusmcyc

    8 weeks ago

    Amazing project. Thank you.


    So far I have done it with the basic controller.
    I'm doing it again, but the advanced one. But I just can't get my hands on the Adafruit LCD Shield, I can't find it in Mexico. I'm just trying to figure it out, doing it with a regular LCD 2x16 keypad shield.

    0
    FluxGarage
    FluxGarage

    Reply 7 weeks ago

    Thanks! In general, it should be possible to replace the adafruit display shield with a different one. Probably there will be a different port expander chip on other shields and thus you might have to use different libraries and adjust the button handling in the code.

    0
    pascalwiemers
    pascalwiemers

    3 months ago

    How hard do you think it would be to use a wired camera trigger instead of IR (Sony A7rii)? Using it for photogrammetry and the ringflash would get in the way (could also make the IR cable longer I guess but it would be nice to have a cable :) )

    0
    robdontech
    robdontech

    Reply 2 months ago

    I would like to know this too :)

    0
    FluxGarage
    FluxGarage

    Reply 3 months ago

    This shouldn't be a big deal, if you already have the right cable for your camera. There's a good instructable for this, just have a look at "Step 5: Activate the Camera Shutter With a Microcontroller":
    https://www.instructables.com/Automatic-Camera-Shutter-Switch/

    Once you have your hardware set up according to above's instructable, you just have to replace the content of the snap()-function of the controller code with sending a low signal to the specific hardware pin. And of course, you should then send a high signal again, so that the camera will only be triggered once.

    0
    NickN78
    NickN78

    Question 5 months ago

    I have this great project working with my Sony AR7II. However, my wife rented the SonyA7R4 and the IR triggering was not working. Could someone help me understand how to change the code to accommodate different IR capable cameras?

    0
    FluxGarage
    FluxGarage

    Answer 5 months ago

    The magic lies in the specific IR signal frequency and bit sequence that differs from manufacturer to manufacturer and in some cases also from camera model to camera model.
    The controller that is described here uses the library "multiCameraIrControl", which covers several camera models and could be theoretically extended with your model specific code.
    I think it makes most sense to leave a comment at the following page, so that the library's author (hopefully) might give you a more concrete answer on what is possible:
    https://codebender.cc/library/multiCameraIrControl#multiCameraIrControl.h

    EDIT:
    This is the Sony-related subpage:
    https://codebender.cc/example/multiCameraIrControl...