Automatic Photogrammetry Turntable not working as expected

Good day fellow Home Assistant Users,

I am trying to set up a turntable for photogrammetry with the ESP32 and an external stepper driver. There is lots of switches for the cameras and lights ect and all is working as expected.

I want most programming done on the esp/esphome side.

I will explain as best as I can so here goes.
Basic Principle:

  1. Turn on switch in HassIO
  2. Delay - Wait for start delay (before turntable starts turning)
  3. Snap all photos (with shutter delays)
  4. Delay - for cameras to finish taking photos (all that is enabled at once)
  5. Turn the turntable a set number of steps or degrees and stop
  6. Snap all photos - same as 3
  7. Delay - same as 4
  8. Check if turntable has reached the final position (Final position in my case is 360 degrees or 47520 steps)
  9. If not: Repeat from point nr 5 above
    If Yes: Stop Turning

My Code is not perfect but does everything except the part where it
-checks if the next/final position has been reached and turn again.

Some (only one or two entries) of the code in here I may not be using anymore.

That is what I need help with and have been trying for a few weeks now but no luck.

substitutions:
  room: workshop
  upper_room: Workshop
  devicename: turntable_esp32
  upper_devicename: Turntable ESP32

##################################################
##################################################
######  ESPHome Config
##################################################
##################################################

esphome:
  name: $devicename
  platform: ESP32
  board: esp32doit-devkit-v1

wifi:
  use_address: 192.168.1.147
  reboot_timeout: 1min
  networks:
  - ssid: "Wifi1"
    password: "wifipassword1"
  - ssid: "Wifi2"
    password: "wifipassword2"
  - ssid: "Wifi3"
    password: "wifipassword3"
  power_save_mode: none
  ap:
    ssid: "ESP32 Turntable"
    password: "password"

captive_portal:

logger:

api:
  services:
    - service: control_stepper
      variables:
        target: int
      then:
        - stepper.set_target:
            id: turntable_stepper
            target: !lambda 'return target;'

ota:

##################################################
##################################################
######  Stepper Motor
##################################################
##################################################

stepper:
  - platform: a4988
    id: turntable_stepper
    step_pin:
      number: 4
      inverted: True
#      mode: INPUT_PULLUP
    dir_pin:
      number: 16
      inverted: True
#      mode: INPUT_PULLUP
    max_speed: 100000 steps/s
#    sleep_pin:
#      number: 17
#      inverted: True
#      mode: INPUT_PULLUP
    acceleration: 2000
    deceleration: 2000

##################################################
##################################################
#####  Switches
##################################################
##################################################

switch:

#####  ESPHome Switches
##################################################

  - platform: restart
    name: "Reboot ${upper_devicename}"
    id: turntable_esp32_restart

##################################################
#####  GPIO Switches
##################################################

##### Lights
  - platform: gpio
    name: Turntable Lights
    id: switch_turntable_lights
    pin:
      number: 25
      inverted: True
    
#####  Stepper Enable
  - platform: gpio
    name: "Turntable Enable Switch"
    id: turntable_enable_switch
    pin:
      number: 17
      inverted: True
      
##### Power Supply Relay
  - platform: gpio
    name: Stepper PSU Switch
    id: switch_stepper_psu
    pin:
      number: 15
      inverted: True
      
##### Camera 1 Shutter
  - platform: gpio
    id: camera_1_shutter_gpio_switch
    pin:
      number: 5
      inverted: True
    on_turn_on:
      then:
        - delay: !lambda return id(camera_1_shutter_delay).state;
        - switch.turn_off: camera_1_shutter_gpio_switch
  - platform: template
    name: Camera 1 Shutter Switch
    id: camera_1_shutter_template_switch
    # icon: mdi:
    turn_on_action:
      if:
        condition:
          binary_sensor.is_on: enable_camera_1
        then:
          - switch.turn_on: camera_1_shutter_gpio_switch

