Pedro52
Published © GPL3+

Arduino controlled Turntable for 3D Photography

3D-printed turntable with stepper motor automatically taking pictures with a camera via Bluetooth to create 3D pictures for 3D printing.

AdvancedFull instructions provided5,198
Arduino controlled Turntable for 3D Photography

Things used in this project

Hardware components

NodeMCU ESP32
for Turntable server
×1
Resistor 4.75k ohm
Resistor 4.75k ohm
4K7 Ohm
×2
Resistor 221 ohm
Resistor 221 ohm
220 Ohm
×2
Capacitor 10 µF
Capacitor 10 µF
×1
Capacitor 220 µF
Capacitor 220 µF
330 uF
×1
Capacitor 1000 µF
Capacitor 1000 µF
3300 uF
×1
Stepper Motor, Mini Step
Stepper Motor, Mini Step
Hanpose 17HS3430 Stepper Motor
×1
Switch Actuator, Head for spring return push-button
Switch Actuator, Head for spring return push-button
×4
Industrial Pushbutton Switch, Push-Pull
Industrial Pushbutton Switch, Push-Pull
×1
Google end stop switch
×1
Capacitor 100 nF
Capacitor 100 nF
×4
connector female 5.5 mm
×1
Dual H-Bridge motor drivers L298
SparkFun Dual H-Bridge motor drivers L298
×1
3 mm LED: Red
3 mm LED: Red
×1
LED 3 mm Blue
×1
9V 1A Switching Wall Power Supply
9V 1A Switching Wall Power Supply
12 V 3 A
×1
Light box 30 * 22 cm
×1
plastic cutting board 34*24 cm
×1
Parts needed for Camera Client
×1
3DR 3D printed box 57 * 77 * 28 mm
×1
Resistor 221 ohm
Resistor 221 ohm
220 Ohm
×7

Software apps and online services

Arduino IDE
Arduino IDE
Fusion 360
Autodesk Fusion 360
CURA
ClickCharts
EasyEDA
Fritzing

Hand tools and fabrication machines

Common tools and test equipment
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

housing for the OLED display

3D printed housing for the 0,96” OLED display

Turntable

Turntable with spindle for the stepper motor

housing for the Camera Client

housing for the camera client made with Fusion 360, derived from a design of Andreas Spiess

housing for the Multiconnector (top part)

