Monday, November 26, 2018

Saturday, August 25, 2018

Smart watch..., who's smart, who's watching?

I got a Pebble watch a while back, for $100 it did everything I was expecting from it. I came with a cloud/web-based IDE, a really fine piece of work, it was possible to develop and debug applications running on the watch in JavaScript, that was really well done, smart and neat.
Then a while back, Pebble got acquired by Fitbit. And now, the Cloud IDE of Pebble is not available anymore. Than means I cannot develop new apps for my Pebble, even if it is still working just fine.
Why would I buy a new watch (twice as expensive), and re-write all my apps? This is quite frustrating...
In fact, there was something wrong from the beginning.
All those so-called smart watches need a Bluetooth cell-phone to connect to, and from there it will reach other data. Why not a TCP-based protocol from the watch, to bypass the phone? Power consumption? I doubt it.
This is not about accessibility or configuration either, I do it all the time for Raspberry Pis and similar boards, ssh and similar protocols have been here for this kind of remote access, for ages, and for good reasons.
Smart glasses, head-up displays (HUD), smart watches, all those devices are just displays, all they need is to connect to a data bus and display what they mean to (just like an NMEA bus).
I suspect some marketing bullshit behind the scene..., again.

If this kind of TCP watch does not show up soon, I'll build one. Bam!

Saturday, July 14, 2018

Raspberry PI, PWM, servos, and PCA9685

The code mentioned below can be found in this git repo.
Pulse Width Modulation (PWM) is the technique used from a digital source to simulate an analog output.
For example, imagine that you want to dim an led from a digital device, to make it look like it is glowing. The digital device only has pins that can take 2 values: 0 or 3V3.
0 means that the led will be off, 3V3 means it will be on, at 100% of its brightness.
In short, it is on or off, and there is nothing in between.
But here is an idea to work around that issue:
To show it at 50% of its brightness, the idea is to turn it off 50% of the time, and on 50% of the time.
To show it at 25% of its brightness, it will be on 25% of the time, and off 75% of the time.
If the on-off cycles are short and fast enough, a human eye will no be able to see them, it will only have the illusion of the resulting brightness.
A human eye cannot make the distinction between images separated by less than one 10th of a second. That is why the movies are shot at 24 images per second, so you cannot tell the difference between the frames.
This technique is call Persistence of Vision (POV).
The #1 parameter of PoV is the human retina. To have an idea of how much it is important, just put your cat in front of a TV, and see how much he/she reacts. To a cat, it might just be a fuzzy screen...
The early movies - like Charlie Chaplin's silent ones - were shot at 16 images per second, fast enough to induce POV. They were later projected by faster projectors - 24 frames per second. That is why the characters seem to move faster. They were originally moving normally.


Here are examples of PWM applied to POV:
At work, for real:
The PCA9685 is a servo driver PCB.
The Raspberry PI does not have analog pins, we need to use Pulse Width Modulation to simulate analog values, a servo is an analog device.
We use for that the method setPWM(channel, 0, pulse), that will eventually write to the registers of the device.
An instruction like setPWM(channel, 0, pulse) means:
  • On channel channel (0 to 15 on the PCA9685)
  • in each cycle, turn the power on between 0 and pulse.
pulse has a value between 0 and 4095, that is 4096 distinct values, 4096 is 212, the PCA9685 is a 12 bit device.

The frequency

The frequency is provided in Hertz (Hz). A frequency of 60 means 60 cycles per second.
At 60 Hz, a cycle will be 1 / 60 second, which is 0.01666666 second, or 16.66666 milli-second (ms).

The pulse

