Wednesday, October 23, 2019

The path to LoRaWAN

In 2017 I already tried to get a LoRa based radio link working. Which worked, but only as a
local send / receive solution. At the time The Things Network (TTN) was already operational, but it was quite complex to get started with it, certainly if you don't live near a public TTN node so you could not just send some data to it. I briefly considered setting up my own station, but at an estimated cost of €300,- this was still a bit too much for just a hobby project.
Nowadays TTN has matured, and it is easier to find information on how to access it. There is a complete description on Adafruit on how to build a single channel gateway, and there are several DIY project on how to build simple LoRa Nodes. 
The easiest way would of course be to buy a complete LoRa enabled board, like the LoPy,  the Adafruit Feather with LoRathe WISEN Whisper Node, the MIKRO Electronika Lora5 Click, or just one of the TTN products. (And there are many more, just Google 'LoRa Board')
 
But I already have these Dragino LoRa Bee units and I want to use them. Should not be that hard since they are basically just RF95W transceiver modules on a carrier board. And the RF95 modules are at the heart of 99% of all other LoRa devices. 
A very nice description of a DIY LoRa node is described by Mario Zwiers in a few blog posts that basically describe what I wanted to do. He created a small PCB with an Arduino Micro, a battery charger and a bare RF95W module. Unfortunately he just created the PCB from scratch, without a schematic. So I have to figure that out myself, but since the combinations are limited that cannot be too hard.

Connecting LoRa Bee and Raspberry Pi Zero W

 Pi to LoRa Bee wiring:
  • 3.3V to Raspberry Pi 3.3V
  • GND to Raspberry Pi Ground
  • DIO0 to Raspberry Pi GPIO #3
  • RST to Raspberry Pi GPIO #25
  • SCK to Raspberry Pi SCK
  • MISO to Raspberry Pi MISO
  • MOSI to Raspberry Pi MOSI
  • CS to Raspberry Pi CE1  


Next I followed the basic instructions on installing Python. First installed the latest Raspbian to an SD card. Booted it on the Pi, and used raspi-config to set a Hostname, new password, and the WiFi network parameters. And from the 'Interfacing Options' section I also enabled SSH, SPI and I2C.
Run the standard updates:
sudo apt-get update
sudo apt-get upgrade
and
sudo pip3 install --upgrade setuptools
If above doesn't work try
sudo apt-get install python3-pip

Then install the GPIO libraries:
pip3 install RPI.GPIO

And the Adafruit libraries:
pip3 install adafruit-blinka 


(All this is also on the Adafruit site, I just repeated the steps here for convenience)
Next install the RFM libraries:
sudo pip3 install adafruit-circuitpython-rfm9x

After that I created a simplified version of the Adafruit sample program that would just check if the RFM unit was connected and working. Note that I changed the frequency setting in the RFM9x() function to 868.0, which is the frequency used in Europe.

#Learn Guide: https://learn.adafruit.com/lora-and-lorawan-for-raspberry-pi
#Author: Brent Rubell for Adafruit Industries

import time
import busio
from digitalio import DigitalInOut, Direction, Pull
import board

# Import the RFM9x radio module.
import adafruit_rfm9x


# Configure RFM9x LoRa Radio
CS = DigitalInOut(board.CE1)
RESET = DigitalInOut(board.D25)
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)

    # Attempt to set up the RFM9x Module
try:
    rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, 868.0)
    print("RFM9x: Detected")
except RuntimeError:
    # Thrown on version mismatch
    print("RFM9x: ERROR")

time.sleep(0.1)

And it works:

The instructions tell you to clone the GIT repository . But GIT is not installed by default on  Raspbian. Use the following commands to get it :

$ sudo apt-get update
$ sudo apt-get install git-core

Next step would be to install WiringPi. But there is a slight problem: WiringPi is no longer available at the URL as given in the instructions. Apparently the creator of this library has given up on the open source community. Fortunately there is still a mirror of the code at Github, which then probably is no longer maintained but will work fine with most projects.:

git clone https://github.com/WiringPi/WiringPi

Build it using 'sudo ./build'

Installing and running the Single Channel Gateway