housing for the 10+5 pins multiconnector to be connected to the micro USB port of the Sony HX 400 camera (to and bottom part

housing for the Multiconnector (bottom part)

housing for the 10+5 pins multiconnector to be connected to the micro USB port of the Sony HX 400 camera (to and bottom part

Schematics

circuit diagram for the Server

This diagram shows the setup of the electronics for the Turntable server:

circuit diagram for the Camera Client

This diagram shows the setup of the electronics for the camera client

Code

Turntable server.ino

Arduino
ARDUINO Sketch for the turntable server running on an ESP32
/*********
  This project has been developed and produced by Pierre Pennings (September/October 2019),
  It applies parts of the code (related to BLE client/server) published by Rui Santos https://randomnerdtutorials.com/courses : Learn ESP32 with Arduino IDE
  His book has been a great help for me to realise this project.

  This Project is about making a (3D printed) Turntable rotate in a selectable number of steps per 360 degrees using a Stepper Motor.
  The turntable's housing contains a ESP 32 (NodeMCU) that is programmed as a Bluetooth Low Energy (BLE) server.
  After every step of x degrees, the turntable stops and sends a command over the Bluetooth
  connection to another ESP32, that is set up as e BLE Client.
  The BLE Client is interfaced with a Sony HX400V Camera through a special Multiconnector (looks like a micro USB C)
  to activate the focus and the camera shutter and then move another step of x degrees. At the same time a LED spotlight can be activated.
  
  The ESP 32 device works at 3.3 Volt levels.
  The ESP module is fed with 5 V derived from the Stepper Motor driver L298N which is connected to a 12V 3A supply.
  The 12V connection is used to power the Stepper Motor.
  The ESP 32 that has an on-board 3.3V voltage regulator, which is used for powering the 128*64 OLED display.
  Four different pushbuttons are used to control the turntable.
      * the RED button (ModeSelect) is used for interaction with the OLED display for mode settings
      * The righthand GREEN button (ManualShot) is used for confirmation of the selected turning mode.
      (and could also be programmed for taking manual pictures with the remote camera)
      * The GREEN button (GoToOrigin) left of the OLED Display is used for commanding the turntable to its ORIGIN Position (sensed with a switch underneath the turntable)
      * The other GREEN button (StartPause) on the most left of the OLED Display is used for starting or pausing an action and choosing another mode
      (with the current programme it causes a system reset and gets you back to the WELCOME menu)
      
  This code is licensed under GPL3+ license.
  
*********/

#include <BLEDevice.h>                                                  // Include the BLE Libraries
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#include <AccelStepper.h>                                               // Include the Arduino AccelStepper Library
#define FULL4WIRE 4                                                     // defines the type of StepperMotor used (NEMA 17)

#include <Wire.h>                                                       // Include the Libraries for the OLED display
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

#define SCREEN_WIDTH 128                                                // OLED display width, in pixels
#define SCREEN_HEIGHT 64                                                // OLED display height, in pixels
#define OLED_RESET -1

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define bleServerName "TurnTableESP32"                                  //BLE server name
#define SERVICE_UUID "e6c24700-6f9c-4bf4-b078-4fc82fad3e28"             //See for generating UUIDs: https://www.uuidgenerator.net/

BLECharacteristic CONTROLCharacteristics("1e0ed88a-1b69-4197-83fa-0373670c4819", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor CONTROLDescriptor(BLEUUID((uint16_t)0x2903));

/////////////////////////////////initialise the GPIO pins///////////////////////////////////////////////////////////////////////////////////////////////////////////////
const int BlueToothPin = 12;                                            // GPIO Pin 12 of ESP32 connected to BlueLED for showing the BlueToothStatus
const int ModeSelectPin = 13;                                           // GPIO Pin 13 of ESP32 to select the Mode of operation of the Turntable (Red button)
const int StartPausePin = 32;                                           // GPIO Pin 32 of ESP32 connected to a Green Pushbutton for Starting/Pausing the Turntable
const int GoToOriginPin = 33;                                           // GPIO Pin 33 of ESP32 connected to a Green Pushbutton for commanding the Turntable to origin position
const int ManualShotPin = 4;                                            // GPIO Pin 4 of ESP32 connected to Pushbutton for taking a manual shot
const int OriginPin = 15;                                               // GPIO Pin 15 of ESP32 connected to a switch on the turntable to sense that the Turntable has reached the Origin position
const int motorPin1 = 14 ;                                              // IN1 on the L298 N driver (Blue)
const int motorPin2 = 27 ;                                              // IN2 on the L298 N driver (Pink)
const int motorPin3 = 26 ;                                              // IN3 on the L298 N driver (Yellow)
const int motorPin4 = 25 ;                                              // IN4 on the L298 N driver (Orange)
// NOTE: GPIO Pin 21 of ESP32 is connected to the SDA pin and GPIO Pin 22 of ESP32 is connected to the SCL pin of the OLED display; no initialisation is needed for these pins

const int stepsPerRevolution = 200;                                     // Number of steps for one 360 degrees rotation of the Stepper Motor

//////////////////////////////////initialise the Global variables///////////////////////////////////////////////////////////////////////////////////////////////////////
int ShootPinState = 1;                                                  // variable for reading the Manual Shoot pushbutton status

float stepperSpeed = 800;                                               //speed of the steppermotor (steps per second)
int Revcount = 0 ;                                                      // Number of revolutions to made since Start
int stepcount = 0 ;                                                     // variable for counting the steps in the 360 degrees turn
int turnmode = 0  ;                                                     // variable for selecting the turning mode of the Turntable
                                                                        // 1 => 5 steps of 72 degrees, 2 => 10 steps of 36 degrees, 3 => 15 steps of 24 degrees, 4 => 20 steps of 18 degrees,  5 = continous rotation

volatile bool GoToOriginState = false;
volatile bool StartPauseState = false;

void IRAM_ATTR GotoORIGIN()
    {
    GoToOriginState = true;
    Serial.println("GoToOrigin pushed");
    }

void IRAM_ATTR STARTPAUSE()
    {
    StartPauseState = true;
    Serial.println("StartPause button pushed");
    }
    
bool deviceConnected = false;
bool BLE = false;
char TakeAuto[11] = "AutoShot";
char TakeManual[11] = "ManualShot";


///////////////////////////////// Create Instance of Stepper library//////////////////////////////////////////////////////////////////////////////////////////////////////
AccelStepper stepper(FULL4WIRE, motorPin1, motorPin2, motorPin3, motorPin4);

/////////////////////////////////set up of the callbacks procedure for BLE////////////////////////////////////////////////////////////////////////////////////////////////
class MyServerCallbacks: public BLEServerCallbacks                      //Setup callbacks onConnect and onDisconnect
{
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
  };
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }
};

///////////////////////////////the setup code that follows, will run once after "Power On" or after a RESET////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);                                                 // Start serial communication with serial monitor of the Arduino IDE

  pinMode (motorPin1, OUTPUT);                                          // Set the motorPin1 as output
  pinMode (motorPin2, OUTPUT);                                          // Set the motorPin2 as output
  pinMode (motorPin3, OUTPUT);                                          // Set the motorPin3 as output
  pinMode (motorPin4, OUTPUT);                                          // Set the motorPin4 as output
  pinMode (BlueToothPin, OUTPUT);                                       // Set the BlueToothPin as output

  pinMode (ManualShotPin, INPUT_PULLUP);                                // Set the ManualShotPin as input and use the internal pullup resistor to set the Pin to HIGH
  pinMode (ModeSelectPin, INPUT_PULLUP);                                // Set the ModeSelectPin as input and use the internal pullup resistor to set the Pin to HIGH
  pinMode (StartPausePin, INPUT_PULLUP);                                // Set the StartPausePin as input and use the internal pullup resistor to set the Pin to HIGH
  pinMode (GoToOriginPin, INPUT_PULLUP);                                // Set the GoToOriginPin as input and use the internal pullup resistor to set the Pin to HIGH
  pinMode (    OriginPin, INPUT_PULLUP);                                // Set the     OriginPin as input and use the internal pullup resistor to set the Pin to HIGH

  attachInterrupt(digitalPinToInterrupt(GoToOriginPin), GotoORIGIN, FALLING); 
  Serial.print("goto origin pin  "); Serial.println(GoToOriginState);

  attachInterrupt(digitalPinToInterrupt(StartPausePin), STRTPSE, FALLING); 
  Serial.print("Start/pause pin  "); Serial.println(StartPauseState);
  
  Wire.begin();                                                         //OLED display setup
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  
  display.clearDisplay();
  
  stepper.setMaxSpeed(3000.0);                                          // setting the maximum speed of the steppermotor
  stepper.setSpeed(stepperSpeed);                                       // setting the running speed of the steppermotor at the value of stepperSpeed
  stepper.setAcceleration (200.0);                                      // setting the Acceleration of the steppermotor 

  /////////////////////herafter functions are called for setting up the Turntable Server////////////////////////////////////////////////////////////////////////// 
  WELCOME ();                                                           //displaying a welcome message until the red button is pushed
  TURNTABLEMODES ();                                                    //displaying the possible turntable modes of operation 
  delay (200);
  HOWTOSET ();                                                          //displaying an explanation how to select the turntable modes
  SETMODE ();                                                           //setting the turntable modes by pushing the red button and selecting with the green button
  delay (2000);                                                         //display selected mode for 2 seconds
  ORIGIN ();                                                            //controlling the turntable to an origin position
 

  /////////////////////routine for setting up the Bluetooth connection with the Camera Client//////////////////////////////////////////////////////////////////////////
  BLEDevice::init(bleServerName);                                       // Create the BLE Device
  BLEServer *pServer = BLEDevice::createServer();                       // Create the BLE Server
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *ControlService = pServer->createService(SERVICE_UUID);    // Create the BLE Service
  
  ControlService->addCharacteristic(&CONTROLCharacteristics);            //Create BLE Characteristics
  CONTROLDescriptor.setValue("Control");                                 //Create a BLE Descriptor
  CONTROLCharacteristics.addDescriptor(new BLE2902());                   //Descriptor https://www.bluetooth.com/specifications/gatt/descriptors/  
  
  ControlService->start();                                               // Start the service
  pServer->getAdvertising()->start();                                    // Start advertising
  Serial.println("Trying to make a BLE connection with the Camera client"); 
  }

