Raspberry Coffee
The best way to predict the future is to invent it. (Alan Kay)
Several Raspberry PI projects in Java, Scala, Groovy, Kotlin, and whatever knows about a JVM...
Important: This document goes along with the code at https://github.com/OlivierLD/raspberry-pi4j-samples.
A vast majority of the code availale to reach various components from the Raspberry PI is often written in Python, and next in C (using Wiring PI).
We will not argue here about which language is the best for your needs (this is close to a religious matter!), but in case you want to use Java or a JVM-aware language, this project is here to help. It gathers the code I
have been using to reach various boards and devices. They all rely on PI4J.
The setup of the Raspberry PI is not Java related, but it is to be done anyway.
Now the Raspberry PI is good to go.
The projects below are mostly written in Java, using PI4J.
Some of the projects below come with their C equivalent, for those interested in compairing...
Interestingly, PI4J is based on Wiring PI (a C library), through javah.
Cool links
Fritzing, Autodesk Circuits.
Summary of the code snippets and libraries
Java
Scala
Groovy
Kotlin
Clojure
-
Analog to Digital
-
Serial
-
Misc
- Drive the Raspberry PI through emails
-
Use a relay, to turn appliances on and off
- Remote debugging and profiling on the Raspberry PI
- Use a HT16K33, src (I2C 7-segment LED backpack)
- Use a MCP4725 (I2C Digital to Analog Converter (DAC), with an example)
- Pulse Width Modulation (PWM) from the Raspberry PI, with an example
- A joystick driving 2 servos, with an example
- Monochrome 128x32 OLED display (SSD1306) SPI, with an example
- Monochrome 84x48 Nokia 5110/3110 display (PCD8544) SPI, src
-
Use a 3x4 phone-style matrix keypad (src)
Uses the GpioPinDigitalMultipurpose PI4J class.
The wiring is explained in the comments of the code.
-
Read from and write to an Arduino (Uno) from the Raspberry PI, using the USB (Serial) port.
Real-time Arduino reads analog sensors, and returns their values to the Raspberry PI (using an NMEA custom sentence).
-
There is in the code repository an example combining a phone keypad and an OLED display. Look in
RasPISamples, see raspisamples.OLEDScreenAndKeypad.
Another example shows how to read several sensors and an Arduino, and display their data on a OLED display, using the keypad to interact with the program. See raspisamples.OLEDKeypadAndMultiSensor.
-
Communicate with an Arduino Uno
- Read data from an Arduino
- Read and Write data to an Arduino
- Raspberry PI communicates with Arduino(s) using I2C, src.
In the output below, 0x04 is the address assigned to the Arduino.
Prompt> sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- 04 -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
- Run Hadoop 2.0.6 on the Raspberry PI
- Use a PIR (Motion Sensor), src
- FONA (Cell Shield), src, details
- Java to C communication: JNI, an example/tutorial.
- AlaMode from Java. Raspberry Pi piggybacking an Arduino-like board. src
- NeuroSky's MindWave from Java. src
-
Servos and Motors
- Use a PCA9685 (I2C Servo driver)
-
Use a PCA9685 (I2C Servo driver) to drive a MeArm
See this demo.
- Use a PCA9685, over the Internet, and from Android
-
Very cool to build a robot: Use an Adafruit Motor HAT (similar to PCA9685) (implementation, and samples).
A more elaborated sample, driving the robot (Adafruit Motor HAT) from a browser, using WebSockets on node.js. Works from laptop, smartphones, tablets... Also produces a QR code, convenient to reach the URL from a smartphone or a tablet.
See here for the java code, and here for the node.js part (scripts and html). The shell script to start is robot.pilot.
-
Sensors
- Use a LSM303 (I2C Accelerometer and Magnetometer)
-
Use a BMP180 (I2C Pressure and Altitude, Temperature)
- Use a BMP183 (SPI Pressure and Temperature) src
-
Use a MCP9808 (I2C high precision thermometer) src
This one reads 16-bit words from its registers.
- Use a TCS34725 (I2C color sensor, with an example)
- Use a TSL2561, src (I2C light sensor)
- Use a VCNL4000, src (I2C proximity sensor)
- Use a L3GD20 (I2C gyroscope, with an example)
- Ultrasonic range sensor (HC-SR04), with an example
-
Use a Humidity/Temperature sensor, HTU21D-F, src (I2C)
Yet another way to read the registers.
- Use an I2C high precision thermometer and barometer (MPL115A2), src
- Use an I2C Triple-Axis Magnetometer (HMC5883L), src
- BME280 (Temperature, pressure, humidity, replaces both the BMP180 and HTU21D-F) from Java. src
- A real world project: a Water Level Detector (with custom hardware and MCP3008)
- SwitchDocLabs Weather Station, with details.
- REST API in Java for Adafruit-IO, IoT server.
- This project contains a tiny REST Server, that runs even on a Raspberry PI Zero.
|
|
Install Scala as mentioned here, and you're good to go!
Another fine way to install Scala (2.11) and sbt is here:
Prompt> sudo apt-get remove scala-library scala
Prompt> sudo wget www.scala-lang.org/files/archive/scala-2.11.4.deb
Prompt> sudo dpkg -i scala-2.11.4.deb
Prompt> sudo apt-get update
Prompt> sudo apt-get install scala
Prompt> sudo wget https://bintray.com/artifact/download/sbt/debian/sbt-0.13.6.deb
Prompt> sudo dpkg -i sbt-0.13.6.deb
Prompt> sudo apt-get update
Prompt> sudo apt-get install sbt
Scala classes are actually Java classes, and as such, run on a Java Virtual Machine.
Scala can be used to program the Raspberry PI, just like Java can.
-
Scala 101, read a BME280 from Scala (src)
See the script named run.scala.pubsub in here.
It also works with the Scala REPL. See the Scala worksheets, suffixed with .sc in the scala.worksheets directory.
|
|
Install Groovy on the PI
Prompt> sudo apt-get install groovy
and you're good to go!
Groovy runs on a Java Virtual Machine.
Groovy can be used to program the Raspberry PI, just like Java can.
|
|
Install Kotlin on the PI, as explained here. The manual install works fine. Modify your path after that (as explained in the link above), and you're good to go.
Kotlin runs on a Java Virtual Machine.
Kotlin can be used to program the Raspberry PI, just like Java can.
-
Kotlin 101, read a BME280 from Kotlin (src)
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $ ./runSensors
Temp:23.418814 °C, Press:1018.09607 hPa, Hum:64.762695 %
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $ PI4J_HOME=/opt/pi4j
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $ CP=../../../I2C.SPI/build/classes/main/
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $ CP=$CP:$PI4J_HOME/lib/pi4j-core.jar
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $ sudo `which kotlinc-jvm` -cp $CP
Welcome to Kotlin version 1.0.3 (JRE 1.8.0_65-b17)
Type :help for help, :quit for quit
>>> import i2c.sensor.BME280
>>> val bme280 = BME280()
>>> val temp = bme280.readTemperature()
>>> println("Temp= $temp \u00baC")
Temp= 23.80598 °C
>>> :quit
pi@raspi-dev ~/raspberry-pi4j-samples/OtherJVM.languages/scripts/kotlin $
|
|
Real world projects and articles
(Using the above)
Some possibly useful hints...
Different breakout boards - specially the I2C ones - have different endianness (little endian, big endian). This is usually clearly taken care of in the code. For example:
public final static int LITTLE_ENDIAN = 0;
public final static int BIG_ENDIAN = 1;
private final static int TCS34725_ENDIANNESS = BIG_ENDIAN;
and the methods used to read some several-byte words are written this way:
private int readU16(int register) throws Exception {
int lo = this.readU8(register);
int hi = this.readU8(register + 1);
int result = (TCS34725_ENDIANNESS == BIG_ENDIAN) ? (hi << 8) + lo : (lo << 8) + hi;
// ...
return result;
}
Notice above that the device this snippet of code is about (TCS34725) delivers two 8-bit words from two different registers (register and register + 1). Then those two 8-bit words (aka bytes) are arranged according to their endianness.
Some other devices (like the MCP9808) deliver 16-bit words (2 bytes) from one register. Then the two bytes are arranged according to their endianness.
public int readU16BE(int register) throws Exception {
final int TWO = 2;
byte[] bb = new byte[TWO];
int nbr = this.mcp9808.read(register, bb, 0, TWO);
if (nbr != TWO)
throw new Exception("Cannot read 2 bytes from register 0x" + lpad(Integer.toHexString(register), "0", 2));
if (verbose)
System.out.println("I2C: 0x" + lpad(Integer.toHexString(bb[0]), "0", 2) + lpad(Integer.toHexString(bb[1]), "0", 2));
return ((bb[0] & 0xFF) << 8) + (bb[1] & 0xFF);
}
In the i2c-tool package, there are several utilities proven very helpful:
i2cdetect
i2cdump
i2cget
i2cset
The i2cget happens to be quite helpful in this area. See the following command:
Prompt> sudo i2cget -y 1 0x18 0x05 w
Without having to write any code, it will read on the bus 1, the device at the address 0x18, from register 0x05 a word (16 bits). Based on the value you expect, you would know whether to read one or two registers, and one or two bytes. Then you would know how to write your code.
Some useful commands...
Prompt> route
Prompt> sudo netstat -tunap
Prompt> sudo iwlist wlan0 scan
Prompt> pcmanfm --desktop-pref
Prompt> apt-get remove motion
Prompt> sudo dpkg-reconfigure console-setup
Prompt> sudo iwlist --help
Prompt> wpa_cli
> scan
> scan_results
> add_network
4
> set_network 4 ssid "RPiNet"
> set_network 4 psk "Password"
> quit
Prompt>
Prompt> sudo apt-get install arp-scan
Prompt> sudo arp-scan --localnet --interface=wlan0
GPIO
Try this:
Prompt> gpio readall
+-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| | | 3.3v | | | 1 || 2 | | | 5v | | |
| 2 | 8 | SDA.1 | ALT0 | 1 | 3 || 4 | | | 5V | | |
| 3 | 9 | SCL.1 | ALT0 | 1 | 5 || 6 | | | 0v | | |
| 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 1 | ALT5 | TxD | 15 | 14 |
| | | 0v | | | 9 || 10 | 1 | ALT5 | RxD | 16 | 15 |
| 17 | 0 | GPIO. 0 | IN | 1 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 |
| 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | |
| 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 1 | OUT | GPIO. 4 | 4 | 23 |
| | | 3.3v | | | 17 || 18 | 1 | OUT | GPIO. 5 | 5 | 24 |
| 10 | 12 | MOSI | OUT | 0 | 19 || 20 | | | 0v | | |
| 9 | 13 | MISO | ALT0 | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 |
| 11 | 14 | SCLK | OUT | 0 | 23 || 24 | 1 | OUT | CE0 | 10 | 8 |
| | | 0v | | | 25 || 26 | 1 | OUT | CE1 | 11 | 7 |
| 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 |
| 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | |
| 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 |
| 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | |
| 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 |
| 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 |
| | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 |
+-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
| BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM |
+-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+
Prompt>
Bonus
Not strictly JVM related, but there is this project, targeting the same features as this one, but with node.js. You write your code in JavaScript. Very cool too.