##### Camera 2 Shutter
  - platform: gpio
    id: camera_2_shutter_gpio_switch
    pin:
      number: 18
      inverted: True
    on_turn_on:
      then:
        - delay: !lambda return id(camera_2_shutter_delay).state;
        - switch.turn_off: camera_2_shutter_gpio_switch
  - platform: template
    name: Camera 2 Shutter Switch
    id: camera_2_shutter_template_switch
    # icon: mdi:
    turn_on_action:
      if:
        condition:
          binary_sensor.is_on: enable_camera_2
        then:
          - switch.turn_on: camera_2_shutter_gpio_switch

##### Camera 3 Shutter
  - platform: gpio
    id: camera_3_shutter_gpio_switch
    pin:
      number: 19
      inverted: True
    on_turn_on:
      then:
        - delay: !lambda return id(camera_3_shutter_delay).state;
        - switch.turn_off: camera_3_shutter_gpio_switch
  - platform: template
    name: Camera 3 Shutter Switch
    id: camera_3_shutter_template_switch
    # icon: mdi:
    turn_on_action:
      if:
        condition:
          binary_sensor.is_on: enable_camera_3
        then:
          - switch.turn_on: camera_3_shutter_gpio_switch

##### Camera 4 Shutter
  - platform: gpio
    id: camera_4_shutter_gpio_switch
    pin:
      number: 21
      inverted: True
    on_turn_on:
      then:
        - delay: !lambda return id(camera_4_shutter_delay).state;
        - switch.turn_off: camera_4_shutter_gpio_switch
  - platform: template
    name: Camera 4 Shutter Switch
    id: camera_4_shutter_template_switch
    # icon: mdi:
    turn_on_action:
      if:
        condition:
          binary_sensor.is_on: enable_camera_4
        then:
          - switch.turn_on: camera_4_shutter_gpio_switch

##### Camera 5 Shutter
  - platform: gpio
    id: camera_5_shutter_gpio_switch
    pin:
      number: 23
      inverted: True
    on_turn_on:
      then:
        - delay: !lambda return id(camera_5_shutter_delay).state;
        - switch.turn_off: camera_5_shutter_gpio_switch
  - platform: template
    name: Camera 5 Shutter Switch
    id: camera_5_shutter_template_switch
    # icon: mdi:
    turn_on_action:
      if:
        condition:
          binary_sensor.is_on: enable_camera_5
        then:
          - switch.turn_on: camera_5_shutter_gpio_switch

##### Camera 5 Focus
  - platform: gpio
    id: camera_5_focus_gpio_switch
    pin:
      number: 22
      inverted: True
    on_turn_on:
      then:
        - delay: !lambda return id(camera_5_shutter_delay).state;
        - switch.turn_off: camera_5_focus_gpio_switch
  - platform: template
    name: Camera 5 Focus Switch
    id: camera_5_focus_template_switch
    # icon: mdi:
    turn_on_action:
      if:
        condition:
          binary_sensor.is_on: enable_camera_5
        then:
          - switch.turn_on: camera_5_focus_gpio_switch

##################################################
#####  Template Switches
##################################################

##### Stop Turntable Switch
  - platform: template
    name: "Stop Turntable Switch"
    id: stop_turntable_template_switch
    turn_on_action:
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0
            - switch.turn_off: switch_stepper_psu
            - switch.turn_off: turntable_enable_switch
                
##### Manual Turntable Control
  - platform: template
    name: "Manual Turntable Control"
    id: manual_turntable_control_template_switch
    turn_on_action:
            - switch.turn_on: switch_stepper_psu
            - switch.turn_on: turntable_enable_switch
            - delay: !lambda return id(start_delay_turntable).state * 1000;
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: !lambda return id(degrees_to_turn).state;
            - stepper.set_speed:
                id: turntable_stepper
                speed: !lambda return id(rpm_turntable).state;
    turn_off_action:
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0