////////////////////////////the loop code that follows, will run repeatedly until "Power Off" or a RESET///////////////////////////////////////////////////////////////
void loop() {
  
  CONNECTION();
    
  switch (turnmode) {    
      case 1:                                                           // Turnmode 1: 5 X 72 dgr)
        STARTandTURN();
        break;
          
      case 2:                                                           // Turnmode 2: 10 X 36 dgr)
        STARTandTURN();
        break;
        
      case 3:                                                           // Turnmode 3: 15 X 24 dgr)
        STARTandTURN();
        break;
        
      case 4:                                                           // Turnmode 4: 20 X 18 dgr)
        STARTandTURN();
        break;
        
      case 5:                                                           // Turnmode 5: CONTINUOUS
        STARTCONTINUOUS ();
        break;    
                  }  
}
//////////////////END of LOOP////////////////////////////////////

/////////////////Hereafter follows the Function for sending a Command message to the Client
void SendCommand (char message [10])
    {
    CONTROLCharacteristics.setValue(message);                           //Set Characteristic value as an integer and notify connected client
    CONTROLCharacteristics.notify();   
    }

/////////////////Hereafter follows the Function for displaying a Welcome message at Start-up of the Turntable on the OLED Display////////////////////////////////////////
void WELCOME ()
    {
  display.startWrite();
  display.setTextSize(2);
  display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
  display.setCursor(0,0);
  display.println("WELCOME! ");
  display.setTextSize(1);
  display.println("Automatic TurnTable");
  display.println("by Pierre Pennings");
  display.println("to make 3D pictures");
  display.println("");
  display.setTextColor(BLACK, WHITE);                                   // Draw 'inverse' text
  display.println("to PROCEED:");
  display.println("    Push RED BUTTON");
  display.display();

  while (digitalRead (ModeSelectPin))
    { 
     digitalWrite(BlueToothPin, HIGH);                                  // turn the blue LED on
     delay(10);                                                         // wait 10 miliseconds
     digitalWrite(BlueToothPin, LOW);                                   // turn the LED off by making the voltage LOW
     delay(500);                                                        // wait 500 miliseconds
    } 
  delay(500);
  Serial.println(" ModeSelectPin = 01  ");
  digitalWrite(BlueToothPin, LOW);                                      // turn the blue LED off
  display.clearDisplay();
    }

