A sky projection based on Stellarium for very curious and inquisitive children
In Carl Sagan's Contact, SETI detects an intelligent signal coming from the star Vega in the constellation Lyra. In The Invincible by Stanislaw Lem, the crew of the eponymous spaceship lands on the planet Regis III, in the constellation Auriga, and finds the ruins of an ancient Lyran civilization (apparently Lyrans are super-advanced, or at least very popular). And in The Three Body Problem by Cixin Liu, the invaders come from the constellation Centaurus.
Constellations are not only the beautiful tapestry of the sky and the source of awe and inspiration for many stories and myths, they are essentially celestial landmarks. Whether it is a super intelligent civilization in a science fiction story or a scientific observation, the constellations are our reference points in the sky. For example, the planets move very close to the ecliptic, so the constellations not only give you your horoscope, but can help you find our traveling companions.
Constellations and their mythologies are also great material for bedtime stories. I was inspired to create this project while reading Constellations by Govert Schilling. In a way, I see this project as an extension of the book. I extended the book with an animated, real-time projection of the night sky. Of course, all the heavy lifting is done by Stellarium, one of my all-time favorite open source software.
This project is basically a remote control for Stellarium. It uses the API provided by the remote control plugin to trigger scripts written in the Stellarium scripting engine. The objects and animations to be displayed are controlled by QR codes (pasted in the corresponding constellations on the book).
The application is designed in a way that it can run on a computer, such as a laptop running Linux or Mac, as well as a Raspberry Pi (I tried a Raspberry Pi 5).
Install Stellarium (follow the instructions for your OS, package manager, etc.)
Enable and make sure the remote control plugin in Stellarium is running. You can do this in the UI or by modifying the config.ini
file. See the [Remote Control]
section in the example Stellarium configuration file for reference.
You can check if the API provided by the remote control plugin is working by calling e.g:
curl -X POST -d 'id=zodiac.ssc' http://localhost:8090/api/scripts/run
Download this code
git clone https://github.com/twaclaw/canismajor.git
cd canismajor
Install the Python application.
Using uv:
uv venv venv --python 3.13 # or 3.11 or 3.12
. venv/bin/activate
uv pip install -e . # on the raspberry pi: uv pip install -e .[rpi]
Using pip
:
virtualenv venv --python 3.13 # or 3.11 or 3.12
. venv/bin/activate
pip install -e . # on the raspberry pi: pip install -e .[rpi]
Modify the conf.yaml configuration file. In particular:
- Make sure that the folder containing the Stellarium scripts is listed under
script_paths
- Check which language the installed version of Stellarium uses to select the constellations. For example, version 24.4 uses
native
names, e.g., "Orion", "Canis Major", "Gemini", etc., while version 25.1 uses English names, e.g., "Hunter", "Great Dog", "Twins", etc. Setconstellations_language
accordingly, either "english" or "native" (you can use the search function CTRL + F to find out which language is used in your Stellarium version).
Run the application
python -m main --conf conf.yaml
The application has a queue waiting for the names of the objects to be selected (constellations, planets, etc.), or otherwise the name of the script to be executed. Note that the names are case sensitive. The following logic and priorities are used:
-
If the name is one of the keys in the
constellations
dictionary defined in stellarium.py (for example "Andromeda" or "Ursa Major"), then the constellations template is used to select the constellation. -
If the name is one of the items in the
search:objects
list in the configuration file (for example "Mars" or "Callisto"), then the object template is used to select the object. Feel free to add more objects to the list. -
If the name is one of the keys, other than "constellations" and "objects", in the
scripts
dictionary in the configuration file (for example "zodiac2"), then the script with the same name in the templates folder will be executed without parameters. If you add new scripts, choose the names so that they do not conflict with existing Stellarium scripts. -
If the name is one of the scripts included in the official Stellarium distribution, this script will be executed without modifications.
The names can be passed to the application in one of the following ways:
- By typing them into the standard input (console), which can be useful for debugging:
python -m main --conf conf.yaml
>>Auriga
>>
- The list
controls
in the configuration file should containconsole
.
The fact that the particular QR code reader I used is recognized as a keyboard is both good and bad. It is good because it is easy to test the QR reading functionality with no code and virtually no configuration. When the focus (mouse over) is on the console (terminal) where the application is running, the QR code readings are passed to the application as if they were typed on the keyboard (make sure that the keyboard is set to the US layout or a similar one that does not transpose the keys).
The reason why this is bad applies mainly to the Raspberry Pi. On the one hand, the HID device is read directly by the application, all good so far, but because the device is also recognized as a keyboard and the focus is on the Stellarium software, the QR code readings are interpreted as shortcuts and Stellarium ends up doing funny things.
One way to prevent this is to disable all shortcuts in Stellarium (at least the alphabetical ones). See the [shortcuts]
section in the Stellarium example configuration file for reference (shortcuts may be different in your Stellarium version).
- By scanning a QR code that encodes the corresponding object name. This approach assumes that the QR code scanner is identified as a keyboard (a HID device).
- The list
controls
in the configuration file should containqrcode
. - The console method described above can work if the application is called from the command line but not if it is run as a
systemd
service.
This image is an example with QR Codes corresponding to the 88 constellations. The script qrcodes.py can be used to generate this file, as well as other QR Codes corresponding to other objects.
python scripts/qrcodes.py --help
# For example to generate the QR codes for the 88 constellations on a single page:
python scripts/qrcodes.py --output codes_constellations.svg constellations
# to generate the QR codes for the objects and scripts:
python scripts/qrcodes.py --output objects_and_scripts.svg objects --conf conf.yaml --what SO
# or to generate a single QR code (exact spelling, case sensitive):
python scripts/qrcodes.py --output canis_major.svg single --data "Canis Major"
- Raspberry Pi 5 (other models might work) with an SSD disk for better performance
- A QR scan code reader
- An HDMI projector or screen
My setup looks like this:
If you are coming from a headless Raspberry Pi, you will need to install the UI.
sudo apt-get install raspberrypi-ui-mods
It can be installed either by snap
or by compiling from source. I found that version v24.4
against Qt 5 generally works better on this device, and built it from source.
Using snap
sudo apt update
sudo apt install snapd
sudo reboot
sudo snap install snapd
sudo snap install stellarium-daily # latest version
Building from source
git clone https://github.com/Stellarium/stellarium.git
cd stellarium
git checkout v24.4 # or any other version
mkdir build24.4 && cd build24.4
# install dependencies, see: https://github.com/Stellarium/stellarium/blob/master/BUILDING.md
# v24.4 and head working with Qt5
sudo apt install build-essential cmake zlib1g-dev libgl1-mesa-dev libdrm-dev gcc g++ \
graphviz doxygen gettext git libgps-dev \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-pulseaudio \
gstreamer1.0-libav gstreamer1.0-vaapi qtbase5-dev \
qtbase5-private-dev qtscript5-dev libqt5svg5-dev qttools5-dev-tools \
qttools5-dev libqt5opengl5-dev qtmultimedia5-dev libqt5multimedia5-plugins \
libqt5serialport5 libqt5serialport5-dev qtpositioning5-dev libqt5positioning5 \
libqt5positioning5-plugins qtwebengine5-dev libqt5charts5-dev \
libexiv2-dev libnlopt-cxx-dev libtbb-dev libtbb2 libqt5concurrent5 \
libmd4c-dev libmd4c-html0-dev
cmake -DCMAKE_BUILD_TYPE="Release" ../stellarium
nice make -j4
The executable will be in build_folder/src/stellarium
.
See the Stellarium service.
See uv docs
curl -LsSf https://astral.sh/uv/install.sh | sh
The application can run as a systemd
service.
mkdir -p $HOME/.config/systemd/user
cp conf/systemd/* $HOME/.config/systemd/user/
systemctl --user start canismajor.service
# optional
systemctl --user enable canismajor.service
loginctl enable-linger
The QR code scanner I used is detected as a HID keyboard device (/dev/hidraw0
). You can use lsusb
to get information about this device, for example to create a udev
rule.
lsusb
Bus 001 Device 014: ID 1a86:5456 QinHeng Electronics USB Keyboard
cat /etc/udev/rules.d/99-qrcode-reader-permissions.rules
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="5456", MODE="0666"
I reversed-engineered the protocol implemented in src/hid.py by checking:
sudo hexdump -C /dev/hidraw0
This is tiny project but your contributions are more than welcome. If you have any suggestions, ideas, or improvements, please feel free to open an issue or a pull request. If you have any questions or want to start a discussion, please feel free to reach out.
Have a look at the contributing guidelines for more information.
- Stellarium
- Constellations by Govert Schilling
- Title image: A celestial map by the Dutch cartographer Frederik de Wit, 1670, Wikimedia