Pages

August 17, 2016

Automatic orientation of Sense HAT display

In this post I will show you how to automatically detect the position of the Raspberry PI using the Sense HAT accelerometer sensor and rotate the display accordingly.

The auto_rotate_display function in the script below is doing all the logic. It's reading sensors data to detect the orientation and rotating the Sense HAT display by calling the set_rotation function.

import time
from sense_hat import SenseHat

MSG_COLOR = [200,0,160]
BKG_COLOR = [0,0,0]
SCROLL_SPEED = 0.06
MESSAGE = "Can't loose my head"


def auto_rotate_display():
  # read sensors data to detect orientation
  x = round(sense.get_accelerometer_raw()['x'], 0)
  y = round(sense.get_accelerometer_raw()['y'], 0)

  rot = 0
  if x == -1:
    rot=90
  elif y == -1:
    rot=180
  elif x == 1:
    rot=270

  # rotate the display according to the orientation
  print ("Current orientation x=%s y=%s  rotating display by %s degrees" % (x, y, rot))
  sense.set_rotation(rot)


sense = SenseHat()

while True:
  auto_rotate_display()
  sense.show_message(MESSAGE, scroll_speed=SCROLL_SPEED, text_colour=MSG_COLOR, back_colour=BKG_COLOR)
  time.sleep(1)


Accurate temperature reading from Raspberry PI Sense HAT

When I first received the Sense HAT for my Raspberry PI 3 I decided to start building a nice weather station using the embedded environmental sensors and RGB LED matrix.
From a quick experiment it turns out that the temperature readings are not accurate. The problem is caused by thermal conduction from the Pi CPU to the humidity and pressure sensors on the Sense HAT.
I have experimented few algorithms and I have found the following formula to be the most reliable. It basically compensate the temperature reading (t) with the CPU temperature (tCpu).
tCorr = t - ((tCpu-t)/1.5)

Here is the full script to print each 5 seconds the environmental data including the corrected temperature.

import os
import time
from sense_hat import SenseHat

def get_cpu_temp():
  res = os.popen("vcgencmd measure_temp").readline()
  t = float(res.replace("temp=","").replace("'C\n",""))
  return(t)


sense = SenseHat()

while True:
  t = sense.get_temperature_from_humidity()
  t_cpu = get_cpu_temp()
  h = sense.get_humidity()
  p = sense.get_pressure()

  # calculates the real temperature compesating CPU heating
  t_corr = t - ((t_cpu-t)/1.5)
  
  print("t=%.1f  t_cpu=%.1f  t_corr=%.1f  h=%d  p=%d" % (t, t_cpu, t_corr, round(h), round(p)))
  
  time.sleep(5)

Running this script I have noticed that the CPU temperature reading is not very stable making the corrected temperature a little bit unstable. To fix this issue I have decided to apply a moving average to the temperature reading.
As a further improvement I'm also the temperature both from the humidity and pressure sensors and calculating the average.

import os
import time
from sense_hat import SenseHat

# get CPU temperature
def get_cpu_temp():
  res = os.popen("vcgencmd measure_temp").readline()
  t = float(res.replace("temp=","").replace("'C\n",""))
  return(t)

# use moving average to smooth readings
def get_smooth(x):
  if not hasattr(get_smooth, "t"):
    get_smooth.t = [x,x,x]
  get_smooth.t[2] = get_smooth.t[1]
  get_smooth.t[1] = get_smooth.t[0]
  get_smooth.t[0] = x
  xs = (get_smooth.t[0]+get_smooth.t[1]+get_smooth.t[2])/3
  return(xs)


sense = SenseHat()

while True:
  t1 = sense.get_temperature_from_humidity()
  t2 = sense.get_temperature_from_pressure()
  t_cpu = get_cpu_temp()
  h = sense.get_humidity()
  p = sense.get_pressure()

  # calculates the real temperature compesating CPU heating
  t = (t1+t2)/2
  t_corr = t - ((t_cpu-t)/1.5)
  t_corr = get_smooth(t_corr)
  
  print("t1=%.1f  t2=%.1f  t_cpu=%.1f  t_corr=%.1f  h=%d  p=%d" % (t1, t2, t_cpu, t_corr, round(h), round(p)))
  
  time.sleep(5)

Display two digits numbers on the Raspberry PI Sense HAT

Here is a small Python script to display two digits numbers on the Raspberry PI Sense HAT led matrix.

The script is very useful if you want to display humidity and temperature without scrolling.


The show_number function accepts the number to be displayed and RGB values of the color to be used.
Here is the full script.

from sense_hat import SenseHat
import time

OFFSET_LEFT = 1
OFFSET_TOP = 2