/////////////////Hereafter follows the Function for displaying the possible Turntable Modes on the OLED Display/////////////////////////////////////////////////////////////
void TURNTABLEMODES ()
    {
  display.startWrite();
  display.setTextSize(2);
  display.setCursor(0,0);
  display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
  display.println("TURNTABLE");
  display.setTextSize(1);
  display.println("Mode 1 =  5 * 72 dgr");
  display.println("Mode 2 = 10 * 36 dgr");
  display.println("Mode 3 = 15 * 24 dgr");
  display.println("Mode 4 = 20 * 18 dgr");
  display.println("Mode 5 = Continuous");
  display.setTextColor(BLACK, WHITE);                                   // Draw 'inverse' text
  display.println("PROCEED: RED BUTTON");
  display.display();
  
  while (digitalRead (ModeSelectPin))
    { 
     digitalWrite(BlueToothPin, HIGH);                                  // turn the blue LED on
     delay(10);                                                         // wait 10 miliseconds
     digitalWrite(BlueToothPin, LOW);                                   // turn the LED off by making the voltage LOW
     delay(500);                                                        // wait 500 miliseconds
    }
   delay(500);
   Serial.println(" ModeSelectPin == 02  ");
   digitalWrite(BlueToothPin, LOW);                                      // turn the blue LED off
   display.clearDisplay();
    }

/////////////////Hereafter follows the Function for displaying an instruction about How to Set the possible Turntable Modes ////////////////////////////////////////////////////
void HOWTOSET ()
    {
  display.startWrite();
  display.setTextSize(2);
  display.setCursor(0,0);
  display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
  display.println("HOW TO SET");
  display.setTextSize(1);
  display.println("to change TurnMode:");
  display.setTextColor(BLACK, WHITE);                                   // Draw 'inverse' text
  display.println("push RED BUTTON");
  display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
  display.println("");
  display.println("if TurnMode is OK :");
  display.setTextColor(BLACK, WHITE);                                   // Draw 'inverse' text
  display.println("push GREEN BUTTON");
  display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
  display.println("-ManualShot Button-");
  display.display();
    }

/////////////////Hereafter follows the Function for setting/changing the Turn Mode and displaying the Selected Turntable Mode on the OLED display //////////////////////////////////
void SETMODE ()
    {
CHANGEMODE:
    turnmode = turnmode + 1;
    display.clearDisplay();
    display.startWrite();
    display.setTextSize(2);
    display.setCursor(0,0);
    display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
    display.print("MODE =");
    display.setCursor(90,0);
    display.println(turnmode);
    display.setCursor(0,45);
    display.setTextSize(1);
    display.setTextColor(BLACK, WHITE);                                   // Draw 'inverse' text
    display.println("Red Button to change");
    display.setCursor(0,55);
    display.println("GREEN Button to stop");
    display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
    display.setTextSize(2);
    display.setCursor(0,20);
  while (digitalRead (ModeSelectPin))
      { 
    digitalWrite(BlueToothPin, LOW);                                      // turn the LED off by making the voltage LOW   
    if (!digitalRead(ManualShotPin))        
        {
      Serial.println("GREEN BUTTON pushed");
      turnmode = turnmode-1 ;
      goto STOPCHANGEMODE;
        }
      }
    {
    digitalWrite(BlueToothPin, HIGH);                                     // turn the blue LED on
  switch (turnmode) {
        case 1:
          display.println("5X 72 dgr");
          display.display();
          break;
        case 2:     
          display.println("10X 36 dgr");
          display.display();
          break;
        case 3:
          display.println("15X 24 dgr");
          display.display();
          break;
        case 4:
          display.println("20X 18 dgr");
          display.display();
          break;
        case 5:
          display.println("CONTINUOUS");
          display.display();
          break;    
                  }  
    delay(500);
    Serial.println("RED BUTTON pushed");
    Serial.print(" turnmode "); Serial.println(turnmode);
    if (turnmode > 5)  {turnmode = 0;}
    goto CHANGEMODE;
    }

    STOPCHANGEMODE:
    //Serial.println("GREEN BUTTON pushed");
    digitalWrite(BlueToothPin, LOW);                                      // turn the blue LED off
    display.clearDisplay();
    display.startWrite();
    display.setTextSize(2);
    display.setCursor(5,0);
    display.setTextColor(BLACK, WHITE);                                   // Draw 'inverse' text
    display.println(" SELECTED ");
    display.setCursor(5,20);
    display.print(" MODE: ");
    display.print(turnmode); display.println("  ");
    display.setCursor(0,45);
    display.setTextColor(WHITE);                                          //display.setBackgroundcolor(WHITE);
    
    switch (turnmode) {
        case 1:
          display.println("5X 72 dgr");
          display.display();
          break;
        case 2:     
          display.println("10X 36 dgr");
          display.display();
          break;
        case 3:
          display.println("15X 24 dgr");
          display.display();
          break;
        case 4:
          display.println("20X 18 dgr");
          display.display();
          break;
        case 5:
          display.println("CONTINUOUS");
          display.display();
          break;    
                  }  
    }

