Automotive OEM rotary controller as driverless USB device

Hi guyz!

I am trying to figure out how to interface my Arduino UNO R3 with an OEM rotary controller device (in my specific case it is a BMW iDrive device from an X3).

My intention is to use Arduino as a proxy, so to be able to use the rotary controller without drivers on any computer, by emulating a keyboard and mouse.

Devices such as the iDrive rotary controller are interfaced via CAN bus (in fact the connector has 4 pins, which I guess will read out to VIN, GND, CAN-H, CAN-L).

I have already purchased the Sparkfun CAN-bus Shield, but haven't had time to try the CAN libraries available on the web.
I know such libraries are usually directed at connecting to an existing CAN network (through the OBD-II diagnostic port on vehicles). Has anybody successfully INITIATED a network with this shield (I guess the iDrive rotary device will in turn try to connect as a slave)?

Cheers to all! May you spend a lovely time with your families this Christmas :slight_smile:

Anybody? Bump! :slight_smile:

Usually CAN-devices isn't just acting as slave devices, so your unit may need some init-messages to start spewing out CAN-frames.

Either way, hook it up, and have a go!

Personally I would just rip out the electronics, and just reuse the encoder and buttons with the Arduino.

If you use one of the newer arduino's with native USB, it's easy to do what you want.

// Per.

Thanks for the reply!!!!

In fact I can't rip the device apart (it is the property of my employer... shhh I shouldn't even have taken it home...).
I've got to manage to fix the can bus connection. It will be useful for my future projects too!!!

I'm starting to understand how CAN works, will report back with news when i have it :slight_smile:

Ok so a few bits of knowledge I have gathered so far. Some are really stupid, but I guess no info is too stupid :slight_smile:

CAN BUS :: General hardware setup
A Controller Area Network consists of a loop, in fact the two lines (CAN High and CAN Low) are "terminated".
If you imagine the CAN "bus" being a railway, it's two lines being CANH and CANL, at the both ends of the rail, the lines are connected! That is with resistors (120 Ohm resistors are defined as standard).
Also, the two lines of the "railway" are twisted together.
Any node can be hooked at any point of the rail (paying attention to connecting the pins correctly to the CANH or CANL line), as long as it's between the two ends of the "railway".

CAN BUS :: In a car
A vehicle has a bunch of individual CAN busses. Usually when people talk CAN, they mean OBD-II (which is the OnBoard Diagnostics port that is mandatory on all vehicles commercialised since 2001 worldwide). The OBD port is a particular port and not interesting to me right now... anyway a quick search will lead to finding out it runs at 500kbps.

BMW :: K-CAN
In modern BMW's the K-CAN is the network on which most interior accessories are running, such as windows, lights, and the CIC (the infotainment system). This bus runs at 100kbps, which is usually not defined in Arduino CAN libraries.
I don't know the logic behind the value specified below, I know it relates to crystal timers, bit clocking etch... suffice to say you will need to add a line similar to this to enable popular CAN libraries to work on the K-CAN:

#define    CANSPEED_100    9   // 100 Kbps

This goes next to where other speeds are defined..

7 = 125 Kbps
3 = 250 Kbps
1 = 500 Kbps

BMW :: CIC Controller (iDrive 2.0 rotary controller)
The BMW part number 6582 9267955-01 refers to the latest iDrive knob (in this case featuring Media, Radio, Tel, Nav, Menu, Back and Option buttons, on top of the knob which has a rotary encoder with integrated 4-way joystick with tilt mechanism and a push button).
This device has a 4-pin connector with the following pinout (pins are numbered inside the connector!):

1 VIN (+12V)
2 GND
3 CANH
4 CANL

I am now in the process of finding out how to set up a sniffer with the CAN-bus shield... basically listening to anything going on, on the bus.
I have to admit that up to now I simply haven't been able to do ANYTHING with the CAN-bus shield. I've been trying each and every popular and less popular libraries around. Unfortunately they all seem to be designed to work specifically with the OBD port.
I also have to understand if the iDrive knob device needs to be initialised somehow, or if it simply starts sending messages when a user interacts with its physical sensors. For that I need to sniff the network.
Will keep posting :slight_smile:

It might be worth investing in a cheap logic analyser that can capture and decode the CAN bus data. I don't have/use CAN but a sample of the decode is below.

Hi Riva!

The point is that I don't want to throw money at a CANalyzer (most are extremely expensive, in my wallet's own words!) when I could/should be able to see traffic with my Arduino.

I guess it's just something that people haven't been willing to fiddle with and comment about that much.
But I am determined to find out how in the earth it works!

:slight_smile:

Ascanio:
The point is that I don't want to throw money at a CANalyzer (most are extremely expensive, in my wallet's own words!) when I could/should be able to see traffic with my Arduino.

You can get logic analysers very cheap though the one I linked to is a bit more expensive at 33 Euros.
Maybe you would have been better off with a DUE as I think it has CAN bus built in.

I have both the UNO + CAN-bus shield and the DUE (and a UDOO Board which integrates a DUE-compatible).

I have yet to start tinkering with the DUE, but in the meantime am using the UNO for work-related projects (for which I don't have much time, and thus have high priority).

What you are referring to, in the DUE, is the CAN Controller (which is embedded in the SAM3 micro controller), but by itself it is not equipped to be connected to a CAN bus: it still needs a CAN Transceiver. In fact I think the Arduino team didn't embed one because they don't wish to incentivate automotive projects (which are at high risk of injure or death)... it's simply a feature that came with the micro controller that they picked for the DUE.

Anyhow, I am at home, I have the parts, I just need to figure out how to make them work :slight_smile:
A CANalyzer at the moment sounds redundant to me.

I'm quite new to arduino and really interested in this as well. my goal is to make the bmw iDrive controller somewhat work as a USB HID device using arduino - have you had any luck with this? Keep us posted :slight_smile:

me too, any progress? i am thinking on buying an idrive CIC controller and test it also.

also for CAN sniffing or sending data for tests, you can use an ELM327 based device, even a 5$ china clone, but i prefer using Obdlink Sx because of the large buffer.
after you sniff the IDs of the Idrive Controller and the idrive unit you can easily filter data based on their IDs.

Best suggestion I could tell you is to go online and buy an elm327 device.. You can get them with Bluetooth,USB, or even serial connections.. Should be able to find one for less than $10.. You might not use it in your final project, but it sure will make attempting to communicate with the device a lot easier to start.. To get started just use the elm327 without the ardunio, use the atma command to start sniffing the data.. Add some filters as you narrow down what you need..

In fact I use these for my auto projects because I just can't beat the price for a canbus ready device.. Take one apart,unsolder the bluetooth card, solder in your data wires to the ardunio and you're done..

that was my sugestion for him also :slight_smile:

tek1229:
I use these for my auto projects

Have you presented them on the forum?

Hello,
I red the post and I believe the iDrive knob is actually LIN-bus protocol not CAN-BUS, I can't locate the CAN node associated to the iDrive knob in the BMW diagram. I am interested if you managed to proxy the iDrive knob with LIN-bus.

Ascanio can you explain how can we set a custom bit rate?
What is the meaning of 9,7,3... numbers?

I'd like to see a post presenting this knowledge.

Ascanio:
Hi guyz!

I am trying to figure out how to interface my Arduino UNO R3 with an OEM rotary controller device (in my specific case it is a BMW iDrive device from an X3).

My intention is to use Arduino as a proxy, so to be able to use the rotary controller without drivers on any computer, by emulating a keyboard and mouse.

Devices such as the iDrive rotary controller are interfaced via CAN bus (in fact the connector has 4 pins, which I guess will read out to VIN, GND, CAN-H, CAN-L).

I have already purchased the Sparkfun CAN-bus Shield, but haven't had time to try the CAN libraries available on the web.
I know such libraries are usually directed at connecting to an existing CAN network (through the OBD-II diagnostic port on vehicles). Has anybody successfully INITIATED a network with this shield (I guess the iDrive rotary device will in turn try to connect as a slave)?

Cheers to all! May you spend a lovely time with your families this Christmas :slight_smile:

hello

how did i go? i have the same plane, but using a rpi

I have used an arduino to control a turbo.. It's been a while since i looked at the specific code for that section though.. I do know that I was able to sniff the packets sent by the turbo telling me it's current parameters.. I used the standard CAN bus library.

MCP CAN1(10); 'pin 10 is the SPI SS pin

#define VGTaddress  0x0CFFC600UL      //CAN bus address of the VGT controller
#define StatusMessageID  0x18FFC502UL //this is the message id of the messages we're concerned with
#define BreakMessageID  0x18FF0A02UL  //This is the message id of a 'terminator' string, or something... no relevant information it seems
#define ErrorMessageID  0x18EEFF02UL  //Seems to be an error message ID when low voltage is triggered?

void loop(){
ReadCanMessages();
}

void ReadCanMessage() {
	//This is from the MCP examples, modified to work for what I need
	unsigned long ID;                                       // assign a variable for Message ID
	byte length;                                            //assign a variable for length
	byte data[8];                                           //assign an array for data


	if (CAN1.msgAvailable()) {                      // Check to see if a valid message has been received.
		CanMessagesReceived++;

		CAN1.read(&ID, &length, data);                        // read Message and assign data through reference operator &

		if (ID == StatusMessageID) {
			VgtCommandPosition = ((data[6] * 256) + data[5]);
			VgtRealPosition = ((data[2] * 256) + data[1]);
			VgtMotorCommandSpeed = data[7] - 127;
			VgtRawTemp = data[3];
		}
		else if (ID == BreakMessageID) {
			//do nothing.. it's an unimportant message
		}
		else if (ID == ErrorMessageID) {
			PrintCANmessage(ID, length, data);
		}
		else {
			//we got a new message type.. lets figure it out
			//PrintCANmessage(ID, length, data);

		}
	}
}
void PrintCANmessage(unsigned long ID, byte length, byte* data) {
	Serial.print("CanMessage = ID");
	Serial.print(" | 0x");
	Serial.print(ID, HEX);                                 // Displays received ID
	Serial.print(" | ");
	Serial.print("Data Length DEC");
	Serial.print(" | ");
	Serial.print(length);                               // Displays message length
	Serial.print(" | ");
	Serial.print("Data");
	for (byte i = 0; i < length; i++) {
		Serial.print(" | ");
		if (data[i] < 0x10)                                   // If the data is less than 10 hex it will assign a zero to the front as leading zeros are ignored...
		{
			Serial.print("0");
		}
		Serial.print(data[i], HEX);                          // Displays message data
	}
	Serial.println();

}

Hope this helps a little

Just noticed how darned old this thread is!