Jump to: navigation, search

Mini Cooper R50 R52 R5

Status

In development / verification phase. The Mini Cooper ECU and instrument cluster electronics are based on BMW running gear, so this integration is adapted from the BMW E46 instructions.

Channels available

This integration will offer the following channels (to be verified)

  • Throttle Position (TPS)
  • Engine Temperature (EngineTemp)
  • Oil Temperature (OilTemp)
  • RPM (RPM)
  • Steering Angle (Steering)
  • Brake Switch (BrakeSw)
  • Brake Pressure (Brake)
  • Left front wheel speed (LFWheelSpd)
  • Right front wheel speed (RFWheelSpd)
  • Left Rear Wheel Speed (LRWheelSpd)
  • Right Rear Wheel Speed (RRWheelSpd)
  • Gearbox Temperature (GearboxTmp)
  • Exterior Temperature (ExtTmp)

Installation

Things you'll need

  • PosiTap insulation piercing taps (22 gauge)
  • RJ 45 (Ethernet) cable, ~6ft
  • RaceCapture/Pro with Bluetooth
  • Android tablet
  • 2002-2006 Mini Cooper (R50, R52, R53)

Estimated Time

2-3 hours, depending on level of wiring experience. The most time consuming part is locating and splicing the CAN, power and groud wires into the RJ45 cable.

CAN wires

CAN wire colors are as follows:

  • (VERIFY) Yellow/Red = CAN+ (high)
  • (VERIFY) Yellow/Brown = CAN- (low)

They are a twisted pair in or attached to the main wiring harness under the driver's side dash above the dead pedal. The wires need to be tapped, not cut.

Tapping CAN wires

To tap into the wires, you'll first need to unravel the wire as the CAN+/CAN- pair are tightly wound. You'll want to have enough room for 2 fingers in between the wires.

Tapping the wires via Posi-taps (recommended) is easy. Pull the top off the Positap, place the wire in it and tighten.

Positaps.png

Once you've tapped both it will most likely look like this:

Can-tapped.jpg

Power and ground wiring

Note: You can skip this section if you already have power wired to RaceCapture/Pro and don't want to change it.

Best option OBD-II port power

Using the same cable used for the CAN bus connection you can tap into power on the OBD-II port, for a clean 4 wire connection


Mini Cooper power, ground and CAN bus connections to RaceCapture/Pro
Connection Mini Cooper RaceCapture/Pro (RJ45 cable)
+12v (VERIFY) Yellow-Red (OBD-II connector) Brown
Ground (VERIFY) Brown (OBD-II connector) Orange/White
CAN High (VERIFY) Yellow/Red Orange
CAN Low (VERIFY) Yellow/Brown Green/White

Note: These color codes assume EIA-T568B RJ45 cable (check printing on the cable to confirm)

CAN Bus connection

In order for RaceCapture/Pro to read CAN data you need to connect the CAN+/CAN- wires to a RJ45 (ethernet cable).

Cut one end off the RJ45 cable and pull apart all the wires.

For a standard RJ45 cable (EIA T568B) the colors are:

  • Orange: CAN1 High
  • Green/white: CAN1 Low
  • Brown: Power
  • Orange/white: Ground
  • Note: Verify your RJ45 cable has EIA T568B printed on the jacket; this will ensure the color codes match.

Use the following diagram:

Canrj45.png

You will end up with something that looks like this:

Rj45labeled.jpg

Configure RaceCapture/Pro

Quick Start configuration

This configuration can be imported into your RaceCapture/Pro system to get you started.

Download: Mini Cooper starter configuration (right-click, save-as)

To complete your configuration for lap timing and live streaming to Podium:

Manual Setup

If you already have an existing, customized configuration, follow these steps to add Mini Cooper CAN bus integration.

Enable the CAN bus in your RaceCapture/Pro configuration

  • Rate is 500kb/s
  • Do not enable OBD-II channels.

Add this script to the Scripting section:

Script

--This example configured for Mini Cooper CAN
-- Automatically starts logging with engine 'on' (RPM triggered)
--how frequently we poll for CAN messages
tickRate = 30
--the CAN baud rate
CAN_baud = 500000
--CAN channel to listen on. 0=first CAN channel, 1=second
CAN_chan = 0

--add your virtual channels here
--format addChannel(<name>, <sample rate>, <precision>, <min>, <max>, [units])
tpsId = addChannel("TPS", 10, 0, 0, 100, "%")
tempId = addChannel("EngineTemp", 1, 0, 0, 255, "F")
oilTempId = addChannel("OilTemp", 1, 0, 0, 255, "F")
rpmId = addChannel("RPM", 10, 0, 0, 10000)
steerId = addChannel("Steering", 10, 0, -360, 360, "Deg.")
brakeId = addChannel("BrakeSw", 10, 0, 0, 1)
brakePressId = addChannel("Brake", 10, 0, 0, 255, "Bar")
clutchId = addChannel("Clutch", 10, 0, 0, 1)
lfWheelId = addChannel("LFWheelSpd", 10, 0, 0, 200, "MPH")
rfWheelId = addChannel("RFWheelSpd", 10, 0, 0, 200, "MPH")
lrWheelId = addChannel("LRWheelSpd", 10, 0, 0, 200, "MPH")
rrWheelId = addChannel("RRWheelSpd", 10, 0, 0, 200, "MPH")
gearTempId = addChannel("GearboxTmp", 10, 0, 0, 400, "F")
fuelId = addChannel("Fuel", 1, 0, 0, 100, "%")
extTempId = addChannel("ExtTemp", 1, 0, 0, 120,"F")

