Device I/O Zero - IMU Sample App

Java Device I/O library with an API based on the Python GPIO Zero supporting portable across Single Board Computers (including Raspberry Pi, BeagleBone Black, Odroid C2, CHIP, Asus Tinker Board)

License

License

GroupId

GroupId

com.diozero
ArtifactId

ArtifactId

diozero-imu-sampleapp
Last Version

Last Version

0.14
Release Date

Release Date

Type

Type

jar
Description

Description

Device I/O Zero - IMU Sample App
Java Device I/O library with an API based on the Python GPIO Zero supporting portable across Single Board Computers (including Raspberry Pi, BeagleBone Black, Odroid C2, CHIP, Asus Tinker Board)
Project Organization

Project Organization

diozero

Download diozero-imu-sampleapp

How to add to project

<!-- https://jarcasting.com/artifacts/com.diozero/diozero-imu-sampleapp/ -->
<dependency>
    <groupId>com.diozero</groupId>
    <artifactId>diozero-imu-sampleapp</artifactId>
    <version>0.14</version>
</dependency>
// https://jarcasting.com/artifacts/com.diozero/diozero-imu-sampleapp/
implementation 'com.diozero:diozero-imu-sampleapp:0.14'
// https://jarcasting.com/artifacts/com.diozero/diozero-imu-sampleapp/
implementation ("com.diozero:diozero-imu-sampleapp:0.14")
'com.diozero:diozero-imu-sampleapp:jar:0.14'
<dependency org="com.diozero" name="diozero-imu-sampleapp" rev="0.14">
  <artifact name="diozero-imu-sampleapp" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.diozero', module='diozero-imu-sampleapp', version='0.14')
)
libraryDependencies += "com.diozero" % "diozero-imu-sampleapp" % "0.14"
[com.diozero/diozero-imu-sampleapp "0.14"]

Dependencies

compile (6)

Group / Artifact Type Version
com.diozero : diozero-core jar 0.14
com.diozero : diozero-imu-devices jar 0.14
org.apache.commons : commons-math3 jar 3.6.1
org.eclipse.paho : org.eclipse.paho.client.mqttv3 jar 1.2.5
org.tinylog : tinylog-api jar 2.1.2
org.tinylog : tinylog-impl jar 2.1.2

test (1)

Group / Artifact Type Version
org.junit.jupiter : junit-jupiter jar

Project Modules

There are no modules declared in this project.

DIOZero - a Java Device I/O wrapper for GPIO / I2C / SPI control

Build Status Maven Central Maven Central status License: MIT Javadoc Documentation Status

A Device I/O library written in Java that provides an object-orientated interface for a range of GPIO / I2C / SPI devices (LEDs, buttons, sensors, motors, displays, etc) connected to Single Board Computers like the Raspberry Pi. Actual GPIO / I2C / SPI device communication is delegated to pluggable service providers for maximum compatibility across different boards. This library is known to work on the following boards: all models of the Raspberry Pi, Odroid C2, BeagleBone Black, C.H.I.P and Asus Tinker Board. It should be portable to any Single Board computer that runs Linux and Java 8.

This library makes use of modern Java features such as automatic resource management, Lambda Expressions and Method References where they simplify development and improve code readability.

Created by Matt Lewis (email [email protected]) (blog), inspired by GPIO Zero and Johnny Five. If you have any issues please use the GitHub issues page. For any other comments or suggestions, please use the diozero Google Group.

Concepts

The aim of this library is to encapsulate real-world devices as classes with meaningful operation names, for example, LED (on / off), LDR (get luminosity), Button (pressed / released), Motor (forward / backwards / left / right). All devices implement Closeable hence will get automatically closed by the try (Device d = new Device()) { d.doSomething(); } statement. This is best illustrated by some simple examples.

Pin Numbering

All pin numbers are device native, i.e. Broadcom for the Raspberry Pi, ASUS for the Tinker Board. Pin layouts:

LED control:

try (LED led = new LED(pin)) {
	led.on();
	SleepUtil.sleepSeconds(.5);
	led.off();
	SleepUtil.sleepSeconds(.5);
	led.toggle();
	SleepUtil.sleepSeconds(.5);
	led.toggle();
	SleepUtil.sleepSeconds(.5);
	led.blink(0.5f, 0.5f, 10, false);
}

