This repository demonstrates how to control light sources with Arduino and Python, and output a trigger signal to synchronize a camera.
The codes rely on Arduino and pyserial.
- Install RomiSerial and the Arduino software
- The light sources are already set-up. Refer to the example gallery for ideas.
- The light sources can be controlled by a trigger, or pulse-width modulated signal (PWM)
- The code was tested on Windows and Linux
Here are the different hardware equipment the
Component | Quantity | Price per unit | Example |
---|---|---|---|
Arduino Uno | 1 | 24€ | Robotshop |
Light source controller | tested up to 5 | X | Thorlabs |
Software | Version we used | Download |
---|---|---|
Arduino | 1.8.13 | download |
Python | 3 | install |
CSL-serial | 1.0 | install |
CSLlight can be used the following way:
from CSLlight import ControlLight
arduino_port = "COM5"
sec = 1000 #conversion ms to s
blue_param = {'pin': 11,
'offset': 0.5*sec, #ms
'period': 5*sec, #ms
'duration': 2*sec, #ms
'analog_value': 255
}
arduino_light = ControlLight(arduino_port)
arduino_light.add_digital_pulse(blue_param)
arduino_light.start_measurement(300*sec)
arduino_light.wait()
The lights are controlled with periodic digital pulses. Each light has its own configuration, as in the blue_param
variable in the example above. The following parameters are expected:
pin
: The Arduino pin to which the LED light is connected.period
: The period of the output signal (an integer value in milliseconds).duration
: The amount of time the signal is 'on' during a period. This is an integer in milliseconds and should be less than the period.offset
: The number of milliseconds that the signal should be delayed (milliseconds).analog_value
: When the light is 'on', it is possible to generate a PWM signal. The underlying implementation uses Arduino's analogWrite, and the value should be between 0 and 255.
Once the lights are configured, use start_measurement
to begin the experiment. This function takes one optionnal argument, the duration of the experiment in milliseconds. The methid light.wait
will block the Python script until the experiment is finished.
Download or clone the repository:
git clone https://github.com/Alienor134/CSL-forge
-
Get the wiring to connect the Arduino to the light source controller. To begin, connect the wire to pin 11.
-
Open the LEDControl/LEDControl.ino file.
-
Select the Arduino board type in the "Tools/card type"
- Press the check sign. If an error related to "RomiSerial" appears, verify that you have properly followed the instructions in the CSL-Serial repository.
-
If no error appears you can click the arrow to load the code in the Arduino.
-
To test that you can properly interact with the Arduino, click on the magnifying glass in the upper right to open the serial monitor. Select 115200 baud and Both NL & CR and type: "#?:xxxx" and ensure you get this output:
- Test the control command: type: #d[11,0,0,1,0,2,0,255]:xxxx. It is a command to generate on and off output on pin 11. The pin stays on for 1 seconds with a period of 2 seconds, at intensity 255. It is later on embeded in a Pyton code for clarity. You should see a character sequence appear. Then type #b[100,0]:xxxx to start the experiment. You should see the LEDs blink (frequency 0.5Hz). To stop the blinking, type #e:xxxx
cd CSL-light
python setup.py develop
- Try running the code:
On Windows: python CSLlight/CSLlight.py --port COMx
by replacing "COMx" by the correct COM port identified in step 1.
On Linux: python3 CSLlight/CSLlight.py --port /dev/ttyACM0
You should see the LED blink.
- Open the python code to see how it works. Open the python code CSLlight.py. The code is commented and allows to control the frequency and amplitude of the LEDs. Set the parameters:
The content of interest is after
if __name__ == __main__:
- replace the COM port with the one of your set-up (tutorial).
- input the correct ports for the LED control. The port 3 and 11 are good choices because they are PWM pins which allow to control the intensity level of the LEDs rather than only ON-OFF.
- you can change the other parameters that correspond to this scheme:
(Note: to build an LED controller refer to this OpenUC2 repository, otherwise you might already use one of these Thorlabs controlers
The constructor.
ControlLight(self, arduino_port)
arduino_port
: The name of the serial device. Example "COM5" (Windows) or "/dev/ttyACM0" (Linux).
Creates a periodic digital pulse.
add_digital_pulse(self, params)
:
params
: A dictionnary with the following entries:pin
: The Arduino output pin.offset
: The delay, in milliseconds, before the pulse short start.period
: The period of the pulse, in milliseconds.duration
: The duration of the pulse in milliseconds (0 <= duration <= period)analog_value
: The implementation uses Arduino's analogWrite. This means that the pulse can actually be a pulse-width modulated signal. (0 <= analog_value <= 255)
If analog_value
is zero, no pulse will be generated. If it is 255, a square wave will be gerated with the given duration
. For a value between zero and 255, a PWM is signal is generated with a duty cycle of analog_value/255
.
Using a PWM is usefull to control the light intensity of the LEDs. The following example will generate the signal shown in the figure below, with a duty-cycle of ~75% (=192/255).
from CSLlight import ControlLight
arduino_port = "COM5"
sec = 1000
blue_param = {'pin': 6,
'offset': 0,
'period': 0.1*sec,
'duration': 0.05*sec,
'analog_value': 192
}
arduino_light = ControlLight(arduino_port)
arduino_light.add_digital_pulse(blue_param)
arduino_light.start_measurement(60*sec)
arduino_light.wait()
Make a pulse secondary to another pulse.
set_secondary(self, primary, secondary)
:
primary
,secondary
: The same descriptions of the pin configuration as inadd_digital_pulse
. Only the keypin
is actually needed to identify the two pulses.
When a pulse is defined as secondary to another pulse, it is turned off when the primaty pulse is on. This is useful, for example, when an activation light should be turned off when the mesurement light is turned on.
from CSLlight import ControlLight
#arduino_port = "COM5"
arduino_port = "/dev/ttyACM0"
ms = 1
sec = 1000
blue_param = {}
purple_param = {}
purple_param["pin"] = 11
purple_param["offset"] = 0
purple_param["duration"] = 10*ms
purple_param["period"] = 50*ms
purple_param["analog_value"] = 255
blue_param["pin"] = 6
blue_param["offset"] = 0
blue_param["duration"] = 0.5*sec
blue_param["period"] = 1*sec
blue_param["analog_value"] = 255
arduino_light = ControlLight(arduino_port)
arduino_light.arduino.set_debug(True)
arduino_light.add_digital_pulse(blue_param)
arduino_light.add_digital_pulse(purple_param)
arduino_light.set_secondary(purple_param, blue_param)
arduino_light.start_measurement(20*sec)
arduino_light.wait()
The following two figures show the difference between the two output signals, taken from test3.py and test4.py
Here is the output when both lights are primary:
This is the output when the bottom signal is set as secondary to the top signal:
Start the experiment.
start_measurement(self, duration=0)
:
duration
: (Optional): The duration of the experiment in milliseconds. If duration is negative or equal to zero, the experiment will run forever. The default value is zero.
Stop the experiment.
Block the execution of the current thread until the experiment is over.
Remove all pulses and starts with a clear set-up. See test5.py for an example.
This project is licensed under the GNU General Public License v3.0