--Convert C to F
function toF(value)
 return value * 1.8 + 32
end

--TPS, correct your throttle here for true 100% 
function tpsFilter(value)
 return value + 0.0
end

--only start logging / telemetry if engine is running
function rpmFilter(value)
 if value > 500 then startLogging() else stopLogging() end
 return value
end

function brakeFilter(value)
 return bit.rshift(bit.band(value, 0x10), 4)
end

function clutchFilter(value)
 return bit.band(value, 0x01)
end

function processWheel(id, data, offset)
  --wheel speed is 13 bits long, little endian
  --low byte high byte
  --76543210 76543210
  --11111111 11111XXX
  local highByte = bit.band(data[offset + 2], 0x1F)
  local lowByte = data[offset + 1]
  local value = highByte * 256 + lowByte
  value = value * 0.0625
  --convert to MPH. comment to keep KPH
  value = value * 0.621371
  setChannel(id, value)
end

function processSteering(data)
    local steer = 0
    if data[2] > 127 then
      steer = -1*(((data[2]-128)*256)+data[1])
    else
      steer = (data[2]*256)+data[1]
    end
    setChannel(steerId, (steer*0.045))
end

function fuelFilter(value)
  --adjust for 7 bit value
  value = bit.band(value, 0x7F)
  --convert liters to %
  return value / 0.48
end

function extTempFilter(value)
  local temp = bit.band(value, 0x7F)
  if value > 127 then
    temp = -1 * temp
  end
  temp = toF(temp)
  return temp
end

----------------------------------------
--customize here for CAN channel mapping
--format is: 
--[CAN Id] = function(data) map_chan(<chan_id>, <data>, <CAN offset>, <CAN length>, <multiplier>,
--                                   <adder>, [filter])
----------------------------------------
CAN_map = {
[496] = function(data) processWheel(lfWheelId, data, 0)
                       processWheel(rfWheelId, data, 2)
                       processWheel(lrWheelId, data, 4)
                       processWheel(rrWheelId, data, 6)
        end, 
[339] = function(data) map_chan(brakeId, data, 0, 1, 1, 0, brakeFilter) end,
[504] = function(data) map_chan(brakePressId, data, 2, 1, 1, 0) end,
[809] = function(data) map_chan(tpsId, data, 5, 1 , 0.392156863, 0, tpsFilter) 
                       map_chan(tempId, data, 1, 1, 0.75, -48, toF)
                       map_chan(clutchId, data, 3, 1, 1, 0, clutchFilter)
        end,
[1349] = function(data) map_chan(oilTempId, data, 4, 1, 1, -48, toF) end,
[1083] = function(data) map_chan(gearTempId, data, 0, 1, 1, -55, toF) end,
[790]  = function(data) map_chan(rpmId, data, 2, 2, 0.15625, 0, rpmFilter) end,
[501]  = function (data) processSteering(data) end,
[1555] = function (data) map_chan(fuelId, data, 2, 1, 1, 0, fuelFilter) end,
[1557] = function (data) map_chan(extTempId, data, 3, 1, 1, 0, extTempFilter) end
}

function onTick()
    processCAN(CAN_chan)
end
--===========do not edit below===========
function processCAN(chan)
    local msg = 0
    repeat
        local id, e, data = rxCAN(chan, 0)
        if id ~= nil then
            local map = CAN_map[id]
            if map ~= nil then
                map(data)         
            end
        end
        msg = msg + 1
    until id == nil or msg > 100
end

--Map CAN channel, little endian format
function map_chan(cid, data, offset, len, mult, add, filter)
    if offset + len > #data then return end
    offset = offset + 1
    local value = 0
    local shift = 1
    while len > 0 do
        value = value + (data[offset] * shift)
        shift = shift * 256
        offset = offset + 1
        len = len - 1
    end
 local cv = value * mult + add
 if filter ~= nil then cv = filter(cv) end
    setChannel(cid, cv)
end
initCAN(CAN_chan, CAN_baud)
setTickRate(tickRate)

Test!

Once everything is connected, plug in the other end of the RJ45 cable to RaceCapture/Pro, turn it on and turn on your car. Make sure RCP is connected to your tablet and the RaceCapture/App is running.

Swipe to the digital dash page and you should see data for Coolant, Oil Temp, Throttle and brake!

Real-Time Telemetry

Just 4 wires - Power, Ground, CAN+ and CAN- is needed to stream tons of data to Podium for monitoring engine, driver and suspension performance!

Troubleshooting

  • If you don't see any data, verify all connections and splices.
  • If everything is connected connect your laptop to RaceCapture/Pro, open the RaceCapture/App, go to the Scripting section, set Logging Level to debug and select 'Poll logfile'. Check the output for any errors relating to the Lua Script.
  • If you're copying in the script file, ensure any existing script is erased first, do not append the script text to the existing script.

If you are still having issues post your problem on the forums here http://www.autosportlabs.org/viewforum.php?f=20