Turn on an LED when you press a button:

try (Button button = new Button(buttonPin, GpioPullUpDown.PULL_UP); LED led = new LED(ledPin)) {
	button.whenPressed(led::on);
	button.whenReleased(led::off);
	SleepUtil.sleepSeconds(10);
}

Or a random LED flicker effect:

Random random = new Random();
try (PwmLed led = new PwmLed(pin)) {
	DioZeroScheduler.getNonDaemonInstance().invokeAtFixedRate(RANDOM::nextFloat, led::setValue, 50, 50, TimeUnit.MILLISECONDS);
}

All devices are actually provisioned by a Device Factory with a default NativeDeviceFactory for provisioning via the host board itself. However, all components accept an optional Device Factory parameter for provisioning the same set of components via an alternative method. This is particularly useful for GPIO expansion boards and Analog-to-Digital converters.

!!! note "Device Factory" Unless you are implementing a new device you shouldn't need to use any of the Device Factory interfaces or helper classes (within the com.diozero.internal package).

Some boards like the Raspberry Pi provide no analog input pins; attempting to create an AnalogInputDevice such as an LDR using the Raspberry Pi default native device factory would result in a runtime error (UnsupportedOperationException). However, support for Analog to Digital Converter expansion devices such as the MCP3008 has been added which are implemented as analog input device factories hence can be used in the constructor of analog devices like LDRs:

try (McpAdc adc = new McpAdc(McpAdc.Type.MCP3008, chipSelect); LDR ldr = new LDR(adc, pin, vRef, r1)) {
	System.out.println(ldr.getUnscaledValue());
}

Repeating the previous example of controlling an LED when you press a button but with all devices connected via an MCP23017 GPIO expansion board:

try (MCP23017 mcp23017 = new MCP23017(intAPin, intBPin);
		Button button = new Button(mcp23017, inputPin, GpioPullUpDown.PULL_UP);
		LED led = new LED(mcp23017, outputPin)) {
	button.whenPressed(led::on);
	button.whenReleased(led::off);
	SleepUtil.sleepSeconds(10);
}

Analog input devices also provide an event notification mechanism. To control the brightness of an LED based on ambient light levels:

try (McpAdc adc = new McpAdc(McpAdc.Type.MCP3008, chipSelect); LDR ldr = new LDR(adc, pin, vRef, r1); PwmLed led = new PwmLed(ledPin)) {
	// Detect variations of 10%, get values every 50ms (the default)
	ldr.addListener((event) -> led.setValue(1-event.getUnscaledValue()), .1f);
	SleepUtil.sleepSeconds(20);
}

Supported Devices

diozero has out of the box support for the following Single Board Computers:

The builtin sysfs provider is designed to be portable across different boards. In addition, the JDK Device I/O providers add an alternative method of compatibility, for example on the Udoo Quad.

Getting Started

Snapshot builds of the library are available in the Nexus Repository Manager. For convenience a ZIP of all diozero JARs (currently v0.13) will also be available on Google Drive.

Javadoc for the core library is also available via javadoc.io.

Unfortunately Java doesn't provide a convenient deployment-time dependency manager such as Python's pip therefore you will need to manually download all dependencies and setup your classpath correctly. You can do this either via setting the CLASSPATH environment variable or as a command-line option (java -cp <jar1>:<jar2>). The dependencies have been deliberately kept to as few libraries as possible, as such this library is only dependent on tinylog v2.1.2.

To compile a diozero application you will need 3 JAR files - tinylog (API and Impl), and diozero-core. To run a diozero application, you can also include one of the supported device provider libraries and the corresponding diozero provider wrapper library. Note that the built-in sysfs device provider gives maximum portability but has some limitations such as not being able to configure internal pull up/down resistors.

SBC Provider Provider Jar diozero wrapper-library
All sysfs N/A Built-in
32bit boards JDK Device I/O 1.0 dio-1.0.1.jar diozero-provider-jdkdeviceio10-<version>.jar
32bit boards JDK Device I/O 1.1 dio-1.1.jar diozero-provider-jdkdeviceio11-<version>.jar
Raspberry Pi Pi4j pi4j-core-1.1.jar diozero-provider-pi4j-<version>.jar
Raspberry Pi wiringPi pi4j-core-1.1.jar diozero-provider-wiringpi-<version>.jar
Raspberry Pi pigpio pigpioj-java-1.0.1.jar diozero-provider-pigio-<version>.jar
Raspberry Pi, Odroid C2 mmap N/A diozero-provider-mmap-<version>.jar