##### Auto Turntable Control
  - platform: template
    name: "Automatic Turntable Photogrammetry"
    id: auto_turntable_photogrammetry_template_switch
    turn_on_action:
            - delay: !lambda return id(start_delay_turntable).state * 1000;
            - script.execute: auto_turntable_photogrammetry_script
    turn_off_action:
            - script.stop: auto_turntable_photogrammetry_script
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0

#####  Snap All Photos
  - platform: template
    name: "Snap All Photos"
    id: snap_all_photos_template_switch
    turn_on_action:
            - switch.turn_on: camera_1_shutter_template_switch
            - switch.turn_on: camera_2_shutter_template_switch
            - switch.turn_on: camera_3_shutter_template_switch
            - switch.turn_on: camera_4_shutter_template_switch
            - switch.turn_on: camera_5_shutter_template_switch


  - platform: template
    name: "Automatic 360 Turntable Photogrammetry"
    id: auto_360_turntable_photogrammetry_template_switch
    turn_on_action:
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0
            - stepper.set_speed:
                id: turntable_stepper
                speed: !lambda return id(rpm_turntable).state;
            - delay: !lambda return id(start_delay_turntable).state * 1000;
            - switch.turn_on: auto_360_turntable_photogrammetry_continue_template_switch
            - lambda: 'id(turntable_current_position) = 0;'
    turn_off_action:
            # - script.stop: auto_turntable_photogrammetry_script
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0
                
  - platform: template
    id: auto_360_turntable_photogrammetry_continue_template_switch
    turn_on_action:
            - switch.turn_on: snap_all_photos_template_switch
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0
            - delay: !lambda return id(take_photo_delay).state * 1000;
            - lambda: 'id(turntable_current_position) = id(turntable_stepper).current_position;'
            
    turn_off_action:
            - stepper.report_position:
                id: turntable_stepper
                position: 0
            - stepper.set_target:
                id: turntable_stepper
                target: 0
            
            
            
##################################################
##################################################
#####  Scripts
##################################################
##################################################
script:

##### Auto Turntable Scripts
  - id: auto_turntable_photogrammetry_script
    then:
      - stepper.report_position:
          id: turntable_stepper
          position: !lambda return id(degrees_to_turn).state;
      - stepper.set_target:
          id: turntable_stepper
          target: !lambda return id(degrees_to_turn).state;
          # target: !lambda return id(steps_to_turn_turntable).state * 132;
      - stepper.set_speed:
          id: turntable_stepper
          speed: !lambda return id(rpm_turntable).state;
      - lambda: 'id(turntable_current_position) = id(turntable_stepper).current_position;'
      # - wait_until:
          # lambda: 'return id(turntable_stepper).current_position == id(degrees_to_turn).state;'
      # - delay: !lambda return id(delay_turntable).state * 1000;
      - switch.turn_on: snap_all_photos_template_switch
      - delay: !lambda return id(take_photo_delay).state * 1000;
      - switch.turn_off: snap_all_photos_template_switch
      - switch.turn_on: auto_turntable_photogrammetry_template_switch
      
      
      
      
##################################################
##################################################
#####  Globals
##################################################
##################################################
globals:
##### ESP32 Sensors
##################################################
   - id: stepspersecond_to_rpm_global
     type: float
     restore_value: no
     initial_value: '0'
   - id: turntable_current_position
     type: float
     restore_value: no
     initial_value: '0'
   - id: turntable_next_target_position
     type: float
     restore_value: no
     initial_value: '0'
   - id: turntable_final_position
     type: float
     restore_value: no
     initial_value: '47500'



##################################################
##################################################
#####  Sensors
##################################################
##################################################
sensor:
##### ESP32 Sensors
##################################################

#####  Voltage
  # - platform: adc
    # pin: VCC
    # name: "Turntable Voltage ESP32"
    # update_interval: 30s

#####  Wifi Signal
  - platform: wifi_signal
    name: "Turntable WiFi Signal ESP32"
    update_interval: 30s

#####  Uptime
  - platform: uptime
    name: "Turntable Uptime ESP32"
    id: turntable_uptime_esp32
    update_interval: 30s    
    
