Hello folks,
Last time I posted here it was to document my O2 Joggler Project.
Now two years later, I've replaced the Joggler with a new installation - this time using an iPad:

In hindsight the Joggler hardware worked fantastically well, however software problems that I was unable to resolve (increasingly slow boots, buggy audio drivers and unstable OS/browser) caused me to look for another solution. I've since gone through a few more traditional (undocumented) car computer installations using a netbook and another Windows-based tablet computer - but these all had the same problems of slow boot times and occasional instability.
So several weeks ago I decided to ditch the computer from the plan entirely and go with a tablet-based solution (as many of you have done before).
As with my previous installations, the installation needed to look as close to a 'factory look' as possible, whilst also retaining the steering wheel control functionality.

As before I bought and modified another Metra double-din fascia; using an old soldering iron to meld together various pieces from the new and old fascias. Due to limited space within the area occupied by the original head unit (and a desire not to modify any of the original car's parts or trim), I could not build a 'enclosed' dock into which the iPad would slide. Instead I created a small protruding dock connector onto which the iPad (or iPod/Phone) would sit, supported laterally by two metal bars (in the style of those on the 'new' Mini), and additionally by series of magnets, which would interface with a metal plate attached to the iPad's protective case. This positioning would avoid any obstruction to my field of vision whilst driving.

To make better use of the space behind the docked iPad, I molded in two storage trays from the fascia kits - making sure they were not deep enough to prevent me from fitting the required electronics in the cavity behind the fascia.
Interfacing the iPad with the steering wheel controls would be more difficult than with the Netbook or Joggler, as I could not use the Joycon EX device. Instead, I located documentation for the Apple Accessory Protocol (that permits communication with a docked Apple device using serial commands). In order to generate these commands and to read changes in resistance from the resistor network within the wheel, I needed a microcontroller.
After doing a little research I decided on the Duinomite Mini - primarily because despite it's tiny size and low cost (£17), it's also a self-contained computer with video and keyboard connections, allowing me to code and debug on the device without shifting around SD Cards or USB cables, or needing to compile any code. The Duinomite runs on a variant of BASIC, so it was extremely easy to pick up. Whenever powered, it immediately and automatically runs a program called 'AUTORUN.BAS' on the SD Card, so no special relays or starter systems are required.

If you're interested in how the Duinomite reads the wheel input and generates the commands for the iPad (and stepper motor, which I'll explain later), I've included the full source code below. At the top you'll find a full list of 'Mode 2' commands that can be sent to an Apple device, even though I only used a small selection of these. Note that the last value on each command is a check-sum byte that is required in order for the device to accept the command. I had a bit of trouble calculating these as I wasn't initially clear on which parts of the command needed to be included in the calculation (thanks to some conflicting online documentation).
Code:
' Define Variables '
Boolean_Pressing = 0
Float_Resistance = 0.00
Integer_Steps = 5
' Define Commands '
Command_SetMode$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H00) + Chr$(&H01) + Chr$(&H02) + Chr$(&HFA)
Command_Release$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&HFB)
Command_PlayPause$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H01) + Chr$(&HFA)
Command_VolumeUp$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H02) + Chr$(&HF9)
Command_VolumeDown$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H04) + Chr$(&HF7)
Command_NextTrack$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H08) + Chr$(&HF3)
Command_PreviousTrack$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H10) + Chr$(&HEB)
Command_NextAlbum$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H20) + Chr$(&HDB)
Command_PreviousAlbum$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H40) + Chr$(&HBB)
Command_Stop$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H03) + Chr$(&H02) + Chr$(&H00) + Chr$(&H80) + Chr$(&H7B)
Command_Play$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H04) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H01) + Chr$(&HF9)
Command_Pause$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H04) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H02) + Chr$(&HF8)
Command_Mute$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H04) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H04) + Chr$(&HF6)
Command_NextPlaylist$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H04) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H20) + Chr$(&HDA)
Command_PreviousPlaylist$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H04) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H40) + Chr$(&HBA)
Command_Shuffle$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H04) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H80) + Chr$(&H7A)
Command_Repeat$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H05) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H01) + Chr$(&HF8)
Command_Off$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H05) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H04) + Chr$(&HF5)
Command_On$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H05) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H08) + Chr$(&HF1)
Command_Menu$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H05) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H40) + Chr$(&HB9)
Command_Select$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H05) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H80) + Chr$(&H79)
Command_ScrollUp$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H06) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H01) + Chr$(&HF7)
Command_ScrollDown$ = Chr$(&HFF) + Chr$(&H55) + Chr$(&H06) + Chr$(&H02) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H00) + Chr$(&H02) + Chr$(&HF6)
' Configure Pins '
SetPin 1, 1 ' Wheel Resistance '
SetPin 18, 8 ' Stepper Coil 1 '
SetPin 17, 8 ' Stepper Coil 2 '
SetPin 16, 8 ' Stepper Coil 3 '
SetPin 15, 8 ' Stepper Coil 4 '
SetPin 14, 2 ' Limit Switch (Clockwise) '
SetPin 13, 2 ' Limit Switch (Counter Clockwise) '
Open "COM4:19200" As #4
' Interaction Loop '
Do
' Read Wheel Resistance '
Float_Resistance = Pin(1)
Print Float_Resistance
' Handle States '
If Float_Resistance < 1 Then
' Detect Button Release '
If Boolean_Pressing = 1 Then
' Send Release Command '
Print #4, Command_Release$
Boolean_Pressing = 0
EndIf
Pause 100
Else
' Detect Button Press'
If Float_Resistance < 3.2 Then
' Check For Held Button '
If Boolean_Pressing = 0 Then
' Send Mode Command '
Print #4, Command_SetMode$
Boolean_Pressing = 1
EndIf
' Identify Button Pressed '
If Float_Resistance < 1.5 Then
' Speaker / Mute Button Pressed '
Print #4, Command_PlayPause$
ElseIf Float_Resistance < 1.9 Then
' Mode Button Pressed '
Print #4, Command_Shuffle$
ElseIf Float_Resistance < 2.3 Then
' Down Button Pressed '
Print #4, Command_NextTrack$
ElseIf Float_Resistance < 2.7 Then
' Up Button Pressed '
Print #4, Command_PreviousTrack$
ElseIf Float_Resistance < 3.0 Then
' Volume Down Button Pressed '
Print #4, Command_VolumeDown$
If Pin(13) >= 1 Then
' Engergise Stepper Coils '
For Integer_Step = 1 To Integer_Steps
Pin(18) = 1
Pin(17) = 0
Pin(16) = 0
Pin(15) = 1
Pause 2
Pin(18) = 1
Pin(17) = 1
Pin(16) = 0
Pin(15) = 0
Pause 2
Pin(18) = 0
Pin(17) = 1
Pin(16) = 1
Pin(15) = 0
Pause 2
Pin(18) = 0
Pin(17) = 0
Pin(16) = 1
Pin(15) = 1
Pause 2
Next
EndIf
' De-Engergise Stepper Coils '
Pin(18) = 0
Pin(17) = 0
Pin(16) = 0
Pin(15) = 0
ElseIf Float_Resistance < 3.2 Then
' Volume Up Button Pressed '
Print #4, Command_VolumeUp$
If Pin(14) >= 1 Then
' Engergise Stepper Coils '
For Integer_Step = 1 To Integer_Steps
Pin(18) = 0
Pin(17) = 0
Pin(16) = 1
Pin(15) = 1
Pause 2
Pin(18) = 0
Pin(17) = 1
Pin(16) = 1
Pin(15) = 0
Pause 2
Pin(18) = 1
Pin(17) = 1
Pin(16) = 0
Pin(15) = 0
Pause 2
Pin(18) = 1
Pin(17) = 0
Pin(16) = 0
Pin(15) = 1
Pause 2
Next
EndIf
' De-Engergise Stepper Coils '
Pin(18) = 0
Pin(17) = 0
Pin(16) = 0
Pin(15) = 0
EndIf
EndIf
EndIf
Pause 15
Loop
Rather than paying for an expensive breakout board for the Apple dock connector, I acquired a cheap 'dock extension cable'. Each end had a connector containing an easily solderable breakout board. I soldered the male end to a 10-way ribbon cable, then embedded into the protruding dock on the fascia.
Getting the iPad to charge properly whilst docked (and in 'serial access mode') requires various pins to be set to specific voltages and resistances (not just 5v and ground, unfortunately), so I also designed and constructed a one-off circuit board that would provide these voltages in addition to a quick way of connecting and disconnecting everything during testing. It also stacked nicely with the Duinomite and my chosen amplifier board using Nylon standoffs. I should note that the resistance values shown on the schematic worked during testing but are no longer the ones I use - I found I had to tweak them to get charging to work properly once everything was in the car. I'm not sure what they are currently set to on the installed board.
As you can see it's an entirely passive circuit and simply reduces the cable mess between the Duinomite, dock connector and stepper motor (more on that in a second).