For each of the cycles set above by setting the frequency, we need to determine the int value, between 0 and 4095, corresponding to the pulse in milliseconds we want to simulate with PWM.
In the class i2c.servo.pwm.PCA9685.java, this is done in this method:
public static int getServoValueFromPulse(int freq, float targetPulse) {
  double pulseLength = 1_000_000; // 1s = 1,000,000 us per pulse. "us" is to be read "micro (mu) sec".
  pulseLength /= freq;  // 40..1000 Hz
  pulseLength /= 4_096; // 12 bits of resolution. 4096 = 2^12
  int pulse = (int) Math.round((targetPulse * 1_000) / pulseLength); // in millisec
  if (verbose) {
    System.out.println(String.format("%.04f \u00b5s per bit, pulse: %d", pulseLength, pulse));
  }
  return pulse;
}
The cycle length (in ms) obviously depends on the frequency.
The pulse required for the servo to work is emitted once per cycle.

Example

As an example, let us calculate for a 60 Hz frequency the pulse value to send to setPWM(channel, 0, pulse) for a 1.5 millisecond PWM:
  • 1 cycle has a duration of 1 / 60 second, or 16.66666 milliseconds.
  • each cycle is divided in 4096 slots, we can say that 4096 bits = 16.6666 ms.
  • the solution is provided by a rule of three: value = 4096 * (pulse / 16.66666), which is 368.64, rounded to 369.

A comment about servos' compliance and reliability

