Micropython, Python and Textual User Interface (TUI) based control framework for the Edukit Rotary Inverted Pendulum Control System developed by ST Microsystems and UCLA. The micropython code is written for the STMicrosystem Nucleo-F401RE the STMicrosystem X-Nucleo IHM01A1 stepper motor board based on the L6474 stepper motor driver, that comes with the STEVAL-EDUKIT, but can be adapted for other hardware as well.
-
Clone the repository by the following command in the terminal (e.g. Windows:
Win-r
then entercmd
orWin-x
and select Terminal; Ubuntu:Ctl-Alt-t
):git clone https://github.com/prfraanje/edukit-micropython
or download the zip-file from the green
<> Code
button on the github repository. Make sure you have a terminal and go to the folderedukit-micropython
with (cd
stands for change directory, directory is the 'old' word for folder):cd edukit-micropython
The advantage of
git clone
would be that, after agit clone
you always can pull the latest version of the code with just:git pull
in the folder
edukit-micropython
. -
If you have not installed Python on your PC install it, and make sure you have the commands
python
andpip
available at the command line (cmd or powershell in Windows, bash or zsh in Linux or Mac). For Windows you may consult this guide, and if you use the python distribution from (https://python.org) make sure you select the option to add the location ofpython.exe
to yourPATH
. Note, you may also need to add the%LOCALAPPDATA%\Roaming\Python\Python312\Scripts\
(or similar!) directory to your path, so you are able to runrshell
from the command line (if you have difficulty determining the directory do a search onrshell.exe
in the File Explorer). For help on adding directories to thePATH
environment variable, see e.g. StackOverflow on how to add a folder to path environment variable in windows. -
Install the dependencies by the following command in the terminal (in the following we leave out "in the terminal", because the terminal will be used all over again, also make sure you are in the folder
edukit-micropython
):python -m pip install -r requirements.txt
this installs the python modules that are necessary on the PC side.
-
On Windows it may be needed to install the STSW-LINK009 ST-LINK, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 USB driver signed for Windows7, Windows8, Windows10 from ST Microsystems.
-
On the microcontroller Micropython (we used v1.24), see Micropython for NUCLEO_F401RE, should be flashed (this can be done easily by copying the
hex
-file to the usb-drive that appears when connecting the microcontroller with the PC, alternatives are using the python IDE Thonny, compiling micropython from source, etc.). -
Copy the files
uL6474.py uencoder.py ucontrol.py urepl.py mpy_edukit.py
or preferably their compiled (
mpy
) versions (see below)uL6474.mpy uencoder.mpy ucontrol.mpy urepl.mpy mpy_edukit.mpy
to the
/flash
folder on the microcontroller. There are several tools to do this:mpremote
,rshell
, etc. Under Windows I was not able to run these tools succesfully, and one better uses Thonny, in which one can copy files from and to the microcontroller. Under Linux (or WSL), one simply doesmake deploy
-
Make sure the files
boot.py
andmain.py
are removed from the microcontroller, on Linux:make erase_default
-
Run the Textual Micropython Edukit Dynamic Pendulum Control user interface with
python textual_mpy_edukit.py
- If everything is fine, you should see the screen similar as the picture above, and repeated here:
You may need to increase your terminal size. Since Textual makes use of Unicode (UTF-8) characters on Windows 10 and older versions not all characters are displayed correctly. One may try to evaluate the command
chcp 65001
in the terminal before runningpython textual_mpy_edukit.py
, or just live with the imperfection.
The following figure gives the architecture of the complete system:
The following block diagram of the PID controller is given below (c.f. ucontrol.py
):
All these pictures may be convenient to better understand the following explanation.
-
In the center of the user interface you see two plot windows. The upper one shows the sensors:
- the steps of the stepper motor in blue, that is retrieved in micropython by evaluating
stepper.get_abs_pos_efficient()
- the ticks of the encoder in green, that is retrieved in micropython by
encoder.value()
.
The lower plot shows the control value, which is proportional to the frequency of the pulses send to the stepper motor by the L6474 stepper driver. In micropython this is the variable
pid.u
for the PID controller orss.u
for the state-space controller, and is send to the L6474 stepper motor driver by evaluating e.g.stepper.set_period_direction(pid.u)
(for PID).The samples are all stored in
pid.sample
orss.sample
, and retrieved at a frequency of 20 Hz in the functionupdate_plots
in the classTimeDisplay
intextual_mpy_edukit.py
(also c.f. the attributeself.update_timer = self.set_interval(1 / 20, self.update_time
), with the statementresp = await serial_eval(micropython_serial_interface,'pid.sample')
In fact all (serial) communication between the PC and the microcontroller is handled by this function
serial_eval
intextual_mpy_edukit.py
. - the steps of the stepper motor in blue, that is retrieved in micropython by evaluating
-
Below the plots there is a left and a right field: the left field contains a python prompt (bottom) and above a region that shows the output of the python interpreter. The right field is similar, but commands at the prompt are send to the microcontroller and the response is printed again above. So at the micropython prompt, e.g. one can type
pid.sample
to see the current value of respectively the stepper steps, encoder ticks and the control value. You may also inspect the other attributes of the object
pid
withdir(pid)
And, note that you may get the stepper motor steps and encoder ticks by typing the following lines in the micropython prompts (
stepper
is an instance of theL6474
class,encoder
is an instance of theEncoder
class):stepper.get_abs_pos_efficient() encoder.value()
or send a control value, e.g. 100, to the stepper motor:
stepper.set_period_direction(100)
Don't forget to set it to zero to prevent the wires get twisted too much:
stepper.set_period_direction(0)
Also the PID controller gains can be returned, for the feedback from the stepper steps:
pid.Kp1 pid.Ki1 pid.Kd1
and for PID controller feeding back the encoder ticks
pid.Kp2 pid.Ki2 pid.Kd2
-
At the micropython prompt one can also set these parameters, e.g. by
pid.Kp1 = 1
-
For quicker getting and setting the PID controller gains, one can use these the following get- and set-functions as well:
pid.get_gains1() pid.get_gains2() pid.set_gains1(0.1,0.0001,0.001) pid.set_gains2(0.1,0.0001,0.001)
Note, that you can do
Kp1, Ki1, Kd1 = pid.get_gains1()
However, the variables
Kp1
,Ki1
andKd1
on the left hand will be in Micropython no the microcontroller. If you want to have the values at the python prompt, you can use themicropython_results
variable in python. For example, run at the micropython prompt (right prompt):pid.get_gains1()
and than on the python prompt (left prompt), you can do:
Kp1, Ki1, Kd1 = micropython_results[0]
The indexing with
[0]
refers to the last micropython output,[1]
refers to the one before, etc. -
The reference (setpoint) value for the feedback from the stepper motor is stored in
pid.r1
and for the feedback from the encoder ticks, the reference is
pid.r2
So if one wants to move the stepper-motor to an angle corresponding with step value 100, one sets (besides the gains of the controller and the run-flags, see shortly below):
pid.r1 = 100
-
Note that the prompts only allow single line input.
-
The results returned by python as well as micropython are stored in python (left field) in the variables
python_results
andmicropython_results
, so they can be accessed later when needed. -
The vertical bar on the right contains a number of settings (radiobuttons) that are directly connected to variables on the microcontroller, e.g. to switch between PID and state-space control, to turn on/off the PID controller (
pid.run
), and to turn off/on the PID controller for the stepper motor (pid.run1
) and the encoder (pid.run2
). -
The vertical bar on the left is for logging. Logging is done with two buffers on the microcontroller, that are subsequently filled. If one buffer is full it is send from the microcontroller to the PC over the serial interface, while the other buffer is being filled, and so on. The logging is at the same sampling rate as the controller (100 Hz), but at the moment a buffer is send over the serial interface, the controller may lag a bit. This is visible in the logged signal as non-fluent changes between the buffers. Reducing the sampling rate or replacing the STM F401RE microcontroller with a faster one, preferably with more processing cores, or moving the control task to a ISR (interrupt service routine) may solve this issue. For now we accept the small lags.
-
If you want to exit, close the user interface with
Ctrl-c
, which will nicely end the program on the microcontroller and the user-interface.
- Micropython firmware for Nucleo-F401RE and mpy-cross tool, tested with version 1.24.0, both should have same version!
- Python, tested with version 3.12 and 3.13
- Textual, tested with version 0.85.1
- aioserial, tested with version 1.3.1 (needed for nonblocking asynchronous communication with the serial interface at the python side)
- mpremote, tested with verion 1.24.0
- Further: see
requirements.txt
- To compile the
mpy
-files one needs thempy-cross
program, that you can install on both Windows and Linux, e.g. byMake sure, you give the same version as the version of micropython on the microcontroller.pip install mpy-cross==1.24.0
- On Linux: Adjust the
Makefile
according to the location of thempy-cross
executable - On Linux: Compile the micropython files with
make
- On Windows: Evaluate
mpy-cross -march=armv7emsp -O3 -X emit=bytecode mpy_edukit.py mpy-cross -march=armv7emsp -O3 -X emit=bytecode ucontrol.py mpy-cross -march=armv7emsp -O3 -X emit=bytecode uencoder.py mpy-cross -march=armv7emsp -O3 -X emit=bytecode uL6474.py mpy-cross -march=armv7emsp -O3 -X emit=bytecode urepl.py