For power purposes I re-used the same Current Logic 50W 12v-5v converter from the Joggler project. I did however obtain a new higher-quality amplifier board than the one I was using before. This is a Class-T amplifier offering slightly better audio quality and increase power (although not by much). Since I'm still using the factory fitted speakers, I wasn't looking for anything particularly powerful.
Controlling volume would be a problem, as the Apple dock connector outputs line-level audio and iOS disables volume/level control when it is used.
Initially I planned to use a digital potentiometer, controlled by the Duinomite using a protocol called SPI - but I had real difficulty getting it to respond as desired. Eventually I ditched the digital pot and attached a small, low-power stepper motor to the amplifier's rotary pot. Whilst this may seem a little Heath Robinson in nature, it actually works very well; it removes the possibility of sudden volume spikes and avoids any potential noise problems caused by a (inevitably badly designed) volume control circuit. Additionally, the volume level always stays wherever it's currently set when power is removed from the system. I can also adjust the speed (and acceleration curve) of volume changes by tweaking the stepper control code in the software.

I did allow for the addition of limit switches to prevent 'over rotating' the pot - however I soon discovered these were not required, as the stepper was connected to the pot via a piece of plastic tubing that could slip (and the stepper itself was not powerful enough to apply any stress to the amplifier board or frame, even when intentionally 'over rotated'). The maximum volume is uncomfortable to listen to, and muting is achieved with the Play/Pause command, so actually encountering either rotational extreme under normal operation was highly unlikely.
The plastic parts seen above are from a construction set intended for educational use. I've found it to be useful for these kinds of projects, but I'm afraid I've long since forgotten what it's called or where I bought it. I have a Solidoodle 3D printer on order which I intend to use to print a proper enclosure for the whole amp/controller/board assembly, eventually replacing this makeshift frame.

