Wearable Sensing DSI-24
Notes on using the DSI API on a Raspberry Pi Zero (2019-05-01)
Headless operation of the Raspberry Pi
To enable remote login via ssh on Raspbian, use another computer to create a 0-byte file
called ssh at the root directory of the SD card.
Already that will let you connect via ethernet if you have the hardware---e.g. an Ethernet dongle such as https://www.adafruit.com/product/2909 connected via an OTG adapter such as https://www.adafruit.com/product/1099, taking care to ensure that the Pi is getting enough current on its power supply (1A or more, from a wall adapter not a computer USB bus) because Ethernet draws a lot of current.
Alternatively, you can go straight onto WiFi: create an additional file on the root of the
SD card, called wpa_supplicant.conf with the following content (changing MyNetworkSSID
and MyPassword appropriately)::
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=US # or the two-letter code for your country
network={
ssid="MyNetworkSSID"
psk="MyPassword"
}
When you boot, that file will get moved automatically to
/etc/wpa_supplicant/wpa_supplicant.conf where you can edit it (e.g. with sudo nano)
to replace that plaintext password (in quotes) with a password hash (WITHOUT quotes).
The password hash is generated by calling wpa_passphrase MyNetworkSSID and then
typing your password at the prompt.
Out of the box, the host name will be raspberrypi, the username pi and the password
raspberry. If the host is not visible as raspberrypi.local then you may have to
log into your router admin webpage to discover the IP address that has been assigned to
it. As soon as you log in, you should change your password (with passwd) and probably
also the host name (best done via sudo raspi-config).
When logged in over ssh, the screen tool is extremely useful as it allows a shell
(and whatever processes it is running) to be "detached" from the terminal and continue
running even after you log out. It may need to be installed first (assuming internet
access, say sudo apt install screen). This particular alias is most useful::
alias scg="screen -R -e^Gg"
Then, typing scg will first attempt to "reattach" any currently detached screen session,
or simply start a new session if there is no existing one. It also remaps the hot key
away from its default (ctrl-A, which overshadows go-to-beginning-of-line) and changes
it to ctrl-G. This means you can detach the session by pressing ctrl-G followed
by d, or get a list of other possible commands by doing ctrl-G followed by ?.
API Compatibility
The released copy of libDSI-Linux-armv6.so was created on a Raspberry Pi Zero W
(https://www.adafruit.com/product/3400 or https://www.adafruit.com/product/3708)
running a pre-loaded Raspbian 9 distribution (https://www.adafruit.com/product/2820)::
$ uname -a
Linux raspberrypi 4.14.34+ #1110 Mon Apr 16 14:51:42 BST 2018 armv6l GNU/Linux
$ head -n 1 /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
$ /opt/vc/bin/vcgencmd version
Apr 16 2018 18:16:56
Copyright (c) 2012 Broadcom
version af8084725947aa2c7314172068f79dad9be1c8b4 (clean) (release)
It also works after sudo apt update; sudo apt upgrade to upgrade everything to the
latest stable versions as at 2019-05-01::
$ uname -a
Linux raspberrypi 4.14.98+ #1200 Tue Feb 12 20:11:02 GMT 2019 armv6l GNU/Linux
$ head -n 1 /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
$ /opt/vc/bin/vcgencmd version
Mar 27 2019 15:45:53
Copyright (c) 2012 Broadcom
version 2e98b31d18547962e564bdf88e57b3df7085c29b (clean) (release) (start)
Quick start
You can test the library from Python::
import DSI
DSI.Test( '/dev/ttyUSB0' ) # assuming wired connection directly into OTG port
For writing your own C code, we can adapt the Linux-specific instructions inside
demo.c to compile as follows::
gcc -o demo demo.c -DDSI_PLATFORM=-Linux-armv6 DSI_API_Loader.c -ldl -lm
Then we need to ensure that the OS can load the dynamic library when you launch your
binary. One way to do that is to copy the dynamic library to the system lib
directory::
sudo cp libDSI-Linux-armv6.so /usr/lib/
...or to soft-link it from there (assuming you're never going to move it)::
sudo ln -sfn `pwd`/libDSI-Linux-armv6.so /usr/lib/
An alternative way is to specify the parent directory of libDSI-Linux-armv6.so in
the LD_LIBRARY_PATH variable::
export LD_LIBRARY_PATH=`pwd` # or wherever the shared library's permanent home is
(NB: if LD_LIBRARY_PATH variable already contains paths, append the new path using
colon as a separator, instead of overwriting the entire variable.)
Wired connection to USB port
Plug the DSI's USB cable into the Pi Zero's "on-the-go" USB port. Connect the other
end to the headset---one end or the other will need a (female USB A)-to-(male USB OTG)
adapter such as https://www.adafruit.com/product/1099. Once connected, turn the headset
on. You can then use /dev/ttyUSB0 as the serial port address. Here's a test::
./demo info --port=/dev/ttyUSB0
You can also omit the --port option if you have set the DSISerialPort environment
variable::
export DSISerialPort=/dev/ttyUSB0
./demo info
Under the hood, this variable is accessed when you use the string "default" as the port
address in your C code::
DSI_Headset h = DSI_Headset_New("default");
// or
DSI_Headset h = DSI_Headset_New(NULL);
// pre-connection configuration, then...
DSI_Headset_Connect(h, "default");
or equivalently in your Python code::
h = DSI.Headset()
# pre-connection configuration, then...
h.Connect("default")
If you have the headset connected via a hub, then presumably there will be a different
port address: you might be able to determine the correct address by running dmesg
after connecting and turning on the headset.
UART serial port on GPIO pins
In theory it sounds like it is also possible to use the GPIO pins instead of the OTG
port, although I have not managed to get it to work. According to the instructions at
https://www.raspberrypi.org/documentation/configuration/uart.md you should be able to
use the address /dev/serial0 after ensuring that there is no console service using
that serial port (sudo raspi-config -> "Interfacing Options" -> "Serial" ->
"Would you like a login shell to be accessible over serial?" -> "No", then reboot with
sudo shutdown -r now). The cable (https://www.adafruit.com/product/954) is connected
as follows, according to
https://learn.adafruit.com/adafruits-raspberry-pi-lesson-5-using-a-console-cable/connect-the-lead:
- Black to GND (3rd pin from corner, on outer edge)
- White to TXD (4th pin from corner, on outer edge)
- Green to RXD (5th pin from corner, on outer edge)
(The red lead can optionally carry power to the Raspberry Pi Zero, at the pin nearest the corner, provided you unplug all other power sources.)
So far this has not worked for me---I connect black/white/green as above, but the headset
does not recognize this as a USB connection and keeps flashing its LED as if looking for
a Bluetooth connection. Accordingly, the API reports that /dev/serial0 cannot be opened.
Bluetooth (only available on the Raspberry Pi Zero W model)
-
Not sure whether (or how much of) this step is necessary. It comes from https://www.raspberrypi.org/forums/viewtopic.php?p=947185 and https://www.raspberrypi.org/forums/viewtopic.php?t=125922. Use
sudoin conjunction with whichever command-line editor you're comfortable with (I likevimbut let's assumenano), to edit the config file for the bluetooth service::sudo nano /lib/systemd/system/bluetooth.serviceLook for the line that says
ExecStartand ensure that it has two flags added to it as follows. Also (maybe?) add theExecStartPostline so that it all reads::ExecStart=/usr/lib/bluetooth/bluetoothd --noplugin=sap --compat ExecStartPost=/usr/bin/sdptool add SPThen either restart the
bluetoothservice::sudo systemctl daemon-reload sudo service bluetooth restartor if in doubt just reboot::
sudo shutdown -r now -
Discover the DSI's BlueTooth MAC address using
hcitool scan. Substitute it for the XX's below. -
Not sure whether this step is necessary::
$ sudo bluetoothctl ... [bluetooth]# pair XX:XX:XX:XX:XX:XX ... [bluetooth]# trust XX:XX:XX:XX:XX:XX...because the next step seems to work even after you
remove XX:XX:XX:XX:XX:XXagain. It could be that only thetrustoperation is necessary. -
Start an
rfcommprocess that connects to the given MAC address and creates a serial port identifier in/dev::export DSI_MAC_ADDRESS=XX:XX:XX:XX:XX:XX sudo rfcomm connect 0 $DSI_MAC_ADDRESS & -
Because of the
0in therfcomm connectcommand, the serial port address will be/dev/rfcomm0, which you can then use as normal::export DSISerialPort=/dev/rfcomm0 ./demo info # or your own DSI_API applicationHowever, note that immediately after creating the
rfcommprocess you may need to wait 30 seconds or so, during which time there may be a red error light on the headset. Time, or repeated connection attempts, or both, seem to clear this error state eventually, and then subsequent handshakes using the API during thatrfcommsession seem to be relatively quick. -
After disconnecting for the last time, kill the
rfcommprocess---either literally withkill, or if you launched it from a terminal you can foreground it withfgand then press ctrl-C.