Theoretically, servos follow those rules:
PulseStandardContinuous
1.5 ms0 °Stop
2.0 ms90 °FullSpeed forward
1.0 ms-90 °FullSpeed backward
That happens not to be always true, some servos (like https://www.adafruit.com/product/169 or https://www.adafruit.com/product/155) have values going between 0.5 ms and 2.5 ms.
Before using them, servos should be calibrated. You can use the class i2c.samples.IntercativeServo.java can be used for that, you set the pulse values interactively, and you see what the servo is doing.
$> ./inter.servo
Connected to bus. OK.
Connected to device. OK.
freq (40-1000)  ? > 60
Setting PWM frequency to 60 Hz
Estimated pre-scale: 100.72526
Final pre-scale: 101.0
Servo Channel (0-15) : 1
Entry method: T for Ticks (0..4095), P for Pulse (in ms) > p
Enter 'quit' to exit.
Pulse in ms > 1.5
setServoPulse(1, 1.5)
4.0690 μs per bit, pulse:369
-------------------
Pulse in ms > 0.5
setServoPulse(1, 0.5)
4.0690 μs per bit, pulse:122
-------------------
Pulse in ms > 0.6
setServoPulse(1, 0.6)
4.0690 μs per bit, pulse:147
-------------------
Pulse in ms > 2.4
setServoPulse(1, 2.4)
4.0690 μs per bit, pulse:589
-------------------
Pulse in ms > 2.5
setServoPulse(1, 2.5)
4.0690 μs per bit, pulse:614
-------------------
... etc.

Once you have determined the appropriate min and max values, you also have the int values to feed the setPWM with.

Some links:

Tuesday, June 12, 2018

Languages Comparison

For the fun: Same problem addressed in several languages, read the paper here.

It is about matrix and systems of equations resolution, curve smoothing, etc.

Done in C, Java, Processing, Scala, Kotlin, Python, JavaScript, Groovy, Go, Clojure (in progress), ...

Tuesday, April 24, 2018

Controlling invisible machines with emails, from Java

Here is the problem

You have your network at home, with several machines connected to it (laptops, tablets, Raspberry PIs, phones, etc). Your home network is a Local Area Network (aka LAN), the machines can see each other, but they cannot be seen from outside, from the Internet.
You may very well want to deal with those machines while away from home, to restart services, launch a new program, or even reboot.
In the configuration mentioned above, this is simple, you just cannot do it. And that is frustrating!
There is a way though. Those machines on your home LAN can send and receive emails...

Using JavaMail

JavaMail is a Java package that has been available for ever, it understands the email protocols (IMAP, POP3, SMTP, etc), and can be used to interact with email accounts programmatically.

An example

There is an example of such an interaction on this github repository.
The fastest way to get it running is to run the following commands (these are for Linux - and MacOS - on Windows, use the git shell):
$ git clone https://github.com/OlivierLD/raspberry-coffee.git
$ cd raspberry-coffee
$ cd common-utils
$ ../gradlew shadowJar
$ cp email.properties.sample email.properties
$ vi email.properties
$ # Here you modify your properties file to match your email account
$ java -cp ./build/libs/common-utils-1.0-all.jar email.examples.EmailWatcher -send:google -receive:google
The -send:google -receive:google depends on the settings in your email.properties.
Then, to the account mentioned in the email.properties, send a message like this:
Subject: execute
Content:
whoami
ifconfig
uname -a
Note: this example requires the content to be in plain/text.
Once the message is received by the EmailWatcher, it sends you an acknowledgement:
Then, the 3 commands are processed by the EmailWatcher, you would see in its console an output like that:
Start receiving.
Received:
whoami
ifconfig
uname -a

Operation: [execute], sent for processing...
pi
lo0: flags=8049 mtu 16384
 options=1203
 inet 127.0.0.1 netmask 0xff000000 
 inet6 ::1 prefixlen 128 
...
And finally, you receive an email like that:
... meaning that the commands you've sent have been executed.

You can also attach the script to execute to a blank email, with topic execute-script:
Attach a file like this:

#!/bin/bash
whoami
ifconfig
ps -ef | grep EmailWatcher
... and just wait for the result to come back to you:
Scripts execution returned: 
pi
eth0: flags=4099  mtu 1500
        ether a4:ba:db:c9:04:2e  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 18  

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1  (Local Loopback)
        RX packets 9215  bytes 2022884 (1.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9215  bytes 2022884 (1.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=4163  mtu 1500
        inet 192.168.42.3  netmask 255.255.255.0  broadcast 192.168.42.255
        inet6 fe80::4038:1f53:b94f:ccc2  prefixlen 64  scopeid 0x20
        ether 78:e4:00:78:ad:8f  txqueuelen 1000  (Ethernet)
        RX packets 8848724  bytes 696021134 (663.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 18848059
        TX packets 6040965  bytes 795472510 (758.6 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 17  base 0xc000  

pi      12476 12472  1 16:39 pts/0    00:00:53 java -cp ./build/libs/RasPISamples-1.0-all.jar weatherstation.email.EmailWatcher -send:google -receive:google
pi      16204 16199  0 18:04 pts/0    00:00:00 grep EmailWatcher
>> sh ./attachments/2018-04-26_18-04-27/sample.sh returned status 0

Comments

This process is not synchronous, this could be a drawback... But still, it allows you to interact remotely with machines invisible from the Internet.

Having the command

java -cp ./build/libs/common-utils-1.0-all.jar email.examples.EmailWatcher -send:google -receive:google
fired when the machine boots will allow you make sure it is waiting for your emails as soon as the machine is up.

This EmailWatcher as it is also allows you to execute scripts, attached to the email. Look into the code for details ;)
It is even possible to ssh to another machine and execute a bunch of commands stored in a script... The command you send in the email's body would be like

ssh pi@192.148.42.13 bash -s < ~/nodepi.banner.sh
If a password is required, use sshpass:
sshpass -p 'secret-password' ssh pi@192.148.42.13 bash -s < ~/nodepi.sudo.sh
You can even sudo:
echo 'secret-password' | sudo -S privilegedCommand
This can be dangerous, hey? With great power come great responsibilities...

Sunday, April 15, 2018

Head-Up Display (HUD)

The idea here is to display a screen on a transparent support - like a wind shield.
The data are displayed on the screen, reflected on the transparent support, and nothing is preventing you from seeing through it.
(Click the image to enlarge it)

Here is above an HTML page, tweaked by some CSS classes to mirror the data (as the page is reflected on the screen, the page content has to be displayed as in a mirror, and flipped upside down.). In this case, the page is rendered on Chromium in kiosk mode, running on a Raspberry PI with a touch screen attached to it.
CSS Classes:
    .mirror {
      display: block;
      -webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
      -moz-transform: matrix(-1, 0, 0, 1, 0, 0);
      -o-transform: matrix(-1, 0, 0, 1, 0, 0);
      transform: matrix(-1, 0, 0, 1, 0, 0);
    }

    .upside-down {
      height: 100%;
      width: 100%;
      -moz-transform: rotate(180deg);
      -webkit-transform: rotate(180deg);
      -ms-transform: rotate(180deg);
      -o-transform: rotate(180deg);
      transform: rotate(180deg);
    }

    .mirror-upside-down {
      display: block;
      -webkit-transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg);
      -moz-transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg);
      -o-transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg);
      transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg);
    }

