Raspberry Pi ...and... PythonScratchBashNodeRedCjavaWolframCOBOLR ...and minecraft?
My friend Helen Wall recently posted about the family tree of programming languages. There's 4,800 of them - probably more. Here's the article...
I've been exploring programming languages and the Raspberry Pi. I've especially been interested in languages that can be used to control the GPIO (General Purpose Input Output). I apparently have a lot of free time, so here's a collection of those languages - and a snippet of each below...
What are your thoughts? Have you used any of these with the Raspberry Pi?
Please subscribe to mnRRRRRRR for more #RaspberryPi goodness.
The Languages - demonstrations
Here's a collections of links to LinkedIn videos for each language, showing how it works with Raspberry Pi
: Python : Scratch : bash : Node-Red : C : java : Wolfram : COBOL : Minecraft : R : BASIC :
The Languages - snippets
Python
# example of programming Raspberry Pi GPIO with gpiozero # refer to gpiozero.readthedocs.io import gpiozero as gpzero from time import sleep # set up pushbutton and bank of leds resetbutton = gpzero.Button(3) leds = gpzero.LEDBoard(26,16,20,21) # functions to control behavior def LightsOn (): while resetbutton.is_pressed: leds.on() def ResetCounter (): global counter leds.off() counter = 0 def binary2lights(showThis): leds.value = ( showThis & 0b1000, showThis & 0b0100, showThis & 0b0010, showThis & 0b0001) # setup button handlers resetbutton.when_pressed = LightsOn resetbutton.when_released = ResetCounter # send 0...15 to lights while True: ResetCounter() while counter < 16: binary2lights(counter) counter += 1 sleep(1)
Scratch
Scratch is a visual / block style language so there aren't any snippets. Here's a screen shot. This scratch code does the same thing as the python code listed above.
bash
Bash is often overlooked as a diminutive scripting language, only used by system administrators to automate daily tasks. With a Raspberry Pi, bash provides a quick and easy way to knock out a solution complete with GPIO support. The following BASH code does the same thing as the python and scratch code above.
#!/bin/bash # the GPIO requires root level access. So... # cd to exercise files # then... # sudo bash ./09-05_bash_gpio.sh # bash shell script to demonstrate gpio control # set up pushbutton resetbutton=3 # BCM numbering scheme echo $resetbutton > /sys/class/gpio/export echo "in" > "/sys/class/gpio/gpio${resetbutton}/direction" echo "assign GPIO pin $resetbutton as pushbutton" # set up bank of LEDs # pin 26 is MSB. pin 21 is LSB # so ${LED_pins[0]} points to gpio pin 21, which is least significant bit (LSB) LED_pins=(21 20 16 26) # BCM numbering scheme. LED_paths=() # creating an array for use in a minute # Assign GPIO pins to LEDs for LED_idx in {0..3} do echo "assign GPIO pin ${LED_pins[$LED_idx]} as LED" echo ${LED_pins[$LED_idx]} > /sys/class/gpio/export LED_paths[$LED_idx]="/sys/class/gpio/gpio${LED_pins[$LED_idx]}/" echo "out" > "${LED_paths[$LED_idx]}direction" done # create and install function to clean up pin assignments on control+c echo "press CTRL+C to stop..." function controlC { echo for LED_idx in {0..3} do echo "Clean up GPIO pin ${LED_pins[$LED_idx]}" echo ${LED_pins[$LED_idx]} > /sys/class/gpio/unexport done echo "Clean up GPIO pin $resetbutton" echo $resetbutton > /sys/class/gpio/unexport exit $? } trap controlC SIGINT # function to turn on/off LEDs function LightsOn ( ) { # $1 is the argument passed to LightsOn. i.e LightsOn($1) echo $(($1 & 2#0001)) > "${LED_paths[0]}value" echo $(($1 & 2#0010)) > "${LED_paths[1]}value" echo $(($1 & 2#0100)) > "${LED_paths[2]}value" echo $(($1 & 2#1000)) > "${LED_paths[3]}value" } # this is the working loop while : do counter=0 while [ $counter -lt 16 ] do # test for pushbutton if [[ $(< "/sys/class/gpio/gpio${resetbutton}/value") == "0" ]] then LightsOn 15 # turn on all the LEDs while [[ $(< "/sys/class/gpio/gpio${resetbutton}/value") == "0" ]] do echo "waiting while button is pressed" done counter=0 # restart the count from zero echo "The button is released" fi LightsOn $counter sleep 1 ((counter++)) done done
Node-Red
Another visual language. Node-red relies on javascript for the logic behind the blocks - but employs a visual editor to illustrate the program flow. And yes - you guessed it - this node-red code does the same thing as the above code examples.
C
C is the "mother of all languages" - although I would award that title to assembler. Here's another way to perform the same activity.
/* 09-07_c_gpio.c * * Demonstration of controlling the Raspberry Pi GPIO with C * * 1) install bcm2835 (https://www.airspayce.com/mikem/bcm2835/index.html) * 2) cd directory-containing-this-file * 3) compile ... gcc -o bincount 09-07_c_gpio.c -l bcm2835 * 4) ./bincount * * Author: Mark Niemann-Ross * https://linkedin.com/in/markniemannross */ #include <bcm2835.h> #include <stdio.h> #include <signal.h> #include <stdlib.h> /* set up bank of LEDs * BCM 26 is MSB. BCM 21 is LSB */ #define LED_1 RPI_V2_GPIO_P1_40 // aka BCM 21 #define LED_2 RPI_V2_GPIO_P1_38 // aka BCM 20 #define LED_4 RPI_V2_GPIO_P1_36 // aka BCM 16 #define LED_8 RPI_V2_GPIO_P1_37 // aka BCM 26 #define resetbutton RPI_V2_GPIO_P1_05 // aka BCM 3 void LightsOn( int lightMask ) { // bcm2835_gpio_write(PIN, HIGH); turns on a pin // HIGH = 1 bcm2835_gpio_write(LED_1, lightMask & 1 ); bcm2835_gpio_write(LED_2, lightMask & 2 ); bcm2835_gpio_write(LED_4, lightMask & 4 ); bcm2835_gpio_write(LED_8, lightMask & 8 ); } void ctlcHandler( int sig) { LightsOn(0); bcm2835_close(); exit(0); } int main(int argc, char **argv) { if (!bcm2835_init()) return 1; signal(SIGINT, ctlcHandler); // Set the LED pins to output bcm2835_gpio_fsel(LED_1, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_fsel(LED_2, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_fsel(LED_4, BCM2835_GPIO_FSEL_OUTP); bcm2835_gpio_fsel(LED_8, BCM2835_GPIO_FSEL_OUTP); // set the resetbutton to input bcm2835_gpio_fsel(resetbutton, BCM2835_GPIO_FSEL_INPT); // with a pullup bcm2835_gpio_set_pud(resetbutton, BCM2835_GPIO_PUD_UP); int counter; while (1) { counter = 0; while (counter < 16 ) { while ( !bcm2835_gpio_lev(resetbutton) ) { printf("reset button pushed\n"); LightsOn(15); counter = 0; } LightsOn( counter ); counter++; delay(1000); } } }
java
Java has been in the top ten most-used languages for years (for ever?) Here's the same process as above - coded with java.
// provision gpio pin #09 as an input pin with its internal pull up resistor enabled final GpioPinDigitalInput resetButton = gpio.provisionDigitalInputPin(RaspiPin.GPIO_09, PinPullResistance.PULL_UP); led1 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_29, PinState.LOW); led2 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_28, PinState.LOW); led4 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_27, PinState.LOW); led8 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_25, PinState.LOW); resetButton.addTrigger(new GpioCallbackTrigger(new Callable<Void>() { public Void call() { while(resetButton.isLow()) { System.out.println("button pressed"); turnLightsOn(15); lightCounter = 0; } turnLightsOn(0); return null; } } )); while(true) { lightCounter = 0; while (lightCounter < 16 ) { turnLightsOn(lightCounter); Thread.sleep(1000); lightCounter++; } } public static void turnLightsOn(int lightMask) { // 0 <= lightMask < 16 ... the number to represent in binary System.out.println("turnLightsOn: " + lightMask); led1.setState( (lightMask & 1) > 0 ); led2.setState( (lightMask & 2) > 0 ); led4.setState( (lightMask & 4) > 0 ); led8.setState( (lightMask & 8) > 0 ); }
Wolfram
led1=21 led2=20 led4=16 led8=26 resetbutton=3 DeviceConfigure["GPIO", { led1->"Output", led2->"Output", led4->"Output", led8->"Output", resetbutton -> "Input" }] turnlightson[lightmask_]:= ( Print["lightmask is ",lightmask]; DeviceWrite["GPIO", led1 -> Boole[BitAnd[lightmask,1]>0]]; DeviceWrite["GPIO", led2 -> Boole[BitAnd[lightmask,2]>0]]; DeviceWrite["GPIO", led4 -> Boole[BitAnd[lightmask,4]>0]]; DeviceWrite["GPIO", led8 -> Boole[BitAnd[lightmask,8]>0]] ) DeviceWrite["GPIO", ... led1 -> Boole[BitAnd[lightmask,1]>0]]; counter=0; Do[ ( counter=0; While[counter<16, ( While[DeviceRead["GPIO", resetbutton][resetbutton]==0, ( turnlightson[15]; counter=0; ) ]; turnlightson[counter]; counter++; Pause[1];
COBOL
IDENTIFICATION DIVISION. PROGRAM-ID. RPIwithCOBOL. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-GPIO-INIT PIC x(40) VALUE 'echo "21" > /sys/class/gpio/export'. 01 WS-GPIO-DIR PIC x(50) VALUE 'echo "out" > /sys/class/gpio/gpio21/direction'. 01 WS-GPIO-ON PIC x(40) VALUE 'echo "1" > /sys/class/gpio/gpio21/value'. 01 WS-GPIO-OFF PIC x(40) VALUE 'echo "0" > /sys/class/gpio/gpio21/value'. 01 WS-GPIO-ClR PIC x(40) VALUE 'echo "21" > /sys/class/gpio/unexport'. PROCEDURE DIVISION. display "This is COBOL running on a Raspberry Pi". display "Here's how to call GPIO from COBOL". CALL "SYSTEM" USING WS-GPIO-INIT. CALL "SYSTEM" USING WS-GPIO-DIR. PERFORM FLASH-LITE 3 TIMES. CALL "SYSTEM" USING WS-GPIO-CLR. STOP RUN. FLASH-LITE. CALL "SYSTEM" USING WS-GPIO-ON. display "LED is ON". CALL "C$SLEEP" USING 1. CALL "SYSTEM" USING WS-GPIO-OFF. display "LED is OFF". CALL "C$SLEEP" USING 1. END PROGRAM RPIwithCOBOL.
Minecraft
So - why is minecraft part of a programming language overview? Because you can control the GPIO with minecraft. Here's how...
# example code for raspberry pi portal # assumes a button for GPIO # thanks to https://www.stuffaboutcode.com/p/minecraft-api-reference.html from mcpi import minecraft, block, vec3 import gpiozero from colorzero import Color from time import sleep from signal import pause mc = minecraft.Minecraft.create() led = gpiozero.RGBLED(red=21, green=20, blue=16) button = gpiozero.Button(26) class portalStateObject: oneDefined ?= False twoDefined = False # keeps track of the state of two portals. # try if (portalState.oneDefined): etc def __init__(self): self.oneDefined = False self.twoDefined = False def setPortal(self, portalNumber, trueOrFalse): if (portalNumber == 1): self.oneDefined = trueOrFalse elif (portalNumber == 2): self.twoDefined = trueOrFalse else: raise ValueError("setPortal only accepts values for 1 or 2") class portal: def __init__(self, thePortalNumber, theColor): self.portalNumber = thePortalNumber self.portalPosition = vec3.Vec3(0,0,0) self.color = theColor portalState.setPortal(self.portalNumber, False) self.portalAlert("Ready to create portal {}".format(self.portalNumber), theColor = 'white') def createPortal(self): # Create a portal at current position x,y,z = mc.player.getPos() # get current player position self.portalPosition = vec3.Vec3(x-2, y, z) mc.setBlock(self.portalPosition, block.GLOWSTONE_BLOCK.id ) # complete list of block types at https://www.stuffaboutcode.com/p/minecraft-api-reference.html self.portalAlert("{}: Created portal {}".format(self.color, self.portalNumber)) def deleteThisPortal(self): # this would be useful pass def amIHere(self): x,y,z = mc.player.getPos() if (int(self.portalPosition.x - 1) <= int(x) <= int(self.portalPosition.x + 1) and int(self.portalPosition.y - 1) <= int(y) <= int(self.portalPosition.y + 1) and int(self.portalPosition.z - 1) <= int(z) <= int(self.portalPosition.z + 1 ) ): return(True) else: return(False) def goHere(self): # go to this portal mc.player.setPos(self.portalPosition.x + 2, self.portalPosition.y, self.portalPosition.z) self.portalAlert("Returned to portal {}".format(self.portalNumber), theColor = 'orange') def portalAlert(self, theMessage, theColor = 'tbd'): # message to chat, change LED to this portal color if (theColor == 'tbd'): theColor = self.color mc.postToChat(theMessage) led.pulse(on_color = Color(theColor)) # set up objects portalState = portalStateObject() # create an object we can use to track portal state portalOne = portal(1, "blue") portalTwo = portal(2, "red") def buttonHandler(): if (not portalState.oneDefined): portalOne.createPortal() portalState.setPortal(1, True) elif (not portalState.twoDefined): portalTwo.createPortal() portalState.setPortal(2, True) else: portalOne.goHere() button.when_pressed = buttonHandler # start watching minecraft while True: if (portalOne.amIHere()) : portalTwo.goHere() if (portalTwo.amIHere()) : portalOne.goHere() print("Here: {}, portalOne: {}, portalTwo: {}".format(mc.player.getPos(), portalOne.portalPosition, portalTwo.portalPosition) ) sleep(1) pause()
# assign buttons btnAlpha <- 15 # BCM numbering scheme btnGamma <- 14 LEDred <- 9 LEDblue <- 10 LEDgreen <- 11 while (doExampleOne) { getGPIOcmd <- paste("gpioget gpiochip0", btnAlpha) if (system(getGPIOcmd, intern = TRUE) == 0) { print("Alpha") setGPIOcmd <- paste0("gpioset --mode=time --sec=1 gpiochip0 ", LEDred,"=", sample(0:1,1), " ", LEDblue,"=", sample(0:1,1), " ", LEDgreen,"=", sample(0:1,1)) print(setGPIOcmd) system(setGPIOcmd) } getGPIOcmd <- paste("gpioget gpiochip0", btnGamma) if (system(getGPIOcmd, intern = TRUE) == 0) print("Gamma") } # control-Z stops the loop
BASIC
REM credit to Richard Thomas Russell, creator of BBC BASIC. REM https://www.rtrussell.co.uk REM details at https://www.raspberrypi.org/forums/viewtopic.php?t=175703 REM based on code at https://elinux.org/RPi_GPIO_Code_Samples#Direct_register_access INSTALL @lib$ + "gpiolib" INSTALL @lib$ + "stringlib" gpio% = FN_gpio_setup FOR pin% = 9 TO 11 PROC_gpio_inp(gpio%,pin%) PROC_gpio_out(gpio%,pin%) NEXT pin% previous% = %111110000000 FOR pattern% = %000000000000 TO %111111000000 STEP %10000000 PROC_gpio_clr(gpio%, (pattern% EOR previous%) AND NOT pattern%) PROC_gpio_set(gpio%, (pattern% EOR previous%) AND pattern%) previous% = pattern% WAIT 20 PRINT FN_tobase(gpio%!&34 >> 7 AND %11111, 2, 5) NEXT pattern% PROC_gpio_clr(gpio%, %111111000000) PRINT "Finished"
What are your thoughts? Which language do you use most often? Have you used any of these to control the Raspberry Pi?
LinkedIn [in]structor | Data Science Consulting
3 年Thanks for the shout-out Mark Niemann-Ross!
Nice work! I suspect ABAP is like Finnish, a strange syntax and language that does not correspond to any know patterns. ??