Last Updated or created 2022-06-29
I got my DIY timelapse slider out of storage, and notished it wasn’t working any more.
I’t was a quick and dirty build, using minimal components and could be build with minimal effort.
We could not take a lot of stuff with us to New Zealand.
Camera and powerbanks, those we always take with us. So i only needed:
- Raspberry Pi
- Steppermotor and a plastic sheet where it was mounted on (using tiewraps you can undo)
- Timingbeld
- Two metal feet it was mounted on
It had to be build strong enough to hold a Nikon 750, and didn’t get out of balance when moving the camera on two metal tubes i bought in NZ.
The RPI would not start anymore, just a red power smd led. SO it didn’t boot.
Taking the mini sdcard out of the raspberry trying to put it in my cardreader .. note the trying part.
The damn thing broke into two parts, never seen anything like it.
Damn, did i backup the latest version? No, i used my mobile and wifi in NZ to modify the scripts.
Well .. “We can rebuild him, we have the technology”
How does it work?
Stepper motors move my camera over two metal rods, with ball bearing wheels.
The raspberry controls my nikon using a usb cable. Mounted on the raspberry is a steppermotor hat (adafruit) which can control DC motors and stepper motors. ( In this project i used only one stepper )
The stepper motor carries the platform containing itself, a raspberry and my nikon over the “rails”
Two switches on each side sends a signal to the program to stop.
All timing are set via the Webgui.
Steps
- At reboot, python script wil be started
- Moving platform to the left, until switch detects the edge
- Waiting for in structions
- Entering for example timer 30, speed 10 and r
- Platform wil move distance 10 to the right
- Wait 30 seconds
- Grab a picture
- And loops until end of rod reached, then it wil move to left again.
Notes:
- Gphoto works with other camera’s also
- When placing the camera on the platform, focus once. Disable autofocus, also put your camera in manual mode, setting Apeture, ISO and shutterspeed same as your test photo. (bear in mind: when doing sundown shots maybe start with a little light over compensation)
Below old 2018 version
New Sdcard. Format, put lite on this
# install gphoto2
apt-get install photo2
# connect nikon with usb, capture test with
gphoto2 --capture-image-and-download --interval 5
# Next steppers
apt-get install python3-pip
pip3 install adafruit-circuitpython-motorkit
# enable I2C
raspi-config -> enable i2c
reboot
# Test python script
import time
import board
from adafruit_motorkit import MotorKit
kit = MotorKit(i2c=board.I2C())
for i in range(100):
kit.stepper1.onestep()
time.sleep(0.01)
# Create a API
apt-get install python3-flask python3-flaskext.wtf
I’m using my phone in Hotspot mode, Timelapser will connect to my phone.
Open a browser and enter : http://<ip of timelapser>:8080/form
speed is the movement on the rail
go = r(ight) or l(eft)
go + timer 0, move until you reach the end (switch detect)
Todo: Need to change CSS to mobile responsive gui .. like my quizzer
import time import subprocess from flask import Flask, jsonify from multiprocessing import Process, Value from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField from wtforms.validators import DataRequired from flask import Flask, render_template, request from flask import render_template import board from adafruit_motor import stepper from adafruit_motorkit import MotorKit import RPi.GPIO as GPIO import os; myenv = os.environ.copy(); myenv["LANG"] = "C" # NOTE: # timer = seconds between shots # speed = distance stepper travel # Using gpio pins to detect max left/right with switches # BCM Numbering GPIO.setmode(GPIO.BCM) # pullup to 17 & 18 GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Stepper HAT is i2c kit = MotorKit(i2c=board.I2C()) kit.stepper1.release() global timer global speed timer=0 speed=0 go="nix" app = Flask(__name__) app.config['SECRET_KEY'] = 'you-will-never-guess' class FormForm(FlaskForm): timer = StringField('timer', validators=[DataRequired()]) speed = StringField('speed', validators=[DataRequired()]) go = StringField('go', validators=[DataRequired()]) submit = SubmitField('Send control') # Make below in something like : nikon record .. slowly 10s to the right and recording stop? # Or bounch left/right using gpio sensors @app.route("/control/<time>/<speed>") def action(number, message): time.sleep(1) # Print form on: http://<IP>:8080/form = start page @app.route("/form") def form(): form = FormForm() return render_template('web.html', title='Web slide control', form=form) # process form @app.route('/data', methods = ['POST', 'GET']) def data(): if request.method == 'GET': return "The URL /data is accessed directly. Try going to '/form' to submit form" if request.method == 'POST': timer = request.form['timer'] speed = request.form['speed'] go = request.form['go'] timer = int(timer) speed = int(speed) if timer == 0: print("Turn off") p = Process(target=record_loop, args=(False,speed,timer,go)) p.start() if str(go) == "l": while GPIO.input(17) == True: kit.stepper1.onestep(direction=stepper.FORWARD) time.sleep(0.01) if str(go) == "r": while GPIO.input(18) == True: kit.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE) time.sleep(0.01) else: print("Turn on") p = Process(target=record_loop, args=(True,speed,timer,go)) p.start() # print form again form = FormForm() return render_template('web.html', title='Web slide control', form=form) # main loop, controls stepper and camera def record_loop(loop_on,myspeed,mytimer,mygo): while True: if loop_on == True: # test if switch hit yet, else move print('timer' + str(mytimer)) print('speed' + str(myspeed)) time.sleep(2) if str(mygo) == "l": if GPIO.input(17): print("Pin 17 is HIGH") for i in range(myspeed): kit.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE) time.sleep(0.01) kit.stepper1.release() else: print("Pin 17 is LOW") if str(mygo) == "r": if GPIO.input(18): print("Pin 18 is HIGH") for i in range(myspeed): kit.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE) time.sleep(0.01) kit.stepper1.release() else: print("Pin 18 is LOW") time.sleep(mytimer) subprocess.run(['/root/mycapture']) subprocess.Popen([ "gphoto2", "--capture-image"],stdout=subprocess.PIPE) # Main loop if __name__ == "__main__": while GPIO.input(17) == True: kit.stepper1.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE) time.sleep(0.01) kit.stepper1.release() p = Process(target=record_loop, args=(False,0,0,go)) p.start() app.run(host='0.0.0.0', port=8080, debug=False) p.join()
Other files
cat templates/web.html
{% block content %}
<h1>Slide control</h1>
<form action="/data" method = "POST">
{{ form.hidden_tag() }}
<p>
{{ form.timer.label }}<br>
{{ form.timer(size=32) }}
</p>
<p>
{{ form.speed.label }}<br>
{{ form.speed(size=32) }}
</p>
<p>
{{ form.speed.go }}<br>
{{ form.go(size=32) }}
</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
gphoto running from cron/python is a b*tch, had to rewrite subprocess and running from screen
Start screen @reboot, just crontab -e
# crontab entry
@reboot screen -dmS slide /usr/bin/python3 /root/control.py