With the electronics in place I finished up the fascia by adding the supporting steel bars (actually door handles) and insetting the magnets. As the iPad itself is non-magnetic, I had to glue a ferromagnetic plate to the plastic case I'd bought. Luckily the iPad's magnetometer is at it's top, so it does not appear to be affected by the magnets in the dock (which are positioned near the bottom where the iPad's back comes into contact with the fascia). In the end I used 24 rare-earth magnets (10mm x 3mm). These keep the iPad completely secure against the heaviest acceleration the MX5 is capable of producing (though at 0-60 in ~10 seconds, it's not exactly quick - a more powerful car would probably make such a docking solution impractical).
I made the spacing between the supporting bars a little wider than required in order to accommodate larger cases in the future. To provide a soft cushion between the case and bars, I wrapped small cuttings of foam around them and then heat-shrank them to achieve a neat, rubberized look. Smaller Apple devices don't have anything like as much inertia, so they can sit in the dock without requiring the bar/magnetic support that the iPad does.

Once installed into the car, the whole assembly actually requires very little room - even if it is a little messy without an enclosure.

The installed dock looks reasonably 'factory fitted'. I attempted to get the closest possible finish and ended up going with Tamiya TS-6 paint for it's fantastically smooth spray. Unfortunately as a convertible the difference in colour becomes more pronounced when the top is down and the sun is out - but not so much that it looks 'wrong'.
I've been using the dock now for a few weeks and it's working perfectly. Apart from an initial bug in my software, I've had no problems at all with the wheel controls or audio noise. The volume control setup remarkably worked first time - although I've since sped up the volume changes to make it more responsive.
Being able to drop the iPad or iPod into the dock and immediately press 'Play' on the wheel is extremely satisfying after spending years trying to get elaborate computer-based setups to boot quickly. The 3/4G connection and GPS hardware also makes navigation, browsing (whilst stopped, of course) and music streaming over Spotify possible. I'm looking forward to the release of iOS6, as it will add voice controlled navigation and Siri to the iPad, which should greatly enhance the 'in motion' functionality of this setup.
Of course as it's all based on a standardized connector and protocol, all Apple devices (with the likely exclusion of the new iPhone coming in October) can dock, charge and be controlled by the steering wheel.


If you're interested in seeing other (car and non-car) projects I've worked on, I've just put up a new blog documenting a few of them here.
You can find the original Joggler Car PC thread here.
Bookmarks