#####  Hall Effect
  - platform: esp32_hall
    name: "Turntable Hall Effect Sensor"
    update_interval: 1s

##################################################
#####  HASSIO Input Numbers
##################################################

#####
  - platform: homeassistant
    name: "steps_to_turn_turntable"
    entity_id: input_number.steps_to_turn_box
    id: steps_to_turn_turntable
    
#####
  - platform: homeassistant
    name: "delay_turntable"
    entity_id: input_number.turntable_delay_box
    id: delay_turntable
    
#####
  - platform: homeassistant
    name: "start_delay_turntable"
    entity_id: input_number.turntable_start_delay_box
    id: start_delay_turntable

#####
  - platform: homeassistant
    name: "rpm_turntable"
    entity_id: sensor.turntable_rpm_sensor
    id: rpm_turntable
    
#####
  - platform: homeassistant
    name: "pulses_per_revolution_stepper"
    entity_id: input_number.pulses_per_revolution_stepper_box
    id: pulses_per_revolution_stepper

#####
  - platform: homeassistant
    name: "steps_per_second_stepper"
    entity_id: input_number.steps_per_second_stepper_box
    id: steps_per_second_stepper

#####
  - platform: homeassistant
    name: "take_photo_delay"
    entity_id: input_number.take_photo_delay_box
    id: take_photo_delay

#####
  - platform: homeassistant
    name: "degrees_to_turn"
    entity_id: sensor.turntable_degrees_to_turn
    id: degrees_to_turn

#####  Current Stepper Position
  - platform: template
    name: "Current Stepper Position"
    id: stepper_position
    lambda: return id(turntable_stepper).current_position;
    update_interval: 1s

#####  Current Stepper Position from global
  - platform: template
    name: "Current Stepper Position from global"
    id: stepper_position_from_global
    lambda: return id(turntable_current_position);
    update_interval: 1s

#####  Next Stepper Position from global
  - platform: template
    name: "Next Stepper Position from global"
    id: next_stepper_position_from_global
    lambda: return id(turntable_next_target_position);
    update_interval: 1s

#####  Camera 1 Shutter Delay
  - platform: homeassistant
    name: "Camera 1 Shutter Delay"
    entity_id: input_number.camera_1_shutter_delay_box
    id: camera_1_shutter_delay

#####  Camera 2 Shutter Delay
  - platform: homeassistant
    name: "Camera 2 Shutter Delay"
    entity_id: input_number.camera_2_shutter_delay_box
    id: camera_2_shutter_delay

#####  Camera 3 Shutter Delay
  - platform: homeassistant
    name: "Camera 3 Shutter Delay"
    entity_id: input_number.camera_3_shutter_delay_box
    id: camera_3_shutter_delay

#####  Camera 4 Shutter Delay
  - platform: homeassistant
    name: "Camera 4 Shutter Delay"
    entity_id: input_number.camera_4_shutter_delay_box
    id: camera_4_shutter_delay

#####  Camera 5 Shutter Delay
  - platform: homeassistant
    name: "Camera 5 Shutter Delay"
    entity_id: input_number.camera_5_shutter_delay_box
    id: camera_5_shutter_delay

##################################################
##################################################
#####  Binary Sensors
##################################################
##################################################
binary_sensor:

##################################################
#####  Stepper Sensor
##################################################

##### Stepper is moving / Has reached target
  # - platform: template
    # name: "Stepper reached next target"
    # id: stepper_reached_next_target
    # lambda: |-
      # if (id(turntable_current_position).state < id(turntable_next_target_position)) {
        # return true;
      # } else {
        # return false;
      # }
    
##### Stepper reached final target
  # - platform: template
    # name: "Stepper reached final target"
    # id: stepper_reached_final_target
    # lambda: |-
      # if (id(turntable_current_position).state < id(turntable_final_position)) {
        # return true;
      # } else {
        # return false;
      # }
    
##################################################
#####  HassIO Binary Sensors
##################################################

