Sunday, July 14, 2019

Robo4J: Adafruit LED Backpacks - guide

Img.1.: Robo4J with Adafruit LED Backpacks
  In the following blog post I will describe how to use the Adafruit LED Backpacks together with Robo4J framework. All mentioned examples are running on Java11+ and as you will see, they are very easy to implement, modify and connect with even more advanced systems.

Inspired by a motto : Plug&Play.  

It's a lot of fun to have all those LEDs under the control and due to Robo4J you don't have to use C++ example, just a pure Java ... 

  The Adafruit is quite great company,  they do provide a lot of easy to implement breakout boards for RaspberryPi platform. One of them are LED Backpacks
  Robo4J does contain  implementations for Bargraphs, Matrixes and Alphanumeric ones. The agenda: 
  1. Bi-Color 24 Bargraph
  2. Bi-Color 8x8 Matrix
  3. 0.54" Alphanumeric
To assemble any of backpacks I'd recommend to go through the well described manuals on the official Adafruit web pages

example requirements:
1. RaspberryPi3 B+ 
2. Java 11 (example: Bell-Soft Liberica 11+)
3. one of Adafruit LED Backpack 

  Before we enjoy a LED shows, let's take a quick look how all is bundled. It should give you an idea how to connect LEDs in other than discussed cases. 
  As you know Robo4J is a light weight messaging framework. It's separated to the dedicated modules according to the purpose. In following blog post we do use robo4j-core, robo4j-units-rpi and robo4j-hw-rpi as you can see in the diagram bellow. The all three mentioned I2C examples are by default configured as following: 


int bus = I2CBus.BUS_1;
int address =  0x70;\

Important: If you intent to use only the robo4j-hw-rpi, it means only the hardware, the module can be used alone without any additional dependencies.
Img.2.: Robo4J Adafruit backpack schema

Let's suppose we have all assembled and we start with the 1st Bi-Color 24 Bargraph.

1. Bi-Color 24 Bargraph
Img.3.: Bi-Color24 Bargraph example
We have connected the device over the I2C interface to the RaspberryPi according to the Adafruit Documentation. As the first step we test the hardware, let's create a simple example that uses only the robo4j-hw-rpi module. :


public class BiColor24BargraphExample {
  public static void main(String[] args) throws Exception {
    BiColor24BarDevice device = new BiColor24BarDevice();
device.clear();
device.display();

int counter = 0;

while(counter < 3){
  for (int i=0; i<12; i++){
    int colorNumber = (i+counter) % 3 + 1;
    XYElement element = new XYElement(i, BiColor.getByValue(colorNumber));
    device.addBar(element);
    TimeUnit.MILLISECONDS.sleep(200);
    device.display();
  }
  counter++;
}
  }
}
The code above (Img.1.) shows how the elements are created and send to the Robo4j hardware unit. 
The next example snippet shows how the Robo4J hardware is exposed to the units from robo4j-units-rpi module. The following module offers more advanced features upon the hardware, like command or continual operations, which allows more advanced usages.


RoboContext ctx = new RoboBuilder().add(settings).build();
ctx.start();
RoboReference<LEDBackpackMessage> barUnit = ctx.getReference("bargraph");
LEDBackpackMessage<XYElement> clearMessage = new LEDBackpackMessage<>();
AtomicInteger position = new AtomicInteger();
executor.scheduleAtFixedRate(() -> {
  if (position.get() > BiColor24BarDevice.MAX_BARS - 1) {
    position.set(0);
  }
  barUnit.sendMessage(clearMessage);
  XYElement element = new XYElement(
    position.getAndIncrement(),
    BiColor.getByValue(position.get() % 3 + 1));
  LEDBackpackMessage<XYElement> addMessage = new LEDBackpackMessage<>(LEDBackpackMessageType.DISPLAY);
  addMessage.addElement(element);
  barUnit.sendMessage(addMessage);


}, 2, 1, TimeUnit.SECONDS);

Congratulation the 1.st LED Backpack is in use and running! 

2.Bi-Color 8x8 Matrix
Img.4.: Bi-Color 8x8 Matrix Face example
The 2nd example is Bi-Color 8x8 LED Matrix. It is really a lot of fun as you can display a simple images or animations. The Matrix is provided exactly in the same manner as the previous example. The hardware can be use only by robo4j-hw-rpi module to make hardware testing simpler, quicker and more fun ;). Here is the simple code snippet:


char[] faceSmile = "00333300,03000030,30300303,30000003,
    30300303,30033003,03000030,00333300".toCharArray();