NUMS =[1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,  # 0
       0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,  # 1
       1,1,1,0,0,1,0,1,0,1,0,0,1,1,1,  # 2
       1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,  # 3
       1,0,0,1,0,1,1,1,1,0,0,1,0,0,1,  # 4
       1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,  # 5
       1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,  # 6
       1,1,1,0,0,1,0,1,0,1,0,0,1,0,0,  # 7
       1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,  # 8
       1,1,1,1,0,1,1,1,1,0,0,1,0,0,1]  # 9

# Displays a single digit (0-9)
def show_digit(val, xd, yd, r, g, b):
  offset = val * 15
  for p in range(offset, offset + 15):
    xt = p % 3
    yt = (p-offset) // 3
    sense.set_pixel(xt+xd, yt+yd, r*NUMS[p], g*NUMS[p], b*NUMS[p])

# Displays a two-digits positive number (0-99)
def show_number(val, r, g, b):
  abs_val = abs(val)
  tens = abs_val // 10
  units = abs_val % 10
  if (abs_val > 9): show_digit(tens, OFFSET_LEFT, OFFSET_TOP, r, g, b)
  show_digit(units, OFFSET_LEFT+4, OFFSET_TOP, r, g, b)


################################################################################
# MAIN

sense = SenseHat()
sense.clear()

for i in range(0, 100):
  show_number(i, 200, 0, 60)
  time.sleep(0.2)

sense.clear()

June 3, 2016

Raspberry PI - Arduino communication over USB serial

The Raspberry Pi is a fine little computer board with a lot of features and very good connectivity especially on version 3 with the integrated WiFi.
However, when dealing with I/O and sensors has a lot of limitations and is lacking the reliability of Arduino board and availability of libraries to interface it with any kind of device or sensor.

That's why I have decided to develop my own approach to integrate the two famous boards to fulfill my own set of requirements:
  • Use Raspberry Pi as a master device to develop the main application and connect to the Internet.
  • Use Java on the Raspberry Pi. This may sound a strange choice but I'm planning to use it to build an OSGi application for IoT.
  • Use Arduino board as a slave device to interact with several sensors.
  • Use a simple USB cable to power the Arduino board and exchange data.


This tutorial explains how to connect Arduino board to a Raspberry PI using a simple USB cable. This will power the Arduino and provide a serial communication between the two little boards.


Arduino


First step is to load and test the Arduino sketch to allow to retrieve the current milliseconds and toggle the on-board LED as described in this article.



Raspberry PI 

First step is to free the serial interface on the RasPI disabling shell and kernel messages via UART.
Run raspi-conf utility from the command prompt:

$ sudo raspi-config

Identify the Serial option and disable it. If is in the advanced menu in recent versions of Raspbian (9, A8).



Enter the following command to reboot your Raspberry Pi board:

$ sudo reboot


Install RxTx library

On the Raspberry PI side we will use the RxTx library. Install it with the following command:

sudo apt-get install librxtx-java

You can see that the native libraries are installed into the /usr/lib/jni directory and the java client is installed in /usr/share/java.

ls -la /usr/lib/jni/librxtx*
ls -la /usr/share/java/RXTX*


Java app

Import this Java project into Eclipse and build it. It is a slightly improved version of the official RxTx sample.
Now copy the three generated class files to your Raspberry Pi device into the /home/pi directory and run the following command:

java -Djava.library.path=/usr/lib/jni -cp /usr/share/java/RXTXcomm.jar:. ArduRasPi /dev/ttyUSB0 9600

This will run the ArduRasPi program connecting to Arduino on the /dev/ttyUSB0 port and 9600 baud.

You should now be able to issue commands to Arduino and receive the correct answer.





References

Arduino Vs. Raspberry Pi: Which Is The Right DIY Platform For You?
Control an Arduino from Java
Raspberry PI reads and writes data from Arduino, in Java
Arduino and Java

May 25, 2016

Interact with Arduino through serial

In this post I will show how to use the USB serial interface to issue commands and retrieve output from an Arduino board. The main goal of this project is to build a simple interface to use Arduino as a 'sensors hub' and integrate it with other more complex devices like Raspberry PI or and PC.

Now plug your Arduino board to the PC and upload the following sketch.


int PIN_LED = 13;

void setup()
{
  pinMode(PIN_LED, OUTPUT);
  
  Serial.begin(9600);

  Serial.println("Welcome to ArduinoSerialControl");
  Serial.println("Enter 't' to retrieve current millis");
  Serial.println("Enter 'l' to toggle LED on pin 13");
}

