Julia programming on a Raspberry Pi

Julia is a relatively new general purpose programming language that has an emphasis towards data science and AI.

In the past few year Julia has been gaining momentum, and it now ranks as the 20th most popular programming language. Like Python and R, Julia can also be used in Jupyter notebooks.

A Raspberry Pi module can be used as great platform to get introduced to Julia programming. Python users will be happy to hear that Python code can be integrated directly into Julia scripts.

In this blog, I’ll look at Julia GUI, micro-Web server, and charting apps that communicate with Raspberry Pi hardware. I’ll also introduce mixing Python code within Julia script to communicate with an LCD display.

Getting Started

Julia is supported on Windows, MacOS and Linux. See the download documentation for your specific system at : https://julialang.org/downloads/. The latest supported version of Julia can be installed on a Raspberry Pi with snap. To install snap:

$ sudo apt update
$ sudo apt install snapd
$ sudo reboot

After the Raspberry Pi has restarted, snap is used to install Julia:

$ sudo snap install core
$ sudo snap install julia --classic

Note, it’s possible to install Julia using: sudo apt install julia , however this will be an older version. To check the version of Julia either use the -v option, or simply run julia.

Your project setup will vary based on the sensors and hardware that you have available. For my setup I used a 16×2 LCD screen and a BME280 temperature/humidity/pressure sensor there were wired into the Raspberry Pi using I2C connections. The hardware was connected using a Pimoroni Explorerhat (~$25) which has four build-in colored LEDs and small prototyping breadboard.

The I2C (Inter-Integrated Circuit) protocol uses a multi-master/multi-slave serial communication bus, with the serial data line (SDA) on Raspberry Pi pin 3 and serial clock line (SCL) on pin 5.

Julia with Raspberry Pi GPIO

Communicating with the Raspberry Pi’s GPIO (General Purpose Input/Output) pins is done with the Julia PiGPIO package. This package can be installed at the command line by:

$ julia --eval 'using Pkg; Pkg.add("PiGPIO")'

To install and view status of packages within Julia:

julia> # load the Pkg module
julia> using Pkg
julia> # install a new package
julia> Pkg.add("PiGPIO")

julia> # view the status of installed packages
julia> Pkg.status()
Status `~/.julia/environments/v1.9/Project.toml`
  [bb151fc1] PiGPIO v0.2.0

Once this package is installed a daemon, pigpiod is created that the Julia script connects to. The pigpiod daemon can be started at the command line by: sudo pigpiod .

Below is some interactive code to; load the PiGPIO library, create the Pi object (p), set the mode of the pin, and finally write to and read from GPIO pin 17:

julia> using PiGPIO
julia> ledpin = 17;
julia> p = Pi();
julia> set_mode(p,ledpin, PiGPIO.OUTPUT);
julia> PiGPIO.write(p, ledpin, PiGPIO.HIGH);
julia> PiGPIO.read(p, ledpin)
1

Note: adding a semi-colon at the end of a line will suppress debug information.

Now that the basic communications is working between Julia and the Raspberry Pi pins, GUI and Web server apps can be created.

GUI’s with Gtk

Like most programming languages Julia has a number of GUI options. For my testing I used the Gtk library which is installed in Julia by:

julia> using Pkg
julia> Pkg.add("Gtk")

Below is a Julia script to create a two button window that will turn on/off a GPIO pin. The Julia code looks somewhat similar to Python or Matlab syntax. Libraries are imported by the using command (lines 4-5). Functions are defined with a function statement and closed with an end (lines 32-35, and 38-41). A do block (lines 45-47) is used to group logic with a function.

# 
# gtk_17.jl - Use a Gtk GUI to toggle a PI GPIO LED
#
using Gtk;
using PiGPIO;

# Setup GPIO 
p=Pi();
led_pin = 17;
set_mode(p, led_pin, PiGPIO.OUTPUT) 