/////////////////Hereafter follows the Function for setting up the BLE connection to the Camera or proceeding without connection  ////////////////////////////////////////
void CONNECTION ()
    {
    while (deviceConnected == false)
    { 
     digitalWrite(BlueToothPin, HIGH);                                  // turn the blue LED on
     delay(50);                                                         // wait 50 miliseconds
     digitalWrite(BlueToothPin, LOW);                                   // turn the LED off by making the voltage LOW
     delay(100);                                                        // wait 100 miliseconds
     Serial.println("trying to connect");
     display.clearDisplay();
     display.startWrite();
     display.setTextSize(2);
     display.setCursor(0,0);
     display.setTextColor(WHITE);                                       //display.setBackgroundcolor(WHITE);
     display.println("BLUETOOTH");
     display.println("CONNECTING");
     display.setTextSize(1);
     display.println("to proceed without");
     display.println("Bluetooth");
     display.println();
     display.setTextColor(BLACK, WHITE);                                // Draw 'inverse' text
     display.println("PUSH RED BUTTON");
     display.display();

    while (digitalRead (ModeSelectPin) == false)
    { 
      Serial.println(" proceed without BLE  ");
      digitalWrite(BlueToothPin, LOW);                                  // turn the blue LED off
      display.clearDisplay();
      display.startWrite();
      display.setTextSize(2);
      display.setCursor(0,0);
      display.setTextColor(WHITE);                                      //display.setBackgroundcolor(WHITE);
      display.println("PROCEEDING");
      display.println("WITHOUT");
      display.println("BLUETOOTH");
      display.display();
      BLE = false;
      delay (2000);
      goto STARTTURNING;
    } 
  }
  if (deviceConnected){
     digitalWrite(BlueToothPin, HIGH);                                  // turn the blue LED on
     display.clearDisplay();
     display.startWrite();
     display.setTextSize(2);
     display.setCursor(0,0);
     display.setTextColor(WHITE);                                       //display.setBackgroundcolor(WHITE);
     display.println("BLUETOOTH");
     display.println("CONNECTED!");
     display.display();
     BLE = true;
     delay (2000);
    }
  STARTTURNING:;
    }

/////////////////Hereafter follows the Function for Starting the Turning of the Turntable  ////////////////////////////////////////////////////////////////////////////////
void STARTandTURN ()
    {
    while (digitalRead (ModeSelectPin) == true)
        { 
          Serial.println("Push RED Button to start");
          display.clearDisplay();
          display.startWrite();
          display.setTextSize(2);
          display.setCursor(0,0);
          display.setTextColor(WHITE);                               //display.setBackgroundcolor(WHITE);
          display.println("TO START");
          display.println("TURNING");
          display.setCursor(0,45);
          display.setTextColor(BLACK, WHITE);                        // Draw 'inverse' text
          display.println("RED BUTTON");
          display.display();
        }
                     
     for (Revcount = 1; Revcount <= (turnmode *5) ; Revcount++) {   
          Serial.print("Revcount "); Serial.println(Revcount);
          display.clearDisplay();
          display.startWrite();
          display.setTextSize(2);
          display.setCursor(0,0);
          display.setTextColor(WHITE);                                //display.setBackgroundcolor(WHITE);
          display.println("  STEP");
          display.print("  ");
          display.print(Revcount);
          display.print(" / ");
          display.println(turnmode *5);
          display.display();
          
          stepper.setSpeed(stepperSpeed/turnmode);                    // set the stepperSpeed at xx steps per second, depending on the turnmode
          stepper.runToNewPosition (stepsPerRevolution/(turnmode*5)*Revcount);     //Moves the motor (with acceleration/deceleration) to the new target position (blocks until it is at position).
          
          display.setCursor(0,42);
          display.setTextSize(3);
          if (BLE == 1){
          display.println(" SHOOT!");                                 // display the fact that the TakeAuto command is given via Bluetooth connection to camera
          display.display();
          delay (500);}
          display.setCursor(0,30);
          display.println("         ");                               // clear the SHOOT field on the display
          display.display();
          SendCommand (TakeAuto);
          delay(2500);
           
          if (GoToOriginState == true)                                // check if Go To Origin button has been pushed
          {ORIGIN (); GoToOriginState = false; Revcount = 0 ; }

        }
          stepper.stop();                                             //Sets a new target position that causes the stepper to stop as quickly as possible, using the current speed and acceleration parameters. 
          stepper.setCurrentPosition(0);
          stepper.disableOutputs();                                   //control of the steppermotor is disabled to avoid unnecessary heating of the motor
        
         // if (StartPauseState == true)                               // check if StartPause button has been pushed
         // {/*STRTPSE ()*/ SETMODE (); StartPauseState = false; }     // THIS DOES NOT WORK THE WAY IT IS MEANT; Pushing the Start/Pause button causes a reset and you enter the welcome menu; which is fine for the moment
    }
       

 /////////////////Hereafter follows the Function for Starting the CONTINUOUS Turning of the Turntable  /////////////////////////////////////////////////////////////////
void STARTCONTINUOUS ()
    {
          Serial.println("Continuous Rotation ");
          display.clearDisplay();
          display.startWrite();
          display.setTextSize(2);
          display.setCursor(0,0);
          display.setTextColor(WHITE);                                  //display.setBackgroundcolor(WHITE);
          display.println("CONTINUOUS");
          display.println("ROTATION");
          display.setTextColor(BLACK, WHITE);                           // Draw 'inverse' text
          display.println("RED BUTTON");
          display.println("TO STOP");
          display.display();
      do
       {
        stepper.setSpeed(40);                                           // rotating at constant speed, until stopped with red button
        stepper.move(1);
        stepper.run();
       }
      while (digitalRead (ModeSelectPin) == true );
        stepper.stop();                                                 //Sets a new target position that causes the stepper to stop as quickly as possible, using the current speed and acceleration parameters. 
        stepper.setCurrentPosition(0);
        stepper.disableOutputs();                                       //control of the steppermotor is disabled to avoid unnecessary heating of the motor
          
      if (GoToOriginState == true)                                      // check if Go To Origin button has been pushed
         {ORIGIN (); GoToOriginState = false; }
      //if (StartPauseState == true)                                    // check if StartPause button has been pushed
      //   {STRTPSE (); StartPauseState = false; }                      // THIS DOES NOT WORK THE WAY IT IS MEANT; Pushing the Start/Pause button causes a reset and you enter the welcome menu; which is fine for the moment
       }

/////////////////Hereafter follows the Function for driving the Turntable to the Origin position  /////////////////////////////////////////////////////////////////////
 void ORIGIN ()
    {
        Serial.print("going to origin, GoToOriginPin = "); Serial.println((digitalRead (GoToOriginPin)) );
        display.clearDisplay();
        display.startWrite();
        display.setTextSize(2);
        display.setCursor(0,0);
        display.setTextColor(WHITE);                                    //display.setBackgroundcolor(WHITE);
        display.println("GOING TO");
        display.println("  ORIGIN");
        display.display();           
        do
           {
           stepper.setSpeed(40);
           stepper.move(1);                                             // rotating the Turntable until the OriginPin goes LOW
           stepper.run();
           }
        while ((digitalRead (OriginPin)) == HIGH );
        stepper.stop();                                                 //Sets a new target position that causes the stepper to stop as quickly as possible, using the current speed and acceleration parameters. 
        stepper.setCurrentPosition(0);
        delay (100);
        stepper.disableOutputs();                                       //control of the steppermotor is disabled to avoid unnecessary heating of the motor
        
        Serial.println("Origin Reached ");
        display.clearDisplay();
        display.startWrite();
        display.setTextSize(2);
        display.setCursor(0,20);
        display.setTextColor(WHITE);                                    //display.setBackgroundcolor(WHITE);
        display.println("ARRIVED");
        display.println("AT ORIGIN");
        display.display();
        delay (1000);

        while (digitalRead (ModeSelectPin) == true)
        {
        Serial.println("Push RED Button to proceed");
        display.clearDisplay();
        display.startWrite();
        display.setTextSize(2);
        display.setCursor(0,0);
        display.setTextColor(WHITE);                               //display.setBackgroundcolor(WHITE);
        display.println("TO START");
        display.println("TURNING");
        display.setCursor(0,45);
        display.setTextColor(BLACK, WHITE);                        // Draw 'inverse' text
        display.println("RED BUTTON");
        display.display();
        }
    }

/////////////////Hereafter follows the Function for pauzing/restarting Turntable selecting a new mode and to put it back in the Origin position  /////////////////////////
/////////////////THIS DOES NOT WORK THE WAY IT IS MEANT; Pushing the Start/Pause button causes a reset and you enter the welcome menu; which is fine for the moment
 void STRTPSE () 
    { 
        Serial.print("Start/pause Pin = "); Serial.println((digitalRead (StartPausePin)) );
        //display.clearDisplay();
        //display.startWrite();
        //display.setTextSize(2);
        //display.setCursor(0,0);
        //display.setTextColor(WHITE);                                    //display.setBackgroundcolor(WHITE);
        //display.println("START ");
        //display.println(" / PAUSE");
        //display.display();
        //delay (500);         
     //ORIGIN ();
     SETMODE ();
     delay (1000);
    }

BLE Client Camera.ino

