In the previous tutorials, you’ve used Python with the Elecrow All-in-One Starter Kit for Arduino to respond to button events, read analogue inputs, measure distance with the ultrasonic sonar module and combine several hardware components to build a countdown timer.
This practical Python tutorial takes another step forward by combining sensor data, user input, mathematical calculations and an LCD display to create a practical photography application. Namely, a simple photography light meter using the All-in-One Starter Kit.
The light meter measures the amount of light falling on the sensor in lux (LUX). The slider selects a shutter speed, the button cycles through ISO sensitivity settings, and the Python code calculates an appropriate F-stop (aperture) value. The resulting exposure information is displayed on the kit’s 16×2 LCD. This project is particularly useful because it demonstrates how Python can be used to process real-world measurements and turn them into useful information.
Before You Begin
If you haven’t already prepared your hardware and Python environment, first follow the setup instructions in this GitHub repository. The Python example discussed in this tutorial (3-photography-metering.py) can be found at the same repository.
Don’t have an All-in-One Starter Kit? The Python Programming: Robotics Foundation Course provides supervised tuition together with remote access to the same All-in-One Starter kit, allowing you to learn challenging Robo-Tx API and Python programming concepts from anywhere.
Photography Light Meter Overview
A photography light meter measures the amount of light available for taking a photograph. When a photographer takes a photograph, three important settings are commonly considered:
- Aperture — represented by the F-stop
- Shutter speed — how long the camera’s shutter remains open
- ISO — the sensitivity of the camera sensor
These settings are closely related. This project uses two settings supplied by the user:
- the slider selects the shutter speed
- the button selects the ISO sensitivity
The light meter sensor supplies the amount of available light. The Python code then calculates an appropriate aperture and displays the resulting F-stop. The LCD then displays the calculated exposure information.
Importing the Required Modules
The program starts with the import of required modules. Most of these imports have appeared in earlier tutorials. The new module is:
import math
The math module provides mathematical functions, including sqrt(), which is used later to calculate the F-stop.
Selecting Shutter Speeds
The program defines a Python list containing common shutter speeds:
SHUTTER_SPEEDS = [
3, 4, 5, 6, 10, 13, 15, 20, 25, 30, 40, 50, 60, 80,
100, 125, 160, 200, 250, 320, 400, 500, 640, 800, 1400
]
In previous tutorials, the slider represented a continuous range of values. Here, the slider is being used as a selector. Moving the slider doesn’t produce every possible shutter speed. Instead, its position selects the nearest entry from the SHUTTER_SPEEDS list.
This is a useful programming technique whenever a physical control needs to select from a predefined set of choices.
The mapping of the slider position to shutter speed is performed by the Python function:
def map_to_shutter_speed(analog_value: float) -> float:
'''Maps analog value of sliding potentiometer to the nearest shutter speed.'''
max_index = len(SHUTTER_SPEEDS) - 1
index = int((max_index * analog_value) / 1023)
index = max(0, min(index, max_index))
return SHUTTER_SPEEDS[index]
This function is registered with the Robo-Tx API in the same way as other analogue converter functions in previous tutorials. The rest of the program can simply read:
shutter.Value
without needing to know how the slider position was converted to a shutter value.
Understanding the Mapping
The slider produces a raw value between 0 and 1023. The function first determines the largest valid list index:
max_index = len(SHUTTER_SPEEDS) - 1
Since Python lists start at index zero, this gives the index of the final shutter speed. The slider value is then converted into an appropriate list index:
index = int((max_index * analog_value) / 1023)
The function contains another interesting line:
index = max(0, min(index, max_index))
This ensures that the calculated index cannot fall outside the valid range. This is called clamping a value. Although the expected analogue range is 0–1023, defensive programming like this makes the function safer and more robust.
The result is then used to select a shutter speed from the list:
return SHUTTER_SPEEDS[index]
This mapping function provides a useful example of combining: lists, indexes, arithmetic, functions and analogue input to support a physical user interface.
Preparing the Light Meter
After the program obtains the light meter object representing the light meter sensor, the sensor is enabled:
light_meter = all_in_one_kit.LightMeter
light_meter.Enable()
However, enabling the sensor does not necessarily mean that it is immediately ready to provide a valid reading. The program therefore waits:
all_in_one_kit.WaitUntilSensorsReady(light_meter)
This is an important concept when working with real hardware. Some sensors require time to initialise, stabilise or perform internal measurements before reliable data becomes available. Rather than repeatedly trying to use a sensor that isn’t ready, the program explicitly waits for the sensor to become available.
Reading the Light Level
Once the light meter is ready, its current reading can be accessed through:
light_meter.LuxValue
The value represents the measured illumination in lux. The program uses this value directly in its exposure calculation. This is another example of the Robo-Tx API presenting hardware information in a form that is immediately useful to Python programs.
Selecting the ISO Setting
The initial ISO value is set to 100. The short button press then cycles through ISO settings.
if input_event == Input.BUTTON_1_RELEASED:
iso *= 2
if iso > 800:
iso = 100
The value therefore progresses through:
100 → 200 → 400 → 800 → 100 → ...
This is a particularly nice example of using a single physical button to implement a cyclic selection control. There is no need for separate buttons for increasing and decreasing the ISO. The selected ISO value is then displayed on the LCD on column 6 of row 0.
Calculating the F-Stop
The central calculation in the program is illustrated below:
f_stop = math.sqrt(
(light_meter.LuxValue * iso * (1 / shutter.Value))
/ calibration_const
)
This is where the project becomes more than a simple hardware demonstration. The Python program takes information from the light meter sensor, ISO and shutter speed, and combines them mathematically to calculate the F-stop (aperture) value.
The actual shutter speed is determined by the reciprocal of the shutter-speed value obtained from SHUTTER_SPEEDS, so for example a value of 50 will result in the shutter speed of 1/50 second.
The program also defines a calibration constant, which is used to scale the calculation so that the resulting F-stop is appropriate for the light meter application.
Not every combination of light level, ISO and shutter speed will produce a usable F-stop. Only values between F1.8 and F22 are considered suitable for display. If the calculated F-stop falls outside the supported range, the program displays Error instead.
The Completed Display
With the calculated F-stop, selected ISO and shutter speed values available, the first row of the LCD might therefore look something like:
F5.6 200 1/125
with the second row showing corresponding labels:
A S T
Moving the slider changes the shutter speed, pressing the button changes the ISO, and changing the light level falling on the light sensor changes the measured LUX value. Since the program runs in a loop, the calculated F-stop therefore continues to respond dynamically to all three inputs.
Programming Concepts Covered
This practical Python tutorial introduces several new Python concepts while reinforcing many of the skills from earlier tutorials:
- Lists – The shutter speeds are stored in SHUTTER_SPEEDS. Students can therefore see how a collection of related values can be represented using a Python list.
- List indexing – The calculated index selects an individual shutter speed from the list.
- Mathematical operations – integer conversion, minimum and maximum values, square roots
- Validation – The calculated F-stop is checked before being displayed.
- Sensor initialisation – The program explicitly enables the light sensor and waits for it to become ready before attempting to use it.
Challenge Exercises
Try extending the photography light meter program yourself to meet the following changes in requirements:
- Detect the button press event Input.BUTTON_1_SUSTAINED to ‘freeze’ the display on a long button press so it does not update until the next long button press event.
- Create and use a Python list of ISO values, and cycle through each list entry when the button is pressed.
- Modify the program such that the slider chooses from a selection of F-stop values and calculates and displays an optimum shutter speed.
Looking Ahead
The photography light meter is another example of what becomes possible when Python programming is connected to real hardware: a relatively small Python program can turn a collection of inexpensive electronic components into a useful, interactive instrument.
The next and final practical Python tutorial in this series will be a metronome application that allows the music student to use the Elecrow All-in-One Starter Kit for Arduino to select a time signature and beats-per-minute to produce regular controlled beeps.