# Init GUI objects
win  = GtkWindow("Toggle a Pi LED", 300, 300);
g  = GtkGrid();

# Text label
label  = GtkLabel(string("Pin : $led_pin"));
# Buttons
btn_on  = GtkButton("ON");
btn_off  = GtkButton("OFF");

# Put GUI widgets into a grid
g[1:2,1] = label;   # Cartesian coordinates, g[x,y]
g[1,2] = btn_on;
g[2,2] = btn_off;

# Show the GUI Window
push!(win, g);
showall(win);

# Callbacks
function turn_on(w1)
	PiGPIO.write(p, led_pin, PiGPIO.HIGH)
	println("ON button pressed")
end
signal_connect(turn_on, btn_on, "clicked")

function turn_off(w2)
	PiGPIO.write(p, led_pin, PiGPIO.LOW)
	println("OFF button pressed")
end
signal_connect(turn_off, btn_off, "clicked")

# Close cleanly
signal_connect(win, :destroy) do widget
    Gtk.gtk_quit()
end
Gtk.gtk_main()

This Julia script is run by:

$ julia  gtk_17.jl

Below is a picture of the Julia Gtk app toggling GPIO pin 17 (the yellow LED 2 on the Pi Explorer Hat).

Julia Web Server

Like graphic libraries, there are a few web server options. I found that the Genie web frame work was one of the easiest to get up and running.

Below is an example web app that create two button to turn a GPIO pin on/off.

For this script, three libraries are used; Genie, for the web server, Sockets, to get the Raspberry Pi’s IP address, and PiGPIO, to connect to the GPIO pins (lines 4-6). Pin 17 is set as an output in lines 9-11. To keep things simple the HTML code is defined as a variable (lines 19-32). For larger projects it would be recommended that external HTML files be used.

The Julia code defines three routes (lines 34-49). The first route is the default (/) page that prints out the html_file variable. The /ON and /OFF routes set the GPIO pin output when either the ON or OFF form buttons are pressed.

The final line in the script sets up the web framework to run on port 8001 with the Raspberry Pi’s IP address.

#
# web2gpio.jl - Julia Web Page with routes to turn on/off a Pi GPIO pin
#
using Genie
using Sockets # to get IP address
using PiGPIO;
 
# Setup GPIO 
p=Pi();
led_pin = 17;
set_mode(p, led_pin, PiGPIO.OUTPUT) 
 
# get the Rasp Pi IP address
myip = string(getipaddr() )
 
println("Loading Genie...")
 
# create an HTML document
html_file = """
<html>
<head>
<title>Julie GPIO Test Page</title>
</head>
<body>
  <h1>Toggle PI LED</h1>
  <form>
    <button type="submit" formaction="/ON">ON</button>
    <button type="submit" formaction="/OFF">OFF</button>
  </form>
</body>
</html>
"""
 
route("/") do
  return html_file
  println("Connected")
end
 
route("/ON?") do
  PiGPIO.write(p, led_pin, PiGPIO.HIGH)
  return html_file
  println("ON Selected")
end
 
route("/OFF?") do
  PiGPIO.write(p, led_pin, PiGPIO.LOW)
  return html_file
  println("OFF Selected")
end
 
# Start the web app on port 8001
up( 8001, myip, async = false)

To start the Julia web script enter:

julia  web2gpio.jl

Plot BME280 Sensor Data

For this final example the goal is to create a dynamic bar chart that will show BME280 temperature and humidity data.

The Plots charting library is installed by:

julia> using Pkg
julia> Pkg.add("Plots")

Unfortunately Julia does not have a large Raspberry Pi sensor library like either Python or Node-Red, so for this a BME280 Bash command line utility can be used:

$ # Install a Python based Bash command line tool
$  sudo python -m pip install bme280

BME280 sensors typically use I2C addresses of 0x76 or 0x77. The i2cdetect tool can be used to verify which address your sensor is on ( i2cdetect -y 1) .