The proceed to the next step, getting the single channel gateway code:

git clone https://github.com/adafruit/single_chan_pkt_fwd.git

This can now be built by using 'sudo make all'
Since I wired the RPi directly to my Lora Bee, and did not add any buttons or the display I had to modify the code in 'lorawan_gateway.py' so there were no references to the display any more and everything was just printed to the console. My modified code:
 
Now, what is not mentioned in the Adafruit guide is the fact that the unit is set-up according the settings in the file 'global_conf.json'. Which I had to modify to get it going for Europe.  I changed the frequency to 868.1 Mhz, and I swapped the servers so the router.eu is now the first in the list. Also set this to 'enabled:true', and the router.us to false. and changed the "is_pi_xero":true (since I am using a Pi ZeroW for my gateway). Also note that "pin_dio0" is set to 3. So it should be connected to GPIO 3, and not (as written on the AdaFruit page) to 5.

{
  "SX127x_conf": {
    "freq": 868100000,
    "spread_factor": 7,
    "pin_nss": 11,
    "pin_dio0": 3,
    "pin_rst": 25
  },
  "gateway_conf": {
    "ref_latitude": 0.0,
    "ref_longitude": 0.0,
    "ref_altitude": 10,
    "name": "Reigersbek51",
    "email": "me@email.com",
    "desc": "RPi Zero-LoraBee 1-Ch Gateway",
    "is_pi_zero": true,
    "servers": [
      {
        "address": "router.eu.thethings.network",
        "port": 1700,
        "enabled": true
      },
      {
        "address": "router.us.thethings.network",
        "port": 1700,
        "enabled": false
      }
    ]
  }
}
 

Now I can start the gateway.: python3 lorawan_gateway.py
and register the gateway at The Things Network.
Full description is on this page, no need to repeat it here...

But after completing the registration and starting the gateway it did not work. It did not show 'connected'. Then I noticed that when the gateway is started it prints  the Gateway ID. And that was all 00:00:FF:FF:00:00. So it looks like though the Python program displays the correct ID, the gateway code itself does not. Checking the code I noticed that there is a special case made for the Raspberry Pi Zero, which I am using. And in the initialisation I also see that 'Pi Zero' is set to 0. Even though I have changed this in the global_config.json to 'true' The fastest fix was to change line 102 in the .cpp file to: 

bool is_pizero = true;

My Modified code on GIST is here.

and run another 'sudo make all' .Which solved the problem.

The Sandbox Single Channel Gateway (LoRa GO DOCK)

The setup with the Raspberry Pi W and the LoRa Bee works fine. But just after finishing this,
I discovered the LoRa GO DOCK. At only $19,- this is a super cheap gateway, based on the ESP8266 so it's programmable using the Arduino IDE. Once programmed and configured the operation is similar to the RPi version, so it is a much easier solution. It's also super small, and comes with two antennas. The only drawback is that it has to come from China so it takes two to three weeks to deliver.


Tuesday, March 19, 2019

Getting started with SDL2

The Simple Directmedia Layer (SDL) is a mature framework that has been around for quite some time. Though mainly targeted at writing games it is good for any program that requires the creation of arbitrary graphics screens, like for example retro computer emulators. One of the more interesting aspects of SDL is that it is cross-platform. It runs fine on your PC, Mac or Linux computer. And this includes the ever so popular Raspberry Pi.
There are many excellent guides for setting up SDL on every platform.
TwinkleBearDev SDL2 Tutorials
Parallel Realities Game Tutorials
Lazy Foo Productions 

Visual Studio

There is a good step-by step guide on WikiHow to configure Visual Studio. It however is already outdated since the easiest way to set it up today is by using the Nuget package manager. One of the major benefits of going this way is that you can now simply switch between 32 and 64 bit builds by just selecting the target platform in the VS project type dropdown. So : Lets Get Started !

First use 'File->New->Project' to create a 'Visual C++' -> 'Empty Project'.

Right click the 'Project' and select 'Manage NuGet packages'. In the NuGet Package manager go to the 'Browse' tab, and search for SDL2. Select the latest SDL2 package and click install. 
Then scroll down an also install the 'SDL2_image', 'SDL2_ttf' and 'SDL2_mixer' packages for image handling, font management and sound. This basically configures your project completely for use with the SDL2 framework. 
The only thing you have to do manually is selecting the SubSystem target. To do this open up the System page and choose either Console or Windows from the drop down. If you choose Windows you won’t get a console window that opens up with stdout, if you choose Console you will. My advice is to choose Console, as the console window is really handy as a debugging tool.
Note that when you switch your target from 32 to 64 bit or vice-versa you will again have to choose the SubSystem target or your build will fail because it 'Cannot find an entry point for main()'



You are now ready to start your first SDL project. 
Right click the 'Source Files' folder and select 'Add ->; New Item...'. Select a 'C++ File', give it meaningful name if you want, and click OK. Open the empty C++ file, and copy the following:
#include "sdl.h"
#include "sdl_image.h"
#include <iostream>
#include <stdio>


const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main(int argc, char* args[]) {
    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = NULL;
    SDL_Renderer *renderer=NULL;
    SDL_Texture *texture=NULL;
    SDL_Event event;
    SDL_Rect r;

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("Could not initialize SDL. SDL_Error: %s\n", SDL_GetError());
    }
    else {
        window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
        if (window == NULL) {
            printf("Cannot create window. SDL_Error: %s\n", SDL_GetError());
        }
        else {
            SDL_Rect arect;
            screenSurface = SDL_GetWindowSurface(window);
            SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x00, 0x00, 0x44));
            arect.x = 64; arect.y = 64; arect.w = SCREEN_WIDTH - 128; arect.h = SCREEN_HEIGHT - 128;
            SDL_FillRect(screenSurface, &arect, SDL_MapRGB(screenSurface->format, 0x00, 0x77, 0x77));
            SDL_UpdateWindowSurface(window);
            SDL_Delay(500);
        }
    }

}


Run the program, and if all is well it will show a window with a blue border and green centre.


Tuesday, January 29, 2019

Extruder Trouble

After more than 100 hours successful printing on my new 3D printer, it suddenly failed heavily.
An overnight print stopped halfway, leaving a mess of scattered plastics on my print bed. The problem was obvious: the thermistor got loose from the hot end, and the printer stopped after detecting a 'thermal runaway'. Prior to this however the temperature of the head did exceed the maximum for PLA and so the nozzle seemed jammed with burnt plastic and it looked like the inner tube of the hot end was filled with plastic.  

After spending two days trying to solve the jamming without any success I decided to give up and order a new hot-end. And not go for the lowest price this time, so I chose the E3D Lite6. Still not very expensive at about €35,- 

The kit is really complete. Everything from the smallest grub-screw to the required Allen-keys is included.
And there is a really good assembly guide.Which, near the end, mentions that after assembly you should tension the nozzle again when the extruder is hot. Of course I assumed that would not be necessary if I just tightened it properly in the first place. WRONG!
At one of the following prints I suddenly found black spots and blobs. At first I assumed that the it was just over-extrusion and that the excess of plastic was slowly building up at the tip. So I decreased the extruder flow by a few percent, but that did not help. Then I searched for 'black blobs in 3d print' and many suggested that probably the extruder was leaking. Which was exactly what happened. And after tightening the nozzle again, now with the extruder at 230 degrees, the problem was solved. 

Despite the very promising first two prints using the new extruder, the third failed again due to a clogged nozzle. And so did the fifth, so I decided to give up on the 0.2 mm nozzle and go to 0.3. At first I was reluctant to do that, since somehow it always stuck in my head that a smaller nozzle would give cleaner results. Which is basically true, but not as much as you'd expect as explained in the 'Everything about nozzle diameters' post on the site of Prusa Printers. And it's just so much easier to get a good flow rate. With the 0.2 nozzle I often experienced that the filament feeding would 'skip' due to the fact that the filament just wasn't feeding through the nozzle fast enough. Something I tried to solve by increasing the temperature to 230 degrees. The disadvantage here is that any excess filament on the nozzle tip seems to burn and finally this burnt plastic will clog the nozzle.