I was interested in creating a RPi Cluster to learn about how they work. After getting the clusterhat and Pi Zero Ws I set about creating the images for 5 sd cards. This seemed a waste so I scrapped that idea and setup the image for one sd card (the main RPi) and got my learn on about network through usb. After about 3 days of googling, learning and much frustration, I got it working!
Once I had got my head around mpiexec I then thought of what I could use it for.
Enter seti@home.
What is SETI@home?
SETI@home is a scientific experiment, based at UC Berkeley, that uses Internet-connected computers in the Search for Extraterrestrial Intelligence (SETI). You can participate by running a free program that downloads and analyzes radio telescope data. You can learn more about Seti@Home on to the project!
How it works
After about 3 days of googling, learning and much swearing I got it working. Once I had got my head around mpiexec I then thought of what I could use it for. Enter seti@home. After more setup, config and swearing I had it running. I wanted to show the status of each pi via cmd line so using shell scripts and mpiexec to display it on a small screen. Then I learned about the blinkt leds strips so got one for each rpi zero on the hat and pythoned up the blinkt strips to display % complete of tasks being performed on that particular pi.
The main rpi3 GPIO pins were used by the clusterhat but it still displayed the status on the screen. Then disaster! I used the washer, dryer and kettle at the same time and the power safety switch got triggered. After reboot and restart I decided I needed a UPS. From an old motorcycle battery, a solar charge controller and a cigarette car charger I cobbled it all together. The switch from mains power to battery is triggered via the network cable on the main rpi3 that is connected to an old router. If the power goes off on the router then the ups kicks in.
Parts for the Cluster:
- 1 RPI3b+
- 4 RPI zeros
- 4 Blinkt strips
- 1 Network cable
- 1 usb to usbmicro cable
- 1 Router (you could also plug the network cable into another computer)
Parts for the UPS (Power Supply)
- 1 12v motorcycle battery
- 1 usb car cigarette charger
- 1 solar charge controller
- 1 usb to usbmicro cable
- 1 12v power adaptor
How the UPS Works
The UPS battery is connected to the solar charge controller and is being charged by the 12v power adaptor. The USB car cigarette charger bumps the voltage from 12v to 5.1v. The usb to usbmicro is the power cable for the cluster. When the mains power goes out, the solar charge controller switches from mains and charging to battery power.
Configuring the RPi Cluster
Each rpi has a getstats.sh script that collects the info and stores it in a file. Only the main rpi3 has the UPS part of the script at the bottom
Read code comments for more information on how it all comes together
getstats.sh ======================================================== #! /bin/bash #echo $HOSTNAME ##remove previous files rm tmpstats* ##create new blank files touch tmpstats_$HOSTNAME ##add the hostname and a line hostname > tmpstats_$HOSTNAME echo "==========" >> tmpstats_$HOSTNAME ##get the uptime of the computer and write to file uptime -p | tr -d , >> tmpstats_$HOSTNAME ##get CPU usage and write to file echo "CPU:" $[100-$(vmstat 1 2|tail -1|awk '{print $15}')] >> tmpstats_$HOSTNAME ##get memory stats and write to file free -th | grep Total | awk '{print "Total Mem: "$2}' >> tmpstats_$HOSTNAME free -th | grep Total | awk '{print "Used Mem: "$3}' >> tmpstats_$HOSTNAME free -th | grep Total | awk '{print "Free Mem: "$4}' >> tmpstats_$HOSTNAME ##get RPI stats and write to file vcgencmd measure_temp >> tmpstats_$HOSTNAME vcgencmd measure_volts core >> tmpstats_$HOSTNAME vcgencmd get_mem arm >> tmpstats_$HOSTNAME vcgencmd get_mem gpu >> tmpstats_$HOSTNAME ##get bounc stats and write to file boinccmd --get_simple_gui_info | grep fraction | sed -r 's/( )+//g' >> /home/pi/tmpstats_$HOSTNAME ##get ups stats and write to file echo "UPS Stats" >> tmpstats_upsd echo "==========" >> tmpstats_upsd upsd -i >> tmpstats_upsd echo ======================================================== The main rpi3 has a runscript that collects all the files and displays them on screen. run001.sh ======================================================== ##clear screen, display date/time and message clear date echo "Finding swarm machines" ##run the command hostname on each node in the cluster mpiexec -f /home/pi/machinefile -n 5 hostname echo "Running swarm scripts" ##run getstats.sh on each node in the cluster mpiexec -f ./machinefile -n 5 /home/pi/getstats.sh ##clear screen, display date/time clear date ##print to screen in columns the contents of 2 files below pr -m -t ~/tmpstats_RPC ~/tmpstats_upsd ##print blank line echo ##print to screen in columns the contents of 4 files below pr -m -t /var/lib/clusterctrl/nfs/p1/home/pi/tmpstats_p1 /var/lib/clusterctrl/nfs/p2/home/pi/tmpstats_p2 /var/lib/clusterctrl/nfs/p3/home/pi/tmpstats_p3 /var/lib/clusterctrl/nfs/p4/home/pi/tmpstats_p4 ========================================================
Pi Zero Configuration
Each Pi Zero has a python script to collect and display the percentage on the blinkt strips. (The results of the boinccmd percentage done is to 6 decimal places so I had a bit of fun with the leds) This is still a work in progress as I want to see how much info I can display via the blinkt strips percent_done.py
Read code comments for more information on how it all comes together
#!/usr/bin/env python import time import subprocess from sys import exit ##check if module is installed try: import psutil except ImportError: exit("This script requires the psutil module\nInstall with: sudo pip install psutil") import blinkt ##when script stops turn off leds blinkt.set_clear_on_exit() def show_graph(v, r, g, b): ##set all the pixels to red v *= blinkt.NUM_PIXELS for x in range(blinkt.NUM_PIXELS): if v < 0: r, g, b = 1, 0, 0 ##fade in blue pixels based on while true calculations else: r, g, b = [int(min(v, 1.0) * c) for c in [r, g, b]] blinkt.set_pixel(x, r, g, b) v -= 1 blinkt.show() blinkt.set_brightness(0.1) ##this bit splits the 6 decimal places number into ##percentages and assigns them to parameters ##for fading the blue pixels while True: v = subprocess.check_output("boinccmd --get_simple_gui_info | grep fraction | sed -r 's/( )+//g' | tail -c 7 | head -c 2", shell=True) c = subprocess.check_output("boinccmd --get_simple_gui_info | grep fraction | sed -r 's/( )+//g' | tail -c 5 | head -c 2", shell=True) b = subprocess.check_output("boinccmd --get_simple_gui_info | grep fraction | sed -r 's/( )+//g' | tail -c 3 | head -c 2", shell=True) v = int(v) c = int(c) b = int(b) v = v / 100.0 v = float(v) ##runs show_graph, passing in values for blue led fade show_graph(v, 0, 0, b) time.sleep(1.0) ========================================================