void loop()
{
  int bytes=Serial.available();
  if (bytes > 0)
  {
    char c = Serial.read();
    switch (c)
    {
    case 't':
      // return the uptime in milliseconds
      Serial.print("millis=");
      Serial.println(millis());
      break;
    case 'l':
      // toggle on-board led connected to pin 13
      digitalWrite(PIN_LED, !digitalRead(PIN_LED));
      Serial.print("LED status is ");
      Serial.println(digitalRead(PIN_LED));
      break;
    }
  }
}


Open the serial monitor and set the baud rate to 9600. Try sending commands using the serial console.



This is just an experiment. If you want to build a solid communication using Firmata protocol.

Complete Control Of An Arduino Via Serial

January 9, 2016

Nativity scene with Arduino and ALA library

Here are my last creations with Arduino and my ALA library.
An Arduino Uno board is driving a WS2812 RGB LED strip and some other LEDs through a TLC5940 chip. The full sketch is less than 100 rows of code!

Normal version




Disco version




Arduino sketch


#include "AlaLed.h"
#include "AlaLedRGB.h"

#define DAY_LEN 12000

AlaLed houses1;
AlaLed houses2;
AlaLedRgb rgbStrip;

AlaColor palRed_[] = { 0xFF0000 };
AlaPalette palRed = { 1, palRed_ };
AlaColor palBlue_[] = { 0x0000FF };
AlaPalette palBlue = { 1, palBlue_ };
AlaColor palGreen_[] = { 0x00FF00 };
AlaPalette palGreen = { 1, palGreen_ };

// RGB palette with black
AlaColor alaPalRgbBlack_[] = { 0xFF0000, 0x000000, 0x00FF00, 0x000000, 0x0000FF, 0x000000 };
AlaPalette alaPalRgbBlack = { 6, alaPalRgbBlack_ };

AlaSeq houses1Seq[] =
{
  { ALA_FADEOUT,          1000, 1000 },
  { ALA_FADEOUT,          1000, 1000 },
  { ALA_FADEOUT,          1000, 1000 },

  { ALA_PIXELSMOOTHSHIFTRIGHT,  800, DAY_LEN },
  { ALA_PIXELSMOOTHBOUNCE,1000, DAY_LEN },
  { ALA_STROBO,            400, DAY_LEN },
  { ALA_SPARKLE,           800, DAY_LEN },
  
  { ALA_STROBO,           1000, 3000 },
  { ALA_FADEOUT,          1000, 1000 },
  { ALA_OFF,              5000, 5000 },
  { ALA_ENDSEQ,              0,    0 }
};

AlaSeq houses2Seq[] =
{
  { ALA_FADEOUT,          1000, 1000 },
  { ALA_FADEOUT,          1000, 1000 },
  { ALA_FADEOUT,          1000, 1000 },

  { ALA_GLOW,              800, DAY_LEN },
  { ALA_SPARKLE2,          500, DAY_LEN },
  { ALA_STROBO,            400, DAY_LEN },
  { ALA_SPARKLE,           1000, DAY_LEN },
  
  { ALA_STROBO,           1000, 3000 },
  { ALA_FADEOUT,          1000, 1000 },
  { ALA_OFF,              5000, 5000 },
  { ALA_ENDSEQ,              0,    0 }
};

AlaSeq rgbStripSeq[] =
{
  { ALA_FADEOUT,          1000, 1000, palRed },
  { ALA_FADEOUT,          1000, 1000, palBlue },
  { ALA_FADEOUT,          1000, 1000, palGreen },

  { ALA_MOVINGGRADIENT,   2000, DAY_LEN, alaPalRgbBlack },
  { ALA_LARSONSCANNER,    3000, DAY_LEN, palBlue },
  { ALA_LARSONSCANNER2,    800, DAY_LEN, palRed },
  { ALA_SPARKLE,          3000, DAY_LEN, alaPalParty },

  { ALA_STROBO,           1000, 3000, palBlue },
  { ALA_FADEOUT,          1000, 1000, palBlue },
  { ALA_OFF,              5000, 5000 },
  { ALA_ENDSEQ,              0,    0 }
};

byte houses1Pin[] = { 1,3,4,2 };
byte houses2Pin[] = { 5,6,7,8,9,10, 11,12,13,14 };
byte rgbStripPin = 2;


void setup()
{
  houses1.initTLC5940(4, houses1Pin);
  houses1.setAnimation(houses1Seq);
  
  houses2.initTLC5940(10, houses2Pin);
  houses2.setAnimation(houses2Seq);
  
  rgbStrip.initWS2812(50, rgbStripPin);
  rgbStrip.setBrightness(0x888888);
  rgbStrip.setAnimation(rgbStripSeq);
}

void loop()
{
  houses1.runAnimation();
  houses2.runAnimation();
  rgbStrip.runAnimation();
}