View on GitHub

md-in-a-box

Md in a Box: Interactive 2D molecular dynamics simulation running on a Raspberry Pi Pico 2

MD in a Box

Interactive 2D molecular dynamics simulation running on a Raspberry Pi Pico 2. Based on the browser-based MD simulation by Ulf R. Pedersen: https://urp.dk/md/

Liquid phase Crystal phase

Physics

Atoms are modelled as classical particles interacting via pair forces, following Newton’s laws of motion. A Langevin thermostat maintains the temperature.

Hardware

Component Details
Raspberry Pi Pico 2 RP2350, dual-core ARM Cortex-M33 @ 150 MHz, 520 KB RAM
Pico Display Pack 2.0 320×240 pixel display (Pimoroni)
BNO055 9-axis IMU Gravity vector + linear acceleration (DFRobot breakout)

Total hardware cost: ~€65


Architecture

The simulation uses both CPU cores:

Particle positions are stored in shared memory arrays read by Core 0 for drawing. The accelerometer feeds tilt (gravity direction) and movement (box linear acceleration) into the simulation.


Performance

The MD force loop and Leap Frog integrator are implemented as a custom C extension to ulab (user.c), called from MicroPython. This gives a large speedup over pure Python/ulab:

N atoms ulab (MDPS) ulab + C (MDPS) Speedup
16 78 12,674 ~160×
25 35 6,816 ~195×
36 18 3,960 ~220×
64 5 1,553 ~310×
100 748

*Measured on Pico 2 as pure MD run, with no graphics or physical input.

In the full demo (display + accelerometer + 100 atoms): ~500 MD steps/second.


Controls

Button Action
A Cycle options: Temperature → Gravity → Pause → Coupling → Box Vel scale
X Increase selected parameter
Y Decrease selected parameter
X + Y Save screenshot (PPM file)
Hold B (1 sec) Shutdown

Physical interaction via the accelerometer:


Files

Simulation cores

File Description
md_sim_ulab_numpy.py Pure Python/ulab simulation class (no C), runs on MicroPython with ulab and standard Python with numpy
md_sim_ulab_user_c_func.py Simulation class using C-accelerated force loop integrated with ulab
user.c Custom ulab C extension for ulab: Leap Frog integrator + LJ forces

Pico applications

File Description
run_show_sim_ulab_user_c_func_dual_core_pico_dislay.py Main demo: dual-core display + physics
run_test_ulab_user_c_func.py Benchmark (no display) — C version
run_test_ulab_user_c_func_pico_display.py Benchmark with display output — C version
run_test_ulab_numpy.py Benchmark (no display) — pure ulab / numpy version
bno055_handler.py BNO055 accelerometer wrapper

Desktop

File Description
run_show_sim_numpy_pc.py Desktop visualization with optional matplotlib plot

Building the Firmware

MicroPython / ulab / display

The C extension requires a custom MicroPython + ulab build.

user.c should be placed in the ulab folder:

ulab/code/user/user.c

and enabled it by setting ULAB_HAS_USER_MODULE in ulab.h.

For the full integration with pico display 2, pimoroni modules are also needed. Easiest build strategy is to use a modified version of the pimoroni-pico-rp2350 build.

Pimoroni provides a CI setup at:

https://github.com/pimoroni/pimoroni-pico-rp2350.git

The script

setup_and_build_firmware.sh

utilizes this CI setup to perform a build (as of February 2026), might be broken in the future.

BNO055 accelerometer support

For supporting the accelerometer the micropython-bno055 library must be added to the device.

The library is found at:

https://github.com/micropython-IMU/micropython-bno055

Quick Start

# Desktop test (numpy / matplotlib version )
python3 run_show_sim_numpy_pc.py

# Upload to Pico
mpremote fs cp md_sim_ulab_user_c_func.py :
mpremote fs cp bno055_handler.py :
mpremote fs cp run_show_sim_ulab_user_c_func_dual_core_pico_dislay.py :

# Run on Pico
mpremote run run_show_sim_ulab_user_c_func_dual_core_pico_dislay.py

References


License

MIT — see LICENSE.

Authors

Bo Jakobsen, IMFUFA, Roskilde University (boj@ruc.dk) Based on the browser-based MD simulation by Ulf R. Pedersen (urp@ruc.dk)