Arduino
ARDUINO Sketch for the Camera Client for a SONY HX 400V camera, running on an ESP32
/*********
  This project has been developed and produced by Pierre Pennings (September/October 2019),
  It applies parts of the code (related to BLE client/server) published by Rui Santos https://randomnerdtutorials.com/courses : Learn ESP32 with Arduino IDE
  His book has been a great help for me to realise this project.

  This Project is about making a (3D printed) Turntable rotate in a selectable number of steps per 360 degrees using a Stepper Motor.
  The turntable's housing contains a ESP 32 (NodeMCU) that is programmed as a Bluetooth Low Energy (BLE) server.
  After every step of x degrees, the turntable stops and sends a command over the Bluetooth
  connection to the ESP32, that is set up as BLE Client. (for which this program has been written.
  The BLE Client is interfaced with a Sony HX400V Camera through a special Multiconnector (looks like a micro USB)
  to activate the focus and the camera shutter and then move another step of x degrees.
  At the same time a LED spotlight will be activated. The spotlight is controlled by this program.
  
  The ESP 32 device works at 3.3 Volt levels.
  The ESP module is fed with 5 V derived from a step-up converter that gets its pimary power from the 3.3v output of the Sony HX400V Camera. 
  As such the Camera client can be completely housed in a small 3D printed box, without the need of en external power supply nor batteries.
  
  The ESP 32 that has an on-board 3.3V voltage regulator, that uses the 5V from the step up convertor.
  Actually we are converting from 3.3V o 5V and back to 3.3V (just because the ESP32 does not accept 3.3V as an input).
  Four different LEDs are used to indicate the following:
      * the RED LED to indicate the availability of the the 3.3 V input from the Camera
      * the BLUE LED to indicate the status of the BLUETOOTH connection.
      * the YELLOW LED to indicate that the FOCUS command to the camera is active
      * the GREEN LED to indicate that the SHOOT command is given to the camera.
      
  This code is licensed under GPL3+ license.
  
*********/
#include "BLEDevice.h"

//////////////////////constants that won't change://////////////////////////////////////
const int YellowLEDPin = 15;                // YellowLEDPin refers GPIO 15 of ESP32 (for focussing of the camera)
const int BlueLEDPin = 16;                  // BlueLEDPin refers GPIO 16 of ESP32
const int GreenLEDPin = 17;                 // GreenLEDPin refers GPIO 17 of ESP32 (for taking a shot with the camera)
const int FlashLEDPin = 4;                  // FlashLEDPin refers GPIO 04 of ESP32

////////////////////////// Variables:///////////////////////////////////////////////////
String command[10];
String Rx = String ('0');

///////////////////////BLE settings ////////////////////////////////////////////////////
#define bleServerName "TurnTableESP32"                                                //the name of the BLE Server, that we are connecting to

static BLEUUID ControlServiceUUID("e6c24700-6f9c-4bf4-b078-4fc82fad3e28");            //The UUID of the service that we want to read
static BLEUUID CONTROLCharacteristicUUID("1e0ed88a-1b69-4197-83fa-0373670c4819");     //The UUID of the Characteristic that we want to read

static boolean doConnect = false;                                                     //Flag indicating to begin connecting
static boolean connected = false;                                                     //Flag indicating if the connection is made

static BLEAddress *pServerAddress;                                                    //Address of the peripheral device; to be found during scanning.
static BLERemoteCharacteristic* CONTROLCharacteristic;                                //the Characteristic that we want to receive

const uint8_t notificationOn[] = {0x1, 0x0};                                          //Activate notify
const uint8_t notificationOff[] = {0x0, 0x0};

//////////////////////////////////////////connect to Server ////////////////////////////
bool connectToServer(BLEAddress pAddress)                                             //Connect to the BLE Server that has the name, Service, and Characteristics
  {
    BLEClient* pClient = BLEDevice::createClient();
    pClient->connect(pAddress);                                                        // Connect to the remote BLE Server.
    Serial.println(" - Connected to server");
 
    BLERemoteService* pRemoteService = pClient->getService(ControlServiceUUID);        // Obtain a reference to the service we are after in the remote BLE server.
    if (pRemoteService == nullptr)
    {
    Serial.print("Failed to find our service UUID: ");
    Serial.println(ControlServiceUUID.toString().c_str());
    return (false);
    }

    CONTROLCharacteristic = pRemoteService->getCharacteristic(CONTROLCharacteristicUUID);   // Obtain a reference to the characteristic in the service of the remote BLE server.
    if (CONTROLCharacteristic == nullptr)
    {
    Serial.print("Failed to find our characteristic UUID");
    return false;
    }
    Serial.println(" - Found our characteristics");
    CONTROLCharacteristic->registerForNotify(CONTROLNotifyCallback);                //Assign callback functions for the Characteristics
  }

//////////////////////////////////////////call back function /////////////////////////
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks              //Callback function that gets called
                                                                                    //when another device's advertisement has been received
  {
  void onResult(BLEAdvertisedDevice advertisedDevice)
    {
    if (advertisedDevice.getName() == bleServerName)                                //Check if the name of the advertiser matches with the server name
      { 
      advertisedDevice.getScan()->stop();                                           //Scan can be stopped, we found what we are looking for
      pServerAddress = new BLEAddress(advertisedDevice.getAddress());               //Address of advertiser is the one we need
      doConnect = true;                                                             //Set indicator, stating that we are ready to connect
      Serial.println("Device found. Connecting!");
      connected = true;
      }
    }
  };