In the picture above, we use the class as follow:
<div id="the-div" class="mirror-upside-down big" style="padding: 0px; text-align: center;">
  <hr/>
  <table>
    <tr>
      <td colspan="2">GPS Data</td>
    </tr>
    <tr>
      <td>
        <span>Your position:</span>
        <br/>
        <span>N 37° 44.93'</span>
...
The page on the screen (not on the wind shield) would actually look like this:

GPS Data
Your position:
N 37° 44.93'
W 122°30.42'
Your Speed:
12.34 kts

You can also work around the perspective effect on the reflected page by tweaking the CSS classes:
    .mirror-upside-down {
      display: block;
      -webkit-transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg) perspective(50em) rotateX(-40deg);
      -moz-transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg) perspective(50em) rotateX(-40deg);
      -o-transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg) perspective(50em) rotateX(-40deg);
      transform: matrix(-1, 0, 0, 1, 0, 0) rotate(180deg) perspective(50em) rotateX(-40deg);
    }

GPS Data
Your position:
N 37° 44.93'
W 122°30.42'
Your Speed:
12.34 kts
We call this the Star Wars effect. ;)

Possibilities are endless!
The full page is here.

Wednesday, April 11, 2018

Docker on the Raspberry PI

This post intends to illustrate how Docker can work around the "But it works on my machine!.." syndrome.

Let's say you have a nodejs project you want to share with others.
The application reads GPS data through a Serial port, and feeds a WebSocket server.
The data can then be visualized through a Web interface.

To enable everything, you need to:
  1. Have a Raspberry PI
  2. Flash its SD card and connect it to a network
  3. Install build tools
  4. Install git
  5. Install NodeJS and npm
  6. Clone the right git repository
  7. Install all the required node modules
  8. Drill down into the right directory
  9. Start the node server with the right script
  10. Access the Raspberry PI from another machine on the same network, and reach the right HTML page.

This is certainly not difficult, but there are many ways to do several mistakes at each step of the process!

Docker can take care of the steps 3 to 9. It will build the image, and then run it.
The image can also be pushed to a repository, so users would not have to build it.
Just to run it after downloading it.

The only pre-requisite would be to have installed Docker on the machine (the Raspberry PI here), as explained here.
Create a Dockerfile like this (available here):
 FROM resin/raspberrypi3-debian:latest

 LABEL maintainer="Olivier LeDiouris <olivier@lediouris.net>"

 RUN echo "alias ll='ls -lisah'" >> $HOME/.bashrc

 RUN apt-get update
 RUN apt-get install sysvbanner
 RUN apt-get install -y curl git build-essential
 RUN curl -sL https://deb.nodesource.com/setup_9.x | bash -
 RUN apt-get install -y nodejs
 RUN echo "banner Node-PI" >> $HOME/.bashrc
 RUN echo "git --version" >> $HOME/.bashrc
 RUN echo "echo -n 'node:' && node -v" >> $HOME/.bashrc
 RUN echo "echo -n 'npm:' && npm -v" >> $HOME/.bashrc

 RUN mkdir /workdir
 WORKDIR /workdir
 RUN git clone https://github.com/OlivierLD/node.pi.git
 WORKDIR /workdir/node.pi
 RUN npm install

 EXPOSE 9876
 CMD ["npm", "start"]