#####  Photogrammetry boolean
  - platform: homeassistant
    name: "Photogrammetry boolean HassIO"
    entity_id: input_boolean.photogrammetry_boolean

#####  Enable Caamera 1 boolean
  - platform: homeassistant
    name: "Enable Camera 1 boolean HassIO"
    entity_id: input_boolean.enable_camera_1_boolean
    id: enable_camera_1

#####  Enable Caamera 2 boolean
  - platform: homeassistant
    name: "Enable Camera 2 boolean HassIO"
    entity_id: input_boolean.enable_camera_2_boolean
    id: enable_camera_2

#####  Enable Caamera 3 boolean
  - platform: homeassistant
    name: "Enable Camera 3 boolean HassIO"
    entity_id: input_boolean.enable_camera_3_boolean
    id: enable_camera_3

#####  Enable Caamera 4 boolean
  - platform: homeassistant
    name: "Enable Camera 4 boolean HassIO"
    entity_id: input_boolean.enable_camera_4_boolean
    id: enable_camera_4

#####  Enable Caamera 5 boolean
  - platform: homeassistant
    name: "Enable Camera 5 boolean HassIO"
    entity_id: input_boolean.enable_camera_5_boolean
    id: enable_camera_5

##################################################
##################################################
#####  Text Sensors
##################################################
##################################################
text_sensor:
   
#####
  - platform: wifi_info
    ip_address:
      icon: "mdi:ip"
      name: Turntable ESP32 IP Address
    ssid:
      name: Turntable ESP32 SSID
      icon: "mdi:access-point-network"
    bssid:
      name: Turntable ESP32 BSSID
      icon: "mdi:access-point-network"
  - platform: version
    name: "ESP32 Turntable ESPHome Version"
    
#####
  - platform: template
    name: "Turntable Uptime (formatted)"
    lambda: |-
      uint32_t dur = id(turntable_uptime_esp32).state;
      int dys = 0;
      int hrs = 0;
      int mnts = 0;
      if (dur > 86399) {
        dys = trunc(dur / 86400);
        dur = dur - (dys * 86400);
      }
      if (dur > 3599) {
        hrs = trunc(dur / 3600);
        dur = dur - (hrs * 3600);
      }
      if (dur > 59) {
        mnts = trunc(dur / 60);
        dur = dur - (mnts * 60);
      }
      char buffer[17];
      sprintf(buffer, "%ud %02uh %02um %02us", dys, hrs, mnts, dur);
      return {buffer};
    icon: mdi:clock-start
    update_interval: 30s

The cameras is phones/DSLR cameras triggered by relays with self made boards with resistors connected to the 3.5mm earphone jacks for shutter.

My Home Assistant code is as follows:

sensor:

########## TURNTABLE ##########
  - platform: template
    sensors:
      turntable_pulses_per_revolution:
        value_template: "{{ '%.0f'%(states('input_number.pulses_per_revolution_stepper_box') | float * 4.75) | float }}"
        friendly_name: 'Turntable Pulses per Revolution'
        # unit_of_measurement: 'Pulse/rev'
      turntable_pulses_per_degree:
        value_template: "{{ '%.0f'%(states('sensor.turntable_pulses_per_revolution') | float / 360) | float }}"
        friendly_name: 'Turntable Pulses per Degree'
      turntable_degrees_to_turn:
        value_template: "{{ '%.0f'%((states.input_number.turntable_turn_degrees.state | float) * 
        (states.sensor.turntable_pulses_per_degree.state | float)) | float }}"
        friendly_name: 'Turntable Degrees to Turn'
      turntable_rpm_sensor:
        value_template: "{{ '%.0f'%((states.input_number.turntable_rpm.state | float) / 60 * 
        (states.sensor.turntable_pulses_per_revolution.state | float)) | float }}"
        friendly_name: 'Turntable RPM Sensor'


###############################################################################