To get started I recommend first looking at the classes in com.diozero.sampleapps. To run the LEDTest sample application using the pigpioj provider:

sudo java -cp tinylog-api-2.1.2.jar:tinylog-impl-2.1.2.jar:diozero-core-0.13.jar:diozero-sampleapps-0.13.jar:diozero-provider-pigpio-0.13.jar:pigpioj-java-2.4.jar com.diozero.sampleapps.LEDTest 12

For an experience similar to Python where source code is interpreted rather than compiled try Groovy (sudo apt-get update && sudo apt-get install groovy2). With the CLASSPATH environment variable set as per the instructions above, a simple test application can be run via the command groovy <filename>. There is also a Groovy shell environment groovysh.

A Groovy equivalent of the LED controlled button example:

import com.diozero.Button
import com.diozero.LED
import com.diozero.util.SleepUtil

led = new LED(12)
button = new Button(25)

button.whenPressed({ led.on() })
button.whenReleased({ led.off() })

println("Waiting for button presses. Press CTRL-C to quit.")
SleepUtil.pause()

To run:

sudo groovy -cp $CLASSPATH test.groovy

Groovy JAVA_HOME config when running via sudo

I was getting the error:

groovy: JAVA_HOME is not defined correctly, can not execute: /usr/lib/jvm/default-java/bin/java

I tried setting JAVA_HOME in /etc/environment and /etc/profile.d/jdk.sh to no affect. Eventually the following fixed it for me. Please let me know if there is a better way to fix this issue.

ln -s /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt /usr/lib/jvm/default-java

Devices

This library provides support for a number of GPIO / I2C / SPI connected components and devices, I have categorised them as follows:

Performance

I've done some limited performance tests (turning a GPIO on then off, see GpioPerfTest) on a Raspberry Pi 2 and 3 using the various native device factory providers. I've also run tests using JNI APIs directly without going via my DIO-Zero wrapper to assess the overhead of using my library (see WiringPiRawPerfTest and PigpioPerfTest) - the overhead of DIO-Zero is approximately 25% for both pigpio and wiringPi. Here are the results:

Provider Device Frequency (kHz)
Pi4j 1.0 Pi2 0.91
JDK DIO 1.1 Pi2 8.23
Pi4j 1.1 Pi2 622
pigpio Pi2 2,019
pigpio Pi3 2,900
pigpio (JNI) Pi2 2,509
pigpio (JNI) Pi3 3,537
wiringPi Pi2 2,640
wiringPi Pi3 3,446
wiringPi (JNI) Pi2 3,298
wiringPi (JNI) Pi3 4,373
mmap Pi3 7,686
mmap (JNI) Pi3 11,007

Performance

For a discussion on why Pi4j 1.0 was so slow, see this issue. These results are in-line with those documented in the book "Raspberry Pi with Java: Programming the Internet of Things". For reference, the author's results were:

Library Frequency (kHz)
Pi4j 1.0 0.751
JDK DIO 1.0 3.048
wiringPi (direct) 1,662

Development

This project is hosted on GitHub, please feel free to join in:

To-Do

  • Thorough testing (various types of devices using each service provider)
  • A clean object-orientated API for IMUs
  • Remote API for board capabilities
  • SPI support for Arduino devices
  • Introduce Servo as a device type
  • Try out ConfigurableFirmata - is there actually any difference to the StandardFirmata protocol?
  • Create a Maven archetype
  • Check docs (.md and Javadoc) regarding constructors with device factories
  • DONE Complete ADS1x15
  • DONE I2C Javadoc - make it clear regarding SMBus 32 byte limits
  • DONE BME680
  • DONE Native support for all devices via mmap (/dev/gpiomem), in particular to improve performance and add support for GPIO pull up/down configuration.
  • DONE Wireless access to Firmata devices (network and Bluetooth). E.g. ESP32 Firmata GitHub issue #315

Release History

License

This work is provided under the MIT License.

Versions

Version
0.14
0.13
0.12
0.11
0.10
0.9
0.8
0.7
0.6