In this case, the full Docker image creation (named oliv-nodepi below) comes down to 1 line (the one in bold red):
 $ docker build -t oliv-nodepi .
Sending build context to Docker daemon  752.6kB
Step 1/20 : FROM resin/raspberrypi3-debian:latest
 ---> c542b8f7a388
Step 2/20 : MAINTAINER Olivier LeDiouris 
 ---> Using cache
 ---> b2ff0d7c489f
Step 3/20 : ADD nodepi.banner.sh /
 ---> 535733298dd1
Step 4/20 : RUN echo "alias ll='ls -lisah'" >> $HOME/.bashrc
 ---> Running in 09baf7261a55
Removing intermediate container 09baf7261a55
 ---> 71e1e4c95663
Step 5/20 : RUN apt-get update
 ---> Running in 5d817a941a14
Get:1 http://security.debian.org jessie/updates InRelease [94.4 kB]
Get:2 http://archive.raspbian.org jessie InRelease [14.9 kB]
Get:3 http://archive.raspberrypi.org jessie InRelease [22.9 kB]

...

npm notice created a lockfile as package-lock.json. You should commit this file.
added 166 packages in 81.166s
Removing intermediate container 13986530db28
 ---> 051eb94b8a3c
Step 19/20 : EXPOSE 9876
 ---> Running in 67b587845fe0
Removing intermediate container 67b587845fe0
 ---> 46973b7ba9ac
Step 20/20 : CMD ["npm", "start"]
 ---> Running in 153bf2ea02ad
Removing intermediate container 153bf2ea02ad
 ---> 6bf3d76d38ae
Successfully built 6bf3d76d38ae
Successfully tagged oliv-nodepi:latest
ed9a7d9042dddd3939b1788cf0e89d16f5273192a6456266507f072f90ce91bc
 $

Once the step above is completed, plug in your GPS, and run
 $ docker run -p 9876:9876 -t -i --privileged -v /dev/ttyUSB0:/dev/ttyUSB0 -d oliv-nodepi:latest
Then from a machine seeing the Raspberry PI on its network (it can be the Raspberry PI itself), reach http://raspi:9876/data/demos/gps.demo.wc.html in a browser.

This shows you the position the GPS has computed, and the satellites in sight.
You can also login to the image:
 $ docker run -it oliv-nodepi:latest /bin/bash

 #     #                                 ######    ###
 ##    #   ####   #####   ######         #     #    #
 # #   #  #    #  #    #  #              #     #    #
 #  #  #  #    #  #    #  #####   #####  ######     #
 #   # #  #    #  #    #  #              #          #
 #    ##  #    #  #    #  #              #          #
 #     #   ####   #####   ######         #         ###

 git version 2.1.4
 node:v9.11.1
 npm:5.6.0
 root@b9679d0d65a7:/workdir/node.pi#

... and do whatever you like.
The build operation needs to be done once.
There is no need to do it again as long as no change in the image is required.

Quick comment
So, with Docker, you do not deliver a software, you actually deliver an image (a virtual machine), on which a software is running.
This is indeed redefining the concept of portability that made Java and other JVM-aware languages so successful.
This may very well explain the rise of languages like Golang (aka Go).
It runs on my machine? Well, here is my machine! You can download and run it. Enjoy!

Saturday, March 17, 2018

Java Weather Station

This is a SwitchDocLabs SDLWeather80422 Weather Station, installed on the roof.

It is connected to a Raspberry PI A+, all the software is written in Java, no Python, no Arduino-like code, no C++.

There is an optional nodeJS server that runs on the Raspberry PI too, to enable WebSockets.

Find the core code here, and the example implementation here.

MySQL, PHP, Web Interface
Web-Components interface, pings the server every second.
WebSocket Web Interface, updated in real-time.
Some papers by John Shovic turned out to be very useful, specially in understanding what this debounce aspect is all about.

See it live here.

It even comes with a pebble application.