Within Julia, external command strings are define with backticks ( ` ). Below is an example that creates a command variables (mycmd), then checks the variable type and runs the command:

julia> mycmd = `pwd`;   # pwd=present working directory
julia> typeof(mycmd)
Cmd

julia> run(mycmd) ; # run the command
/home/pete/jtest

The Julia read function can run an external command and store the output string as a variable. A split can be used to output BME280 results into an array strings. Below is some interactive code that show the humidity as the 3rd index (data[3]), and temperature as the fifth index (data[5]).

The Julia script below has a while loop that cycles every 10 seconds (lines 9 and 28). The sensor data is read from the Bash command and then passed to a data array (lines 12 and 13). The temperature and humidity values are parsed as floats (lines 16 and 19) and then shown in a bar chart (lines 23-25).

#!/snap/bin/julia
#
# bme_280.jl - show BME280 sensor data on a refreshing bar chart
#
using Plots
using Dates

print("Show BME280 readings every 10 seconds. Control-C to exit.\n")
while true

    # get the sensor output, then split it into an array of strings
    output = read(`read_bme280 --i2c-address 0x77`, String)
    data = split(output)

    # get the temperature as a Float, (5th item in array)
    t = parse(Float64,data[5]) 

    # get the humidity as a Float, (3rd item in array)
    h = parse(Float64,data[3])

    # define a bar chart
    thetitle = "BME280 Data - " * Dates.format(now(), "H:MM:SS")
    p = bar(["Temperature (C)","Humidity (%)"], [t,h],legend=false, 
            title=thetitle, texts = [t,h], color=[:red, :yellow] )
    display(p)

    sleep(10)
end

This script has the location of the julia binary in the first line, so the file can be run like a Bash or Python application:

$ # enable the execute status on the file
$ sudo chmod +x bme_280.jl
$ # run the script directly
$ ./bme_280.jl

Julia calling Python

One of the interesting features of Julia is that script languages like Lua, Matlab, R and Python can be integrated directly into Julia code.

To enable this functionality the first step is to install the required language library. To add the Python interface library:

$  julia --eval 'using Pkg; Pkg.add("PyCall")'

Most of the Raspberry Pi sensors and 3rd party devices are supported in Python, so the PyCall library can come in extremely handy when you want to communication with any external Pi hardware.

An easy example using PyCall can be done with a 16×2 LCD display. The first step in the integration is to install the Python Pi LCD library:

$ # install the Python Raspberry Pi LCD library
$ pip install RPi.bme280

PyCall works in a couple of different ways. The first is that Python code can be used directly within Julia script, and the second approach is to have Julia code reference Python objects.

An example to run Python code directly to write text to a 2 line I2C LED screen:

julia> using PyCall
julia> py"""
       # Use Python to write text to a 2 line LCD screen
       from rpi_lcd import LCD
       lcd = LCD()
       lcd.text('Hello World!', 1)
       lcd.text('Raspberry Pi', 2)
       """
julia> # Now back into Julia

The py statements runs a string of multiple Python lines. Errors will occur if the string does not adhere to Python’s indentation rules.

To do the same functionality referencing a Python object in Julia:

using PyCall
rpi_lcd = pyimport("rpi_lcd");
lcd = rpi_lcd.LCD();
lcd.text("Hello from Julia", 1)
lcd.text("Raspberry Pi!", 2)

Summary

A Raspberry Pi can be a good platform to get introduced to Julia programming. For Python user the mixing of Python code into Julia scripts allows for common Pi hardware to be integrated into your new projects.

After getting a handle on some of the Julia basics, the next steps might be to investigate data analysis, Jupyter notebooks, or AI applications.

It should be noted that playing with Julia on older Raspberry Pi hardware or using early versions of Julia can run painfully slow. To improve the call-up time, Julia offers a number of packaging and pre-compilation options.

One thought on “Julia programming on a Raspberry Pi

Leave a comment