########## INPUT BOOLEANS ##########
input_boolean:
  
  photogrammetry_boolean:
    name: Snap All Photos Boolean
    initial: off

  enable_camera_1_boolean:
    name: Enable Camera 1 Boolean
    initial: off
    icon: mdi:camera

  enable_camera_2_boolean:
    name: Enable Camera 2 Boolean
    initial: off
    icon: mdi:camera

  enable_camera_3_boolean:
    name: Enable Camera 3 Boolean
    initial: off
    icon: mdi:camera

  enable_camera_4_boolean:
    name: Enable Camera 4 Boolean
    initial: off
    icon: mdi:camera

  enable_camera_5_boolean:
    name: Enable Camera 5 Boolean
    initial: off
    icon: mdi:camera

    
###############################################################################

#################### INPUT NUMBERS ####################
input_number:

########## TURNTABLE STEPPER INPUT NUMBERS ##########

#  turntable_stepper_control_slider:
#    name: "Turntable Stepper Control Slider"
#    initial: 0
#    min: -15224
#    max: 15224
#    step: 1
#    mode: slider

  steps_to_turn_box:
    name: "Turntable Steps to Turn Box"
    initial: 0
    min: -9999999
    max: 9999999
    step: 1
    mode: box

  turntable_delay_box:
    name: "Turntable Delay Box"
    initial: 0
    min: 0
    max: 9999999
    step: 1
    mode: box

  turntable_start_delay_box:
    name: "Turntable Start Delay Box"
    initial: 0
    min: 0
    max: 9999999
    step: 1
    mode: box
    
  turntable_rpm:
    name: "Turntable RPM"
    initial: 0
    min: 0
    max: 5000
    step: 1
    mode: box

  pulses_per_revolution_stepper_box:
    name: "Stepper Driver Pulses per Revolution Box"
    initial: 10000
    min: 400
    max: 50000
    step: 1
    mode: box

  turntable_turn_degrees:
    name: "Turtable turn degrees Box"
    initial: 10
    min: -720
    max: 720
    step: 1
    mode: box

  turntable_nr_of_photos_per_revolution:
    name: "Turtable number of photos per revolution Box"
    initial: 0
    min: 0
    max: 360
    step: 1
    mode: box

  steps_per_second_stepper_box:
    name: "Turntable Steps per Second Box"
    initial: 0
    min: 0
    max: 30000
    step: 1
    mode: box
    
  kinect_scan_nr_of_turns_box:
    name: "Turntable Number of Turns Box"
    initial: 0
    min: 0
    max: 100
    step: 1
    mode: box
    
  take_photo_delay_box:
    name: "Turntable Take Photo Delay"
    initial: 0
    min: 0
    max: 9999999
    step: 1
    mode: box

  send_photos_every_box:
    name: "Send Photos every amount of minutes"
    initial: 60
    min: 0
    max: 9999
    step: 1
    mode: box

  camera_1_shutter_delay_box:
    name: "Camera 1 Shutter Delay"
    initial: 50
    min: 0
    max: 9999999
    step: 1
    mode: box

  camera_2_shutter_delay_box:
    name: "Camera 2 Shutter Delay"
    initial: 50
    min: 0
    max: 9999999
    step: 1
    mode: box

  camera_3_shutter_delay_box:
    name: "Camera 3 Shutter Delay"
    initial: 50
    min: 0
    max: 9999999
    step: 1
    mode: box

  camera_4_shutter_delay_box:
    name: "Camera 4 Shutter Delay"
    initial: 50
    min: 0
    max: 9999999
    step: 1
    mode: box

  camera_5_shutter_delay_box:
    name: "Camera 5 Shutter Delay"
    initial: 50
    min: 0
    max: 9999999
    step: 1
    mode: box

Technical Details:
HassOS 2.12 on Virtual Machine
HomeAssistant 0.101.2
ESP32 DevKit V1
Stepper Driver: Wantai DQ860MA Microstepping Driver
8ch Relay board with Octocouplers
220V Led Lights for photogrammetry (1 relay switches on all lights)


1 Like