...
List<char[]> availableFaces = Arrays.asList(faceSad, faceNeutral, faceSmile);
for (char[] face : availableFaces) {
  matrix.clear();
  matrix.display();
  byte[] faceByte = LEDBackpackUtils.createMatrixBiColorArrayByCharSequence(
    matrix.getMatrixSize(), ',',face);
    XYElement[] faceElements = LEDBackpackUtils.createMatrixByBiColorByteArray(matrix.getMatrixSize(), faceByte);
    matrix.addPixels(faceElements);
    matrix.display();
    TimeUnit.SECONDS.sleep(1);
}
  
Having the hardware tested we can move the the robo4j-units-rpi module and enjoy a bit advanced hardware usages. Now we have an opportunity to connect the units with another ones and create a more advanced system based on messages passing, see a example snippet bellow:


RoboContext ctx = new RoboBuilder().add(settings).build();
ctx.start();
RoboReference<LEDBackpackMessage> barUnit = ctx.getReference("matrix");
LEDBackpackMessage<XYElement> clearMessage = new LEDBackpackMessage<>();
AtomicInteger position = new AtomicInteger();
executor.scheduleAtFixedRate(() -> {
   if (position.get() > 7) {
   position.set(0); }
  barUnit.sendMessage(clearMessage);
  XYElement element = new XYElement(
    position.get(), position.getAndIncrement(),
    BiColor.getByValue(position.get() % 3 + 1));
    LEDBackpackMessage<XYElement> addMessage = 
        new LEDBackpackMessage<>(LEDBackpackMessageType.DISPLAY);
    addMessage.addElement(element);
    barUnit.sendMessage(addMessage);

}, 2, 1, TimeUnit.SECONDS);


3. 0.54" Alphanumeric
Img.5.: Adafruit Alphanumeric LED Backpack
 The previous examples were only about to just turning on/off a specific LED diodes. The last example shows how to display ASCII Characters on 14-segments (Img.6.) display (see wiki). The value can be transmitted as the ASCII character of specific segments can be turned off/on as is visible from the picture above (Img.5.). 
Img.6.: 14-segments LED (source: Adafruit)
The robo4j-hw-rpi module provides an example that shows how to configure and run Adafruit hardware:

AlphanumericDevice device = new AlphanumericDevice();
device.clear();
device.display();
device.addCharacter('R', false);
device.addCharacter('O', true);
device.addCharacter('B', false);
device.addByteValue((short) 0x3FFF, true);
device.display();

It looks very simple. It's possible to add the value by the character reference on by its 16-bit value. The module robo4j-units-rpi, similar as in previous cases, provides a advanced features that can be used for controlling the Alphanumeric LED Backpack, see the code bellow: 

RoboContext ctx = new RoboBuilder().add(settings).build();
ctx.start();
RoboReference<LEDBackpackMessage> alphaUnit = ctx.getReference("alphanumeric");
LEDBackpackMessage<AsciElement> clearMessage = new LEDBackpackMessage<>();
LEDBackpackMessage<AsciElement> displayMessage = new LEDBackpackMessage<>(LEDBackpackMessageType.DISPLAY);
AtomicInteger textPosition = new AtomicInteger();
executor.scheduleAtFixedRate(() -> {
    if(textPosition.getAndIncrement() >= MESSAGE.length - 1){
        textPosition.set(0);
    }
    alphaUnit.sendMessage(clearMessage);
    LEDBackpackMessage<AsciElement> messageAdd = new LEDBackpackMessage<>(LEDBackpackMessageType.ADD);
    char currentChar =  MESSAGE[textPosition.get()];
    adjustBuffer(currentChar);
    messageAdd.addElement(new AsciElement(0, BUFFER[0], false));
    messageAdd.addElement(new AsciElement(1, BUFFER[1], false));
    messageAdd.addElement(new AsciElement(2, BUFFER[2], false));
    messageAdd.addElement(new AsciElement(3, BUFFER[3], false));
    alphaUnit.sendMessage(messageAdd);
    alphaUnit.sendMessage(displayMessage);
}, 1, 500, TimeUnit.MILLISECONDS);

The final words and conclusion
 The Robo4j framework delivers easy to use hardware abstractions. Such abstractions are exposed through the Robo4j units. The Units provide an additional functionalities (example: simple matrix operation, bargraph led selection etc.) The Robo4j Units allow to employ scheduled or time based operations. All units can be extended about any features/possibilities provided by the Java Ecosystem. 

The Robo4j Adafruit LED Backpack implementation gives a power to create any LED show.
Enjoy and Happy Coding ! 

No comments: