Sunday, January 8, 2012

Android Tablet as Head Unit

For some time I have been hoping to have a unified dashboard display of all the data for the EV. The sources of this data are three Atmel ATmega based devices I built in the car: the battery charger and vehicle interface each use an ATmega168 and the battery monitor uses an ATmega644. Each of these has a serial port (the 644 has two ports, but one is tied to a GPS unit,) and each has a simple serial-Bluetooth adapter connected to that port.
Via Bluetooth, I can monitor the car from my office with a simple serial terminal app, though I wrote a custom MacOSX terminal program with a few extras: auto-reconnect the bluetooth links, display the battery voltages in a bar graph, and log all the data to weekly files. At a glance I can see the charger's progress, the voltage of each battery, and the distance of the last 15 trips. I can also control the charger and change its parameters.


There is a fourth device in the car which produces serial data - the UMOC motor controller. This communicates at 38400bps and sends around 410 bytes 3 times per second. Here is an example data block from the UMOC:
ad 342 1021 1022 1021 3 516 42 182
D 11 2 -24 I 24A -28A 28A

INFO: LIMITS TO TORQUE:

ped_T -334 Pwr Svr: 1.0 Relay: ON

Id 16.2 A Mtr Temp: 1.00 Power Stage: ENABLED

Iq 16.2 A Box Temp: 1.00 Regen: ENABLED

Temp 31.6 C Dev Temp: 0.98 Err PAL: LEDPwr
Bat. 247.6 V BatV: 1.00 Last err:

Rotor -1757 rpm Speed: 1.00 FORWARD Accel


To process this data I first used an arduino, but the volume of data was too much for a 16MHz processor to handle (parse and store on SD card) much less display on even a serial LCD. Something faster was needed.

My first thought was to use an iPad, as I have experience with MacOSX programming, but it turns out to be non-trivial to connect serial data to an iOS device. First, the SPP (Serial Port Profile) is not supported by the iOS Bluetooth APIs. Third party hardware solutions allowed only 1 serial stream connected. And to top it off, I would need to pay Apple $99/year to program my own device!

I resisted an obvious option, namely Android tablets, because I did not want to invest the time to learn a whole new OS that may not be around for long (remember Palm?) But the prices dropped to where it was worth a try, and I bought a WM8650 based 7" tablet for about $80 (now going for $60 in Jan 2012.) I planned to use a IOIO for Android to interface with the car's electronics.

For some time I struggled with connecting the tablet to my PC, because I was mistaken in thinking it had a device mode. Turns out the two USB ports on the adapter, which also has an RJ45 ethernet port, are for hosting devices. Just plug in a mouse or keyboard and they work, which is great because 7" screen-based keyboards suck!

Next I wondered if I can plug in a USB-to-serial adapter. Well, not exactly. CDC-ACM devices were supported out of the box (like the new Arduino Mega) but not chipsets with proprietary interfaces like FTDI, Prolific, or WinChipHead. That last one is used in some real low cost adapters, of which I happen to have four. I have seen them on eBay for less than $2.

I figured I needed to compile a kernel module (ch341.ko) for the adapter and modify the linux boot scripts to load it at start-up. To compile the module, I need the tablet's kernel configuration, which was not available under /proc/config.gz. I had to extract the kernel from flash memory and then find the config embedded within it. This took some time, but I learned some interesting things along the way.

Trying to compile the kernel was a real adventure. First I spent time finding the tools to cross-compile as I am using MacIntel. Neither the Android NDK nor the CodeSourcery (now Mentor Graphics) tools were able to get me all the way to a compiled kernel with modules. Then I thought I would try running linux on my Mac and compile under that, but I had no install CDs, and I could not install from a HD, though I tired many permutations. I eventually used parallels to install and run Ubuntu.

Even under linux I was having trouble getting the kernel to compile. I am not a linux expert and perhaps the config used by the manufacturer was too old or new or customized. And I had issues with header files, too. In any case, I finally found a link to a bundle of compiled modules in an android forum. Shazam! - they worked with a simple 'insmod' of the ones I wanted.

I put the modules in '/lib/modules/moremodules' and modified the script file '/etc/rc.d/rc0.d/S99modules' to load them. This was added to the end of the script:

#################### insmod USB-Serial-BT ############################## MOMODULE_PATH="/lib/modules/moremodules" echo "Install USB-Serial modules" insmod $MOMODULE_PATH/ch341.ko insmod $MOMODULE_PATH/ftdi_sio.ko
insmod $MOMODULE_PATH/cp210x.ko
echo "Install Bluetooth Modes"
insmod $MOMODULE_PATH/bluetooth.ko insmod $MOMODULE_PATH/btusb.ko
insmod $MOMODULE_PATH/bcm203x.ko
insmod $MOMODULE_PATH/btsdio.ko
insmod $MOMODULE_PATH/hci_uart.ko
insmod $MOMODULE_PATH/hci_vhci.ko
insmod $MOMODULE_PATH/btmrvl.ko
insmod $MOMODULE_PATH/btmrvl_sdio.ko
echo "FINISHED with Modules -- HOORAY"

Now, connecting the adapter produced the hoped-for entry /dev/ttyUSB0, but the default permission allowed only root access. So I wrote this shell script:
#!/bin/sh
changepermissions() {
for i in /dev/ttyUSB*
do
chmod +rw $i
done
}

plk=1
while [ "$plk" -ne 0 ]
do
changepermissions
sleep 10

done

which checks for any ttyUSB devices and changes the permissions on them. It is launched by including the following in '/init.rc'
service changedevperms /monitorDevs.sh
user root
oneshot

After all that, I can finally start on an Android app to read and display the UMOC data. Using the serial port access code written by Cedric Priscal and looking at the graphics calls implemented in this thermometer example by Ivan Memruk, I cobbled together the android part. I recycled the data-parsing code from the arduino experiments.

It works! the 800MHz tablet has no trouble reading, parsing, and displaying the UMOC data. And I can connect multiple usb-serial adapters to centralize all the data collection in the car, after I make some optically isolating connectors for the charger and UMOC.
The biggest remaining issue is how to mount the thing. The tablet's usb/ethernet adapter is about 60x30mm, has a tiny 24 pin connector, and extends the tablet's length. I have not found any right-angle adapters, or even a simple 24 pin extension cable for this thing. Even if I can, the power is on a separate connector, so I may have to open up the table and put something new on the back. Stay tuned....