//////////////////////////////////////////Reading new data ///////////////////////////
static void CONTROLNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) 
    {                                                                               //When the BLE Server sends a new CONTROL reading with the notify property
        Rx = String(*pData);
        Serial.print("  Command Received: "); Serial.print(Rx); 

      if (Rx == String(77))                                                         //if the first character of the received pData is 77 HEX (being a B in ASCII), the command is "ManualShot"
        {
        digitalWrite(FlashLEDPin, HIGH);                                            //activates the FlashLight connected to the server
        delay (100);                                                                //short time to enable the Flash LED to achieve its full illuminance level
        digitalWrite(YellowLEDPin, HIGH);                                           //put Yellow LED to on; activates the Focus of the Camera for 0,9 seconds
        delay (900);
        digitalWrite(YellowLEDPin, LOW);                                            //put Yellow LED to Off
        Serial.println(" ManualShot");
        digitalWrite(GreenLEDPin, HIGH);                                            //put Green LED to On; activates the shutter of the Camera for 0,2 seconds
        delay (200);
        digitalWrite(GreenLEDPin, LOW);                                             //put Green LED to Off
        Rx = String(0);
        }
      if (Rx == String(65))                                                          //if the first character of the received pData is 65 HEX (being a A in ASCII), the the command is "AutoShot"
        {
        digitalWrite(FlashLEDPin, HIGH);                                             //activates the FlashLight connected to the server
        delay (100);                                                                 //short time to enable the Flash LED to achieve its full illuminance level
        digitalWrite(YellowLEDPin, HIGH);                                            //put Yellow LED to on; activates the Focus of the Camera for 0,9 seconds
        delay (900);
        digitalWrite(YellowLEDPin, LOW);                                            //put Yellow LED to Off
        Serial.println(" Auto Shot");
        digitalWrite(GreenLEDPin, HIGH);                                            //put Green LED to On; activates the shutter of the Camera for 0,2 seconds
        delay (200);
        digitalWrite(GreenLEDPin, LOW);                                             //put Green LED to Off
        Rx = String(0);
        }    
        delay(600); 
        digitalWrite(FlashLEDPin, LOW);                                             //de-activates the FlashLight connected to the server
   }
//////////////////////////////the setup code that follows, will run once after "Power On" or after a RESET
void setup()  {
  Serial.begin(115200);                                                             //Start serial communication
  Serial.println("Starting BLE Client application...");

  pinMode(GreenLEDPin, OUTPUT);                                                     // initialize digital pin GreenLEDPin as an output.
  pinMode(YellowLEDPin, OUTPUT);                                                    // initialize digital pin YellowLEDPin as an output.
  pinMode(BlueLEDPin, OUTPUT);                                                      // initialize digital pin BlueLEDPin as an output.
  pinMode(FlashLEDPin, OUTPUT);                                                     // initialize digital pin FlashLEDPin as an output.

  digitalWrite(FlashLEDPin, LOW);                                                   // at start turn the FlashLEDPin off (LOW means Flash Light OFF);
  
  BLEDevice::init("");                                                              //Init BLE device
                                                                                    // Retrieve a Scanner and set the callback we want to use to be informed when we
                                                                                    // have detected a new device.  Specify that we want active scanning and start the
                                                                                    // scan to run for 30 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  digitalWrite(BlueLEDPin, HIGH);                                                   // at start of scan process: turn the blue LED on;
  pBLEScan->start(10);
     if (connected == false) {                                                      // blue LED will start flashing if no scan succes after 9 seconds
       for (int s = 1; s <10 ; s++) 
        {
        digitalWrite(BlueLEDPin, HIGH);                                             // turn the blue LED on
        delay(50);                                                                  // wait 50 miliseconds
        digitalWrite(BlueLEDPin, LOW);                                              // turn the LED off by making the voltage LOW
        delay(500);                                                                 // wait 500 miliseconds
        Serial.print
          ("NOT connected to the BLE Server. Device will reboot after: ");
          Serial.print (10-s); Serial.println ("seconds");                          // device will automatically reset to try again scan for nearby BLE server again. 
        }
     } 
  }
  

//////////////////////////////the loop code that follows, will run repeatedly until "Power On" or a RESET
void loop() {
                                                                                    // If the flag "doConnect" is true then we have scanned for and found the desired
                                                                                    // BLE Server with which we wish to connect.  Now we connect to it.  Once we are
                                                                                    // connected we set the connected flag to be true.
  if (doConnect == true)
  {
    if (connectToServer(*pServerAddress))
      {
        Serial.println("We are now connected to the BLE Server.");
        digitalWrite(BlueLEDPin, HIGH);                                             // turn the blue LED on 
        connected = true;
      }
    else
      {
        digitalWrite(BlueLEDPin, HIGH);                                             // turn the blue LED on
        delay(50);                                                                  // wait 50 miliseconds
        digitalWrite(BlueLEDPin, LOW);                                              // turn the LED off by making the voltage LOW
        delay(100);                                                                 // wait 100 miliseconds
        Serial.println("NOT connected to the BLE Server.");                         // Restart your device to scan for nearby BLE server again.
        connected = false;
      }
        doConnect = false;  
  }  
  
      CONTROLCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);      //Activate the Notify property of each Characteristic    
      delay(500);                                                                                                          // Delay half a second between loops. 
}

Credits

Pedro52

Pedro52

6 projects • 46 followers

Comments