Wednesday, September 21, 2016

Programming the i2c Bus in Python

Reference

There's a useful reference on the Raspberry Pi website targeted at kids using the Raspberry Pi, that has a tutorial on GPIO programming in Python.

Python

To program the Raspberry Pi I chose to use Python 2.7.4 which was pre-installed with the JESSIAN Linux OS.  I wrote and tested the code using the simple Idle IDE application which came pre-installed with the Raspberry Pi's Linux operating system.  Be sure to use the correct version of Idle ... Idle is for Python 2.7 and Idle3 is for Python 3.0.

When I wrote the final code I also worked in the PyCharm IDE on my Mac because I like its code formatting features.  PyCharm can be used to edit code on a different computer using SSH.

Python's smbus Library

The first thing I had to do before beginning to code was to install the Python smbus library, which provides a high level abstraction from the specific pin voltages that need to be set to communicate on the i2c bus.  It's important to note here that I'm using Python 2.7 and the Idle IDE (ie not Idle 3 which is for Python 3.x).  The smbus library does not install the same way with Python 3, and may need manual packaging).

This was installed from the Raspberry Pi's Linux command line using:

sudo apt-get install python-smbus

The smbus library when used in python has three important commands:

bus = smbus.SMBus(n) 
... is used to instantiate an smbus object that can then be used to execute commands.  From reading various articles, early Raspberry Pi devices used n=0, and later ones used n=1.  This  is the same value that is passed in the i2c-detect command, which by trial and error I worked out should be n=1.

Once the smbus object has been instantiated, there are commands to write and read data to / from the bus.

To activate a device on the bus, we must write to its control register.   The command to do this is:
bus.write_byte_data(bus_address, control_register, value)

To read data from a device  we use:
bus.read_byte_data(bus_address, data_register)

Checking For Responses

Next I wrote three short scripts to sample each of the sensors and print out the results.

Accelerometer:

Gyroscope:

 Magnetometer / Compass



Results:





Fantastic!  I'm now reading values from all three devices, so now I can write a some useful code to capture a sequence of readings.


Reference

The most helpful reference for this project has been Ozzmaker.  It certainly does not provide a straight lift-out for two reasons - this blog uses a different sensor board, and programs in C rather than my preferred Python.



Exploring the i2c Bus

 

In this project I am using three separate sensor chips that are built into the AltiMU-10 sensor board:  Gyro, Accelerometer and Magnetometer.  By careful review of the the documentation on the Pololu web page for the MiniMu-9 V5

MiniMu9

The MiniMu9 circuit board contains three devices, a gyro, a magnetometer and a compass.  Each of the three devices has three sub sensors, X, Y and Z each representing a different dimension / orientation.

We communicate with the MiniMu9 using the Raspberry Pi's i2c serial bus.  The i2c bus is a serial bus that allows a computer to communicate with a variety of devices connected to the bus.  Broadly, this is how it works:
  • Each device has an address on the bus
  • Each device has a set of registers which can either be readable, writable or both
  • Some of the registers are control registers, where you can read or write settings
  • Some of the registers are data registers, where you can read or write data
A reading from one of the 9 sensors is read by sending a value to a register to tell the circuit which value we wish to read, then reading the value from a specific address.  We will need to read all nine addresses in order to take one complete set of readings.

Physical Connectivity



The i2c bus is accessed through the Raspberry Pi's serial input/output port.  4 wire connections are needed as follows:

Raspberry Pi Port       Altimu-10 Port        Purpose      My Cable Color
1   3V                             VDD                         3V Power   Red
3  GPIO-0                      SDA                          SDA           Yellow
5  GPIO-1                      SCL                           SCL            Orange
9  Ground                      GND                          GND           Black                                 


The picture above shows the orientation of the pin-out on the Raspberry Pi (note, this is picture of the Raspberry Pi V2 - I will retake the pic with a V3).

Raspberry Pi i2c Bus

i2c bus is a software convention for multiple devices to communicate with a computer over the same serial bus.  The Raspberry Pi's General Purpose Input Output (GPIO) connector (bottom right in the picture above) communicates with the Pi's processor using i2c.

The i2c bus documentation is available online, though is generally not needed here as the developer is abstracted from the complexities the electronic circuits by using a software library.  More to follow on the software later.

First, check that the i2c capability is enabled by accessing the Raspberry Pi's configuration menu:
sudo raspi-config

From the menu select Advanced Options, then select I2C.   On the next screen you are asked if you wish to enable the ARM I2C interface - select YES.

Reboot the Raspberry Pi to make the I2C interface active.

Next install the package that allows Python to communicates with the bus:
sudo apt-get install python-smbus

Next I install i2c tools, a package that allows you to see if devices are active on the i2c bus using the i2cdetect application.  From the Linux command line:
sudo apt-get install i2c-tools libi2c-dev

After saving and exiting from Nano, the Raspberry Pi must be rebooted from the command line with:
 sudo reboot 


Testing The i2c Bus

After rebooting I can use i2c tools to identify if the connections are working correctly.  From the Linux command line I run:
sudo i2cdetect -y 1
The resulting grid is displayed:


I  see the device addresses 6bH and 1eH are visible on the ic2 bus, and that no others are visible.  I check that against the port addresses used by the Gyro, Accelerometer and Magnetometer from my device documentation.  This looks good as the Gyro and Accelerometer both use 6b and the compass uses 1e.

Port Addresses

Gyro - LSM6DS33

Address                     0x6b
Control Register 2_G  0x11
Message                     0x40  01000000b  104Hz, 245dps, Gyro full scale at 125dps
Control Register 7_G  0x16
Message                     0x38  00111000b - X, Y, Z Gyro on
X Data Low               0x22
X Data High              0x23
Y Data Low               0x24
Y Data High              0x25
Z Data Low               0x26
Z Data High              0x27

Accelerometer - LSM6DS33

Address                       0x6b    1101011b
Control Register 1XL 0x10
Message                      0x40     01000000b - 104Hz, +/- 2g, 400Hz BW
Control Register 9XL 0x18      
Message                      0x38     00111000b - X, Y, Z Accel on
X Data Low                0x28
X Data High               0x29
Y Data Low                0x2a
Y Data High               0x2b
Z Data Low                0x2c
Z Data High               0x2d

Magnetometer - LIS3MDL

Address                   0x1e
Control Register 1   0x20
Message                  0x10
Control Register 4   0x23
Message                   0x00
X Data Low             0x28
X Data High            0x29
Y Data Low             0x2a
Y Data High            0x2b
Z Data Low             0x2c
Z Data High            0x2d
Temp Low               0x2e
Temp High              0x2f



Raspberry Pi Basics

 

I started out with a new (Dec 2016) Raspberry Pi v3 purchased online from Amazon.   When I first tried this project I spent a lot of time getting basic functions like WiFi working.  The new Pi has onboard wifi and bluetooth, which makes things much easier, as the Linux OS is preconfigured to use them.

The Raspberry Pi comes without an operating system, and without any storage.  It has a Micro-SD slot and four USB ports.  It is configured to boot from an operating system on the Micro-SD slot.  Best practice is to put the operating system on a fast Micro-SD card, and use a USB thumb drive to store data.

Operating System Installation

Any Linux OS will work on the Raspberry Pi, but it is best to use a variant that has been built specifically for the Raspberry Pi.  I chose the most common on which is called Raspbian.  Raspbian has named major releases, the first was called Debian, the second and latest is called Jessian.

The operating system is downloaded from the Raspberry Pi website.  There are two sets of installation files to choose from:  "New Out of The Box" aka NOOBS, which is a simple version with everything pre-configured, and a version to self-configure.  I chose NOOBS.  Here are the steps:

  1. Download NOOBS to my Macbook
  2. Unzip the NOOBS download
  3. Insert the SD card into my Macbook
  4. Using the Mac Disk utility format the SD card as MSDOS
  5. Using Finder, copy the NOOBS files into the root directory of the SD card
  6. Put the SD card into the Raspberry Pi's SD card slot.  Connect keyboard, mouse and monitor and boot it.
  7. The Raspberry Pi presents a configuration screen.  I selected Raspberry Pi "JESSIAN" operating system full version, and English-US keyboard.  I did not configure WiFi at this stage.  The software then proceeded to install and configure itself and booted up to a Linux desktop.

Configuring WiFi on a Rapsberry Pi 3 with JESSIAN is easy.  No editing of files like the previous version, just click the WiFi icon, select the network SSID, enter the network password and you are done.

With the wifi now working, I want to set the PC up for remote access.  I want two types of remote access: SSH terminal access and RealVNC screen sharing.  I will do the SSH first, as once I have that I can configure the Raspberry Pi for RealVNC remotely over SSH.

The Raspberry Pi comes with a default user account called "pi" with a password of "raspberry". First thing to do is to reset the password for the account pi.  This can be done by opening a terminal window on the Pi and using the  passwd  linux command.  Note that you will be forced to select a complex password that is not based on a dictionary word.

Static IP Address

Because I don't want to have to reconfigure my SSH and VNC settings each time the Raspberry Pi device is assigned a new IP address by DHCP, the next thing to do is to configure the Raspberry Pi for a static IP address.  This involves two steps: (1) reserve an IP address for the Raspberry Pi on the router and (2) configure the reserved IP address on the Raspberry Pi.

For my router I'm using an airport extreme, so I open the Airport Utility, select the Airport, select Edit.  On the network tab I add a DHCP reservation for the Raspberry Pi.  I chose 192.168.0.30

The Raspberry Pi's Static IP address on the WiFi interface is configured by editing the file /etc/dhcpcd.conf and adding the following lines at the end:

    interface wlan0

    static ip_address=192.168.0.200/24    static routers=192.168.0.1    static domain_name_servers=192.168.0.1

Secure Shell (SSH)

I enable the Raspberry Pi's SSH server.  On the Raspberry Pi terminal window, run the  rasbpi-config  command.  Select "Advanced Options" then enable both SSH.

If I open a terminal window on my Mac I can run:
       ssh pi@192.168.0.23
I am then prompted for a password and I am able to enter script commands directly to the Raspberry Pi.

Configure USB Drive For Storage

Here's a good Instructable on setting up the USB drive.  It was straightforward to follow.  After formatting it I created two directories in the USB drive root - /code and /data.  When I configured the USB drive into the Raspberry Pi file system I made it /usbdrv, so on the Pi the directories will appear as /usbdrv/code and /usbdrv/data.   I also made a second mapping so that my code and data folders would appear under /home/pi/usb.

File Transfer

To be able to easily transfer files between my Macbook and the Raspberry Pi, I use the Macbook's Finder app and configure the Raspberry Pi as a remote server by selecting
     Go / Connect to Server



The Raspberry Pi's file system is now visible in the Finder left nav in the "Shared" section.  I am able to navigate to the /usbdrv folder which represents the USB drive that is plugged into the Raspberry Pi.



In the dialog that appears I add afp://192.168.0.23, and when prompted I enter the username pi and the password that I changed on the Raspberry Pi.

Remote Desktop (VNC)

To remotely control the Raspberry Pi's desktop requires three tasks

  1. Enable the VNC server function on the Raspberry Pi's BIOS
  2. Set the VNC server running
  3. Run VNC client software on my Mac and make a connection to the Raspberry Pi

I enable the Raspberry Pi's VNC server.  On the Raspberry Pi terminal window, run the  rasbpi-config  command.  Select "Advanced Options" then enable both SSH.

To set the VNC server running, run the following command:
vncserver :1 -geometry 1024x600 -depth 16 -pixelformat rgb56
Next to access the remote desktop on the Raspberry Pi.  I downloaded the Mac VNC viewer application from the RealVNC website.   I launch the app and enter the details of the Raspberry Pi
   192.168.0.23:5901

Note - the password entered is not the password associated with the Pi account on the Raspberry Pi - it is the password that was entered as the VNC password when VNC was installed on the Raspberry Pi.

I am now able to remotely control the Raspberry Pi's desktop (of course being careful to use the Mac's Control Key instead of the Command Key!)


Next Steps

Once all that's in place then I can move on to the new sensor board, and accessing it via the Raspberry Pi's i2c Serial Bus.