My own ECU simulator

I’m building my own car simulator using the next components:

  • Arduino UNO
  • mcp2515 breakout
  • A obd female cable extension

I’m using the next code:

#include <SPI.h>
#include <mcp_can.h>

const int SPI_CS_PIN = 10; 
INT32U canId = 0x000; 
MCP_CAN CAN(SPI_CS_PIN);
unsigned char len = 0;
unsigned char buf[8]; 
int PID = 0; 
int MODE = 0;

void setup() {
  Serial.begin(9600); 

  if(CAN_OK == CAN.begin(CAN_500KBPS)) {
    Serial.println("Init done");
  } else {
    Serial.println("Error on init");
  }  
}

void loop() {
  //CAN.readMsgBuf(&len, buf); 
  if(CAN_MSGAVAIL == CAN.checkReceive()) {

    CAN.readMsgBuf(&len, buf); 
    canId = CAN.getCanId(); 
    PID = buf[2]; 
    MODE = buf[1];

    Serial.print("PID ");
    Serial.print(PID, HEX);
    Serial.print(" MODE ");
    Serial.println(MODE);

    if(MODE == 1) {
      unsigned char OBDIImsg[8] = {4, 65, 0x0C, 0, 0, 0, 0, 0};       
      
      switch (PID){
        case 0: // PID 00 hex
          OBDIImsg[0] = 6;
          OBDIImsg[3] = 0x88;
          OBDIImsg[4] = 0x18;
          OBDIImsg[5] = 0x80;
          OBDIImsg[6] = 0x13;
          CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg); // Respuesta
          break;      
        case 12:
          OBDIImsg[3] = 100 * 4 / 256;
          OBDIImsg[4] = 100 - (100 * 4 / 256);
          CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg);
          break;
        case 13:
          OBDIImsg[3] = 75;
          CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg);
          break;
        case 4:
          OBDIImsg[3] = 98;
          CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg);
          break;
        case 31: // PID 19 hex
          OBDIImsg[3] = (millis()/1000)/256;
          OBDIImsg[4] = (millis()/1000) - (millis()/1000)/256;
          CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg);
          break;     
        case 47: // PID 2F hex
          OBDIImsg[3] = 60; 
          CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg);
          break;
      }      
    } else if (MODE == 3) {
      unsigned char OBDIImsg[8] = {6, 67, 0, 0, 0, 0, 0, 0};

      OBDIImsg[2] = 1; // Número de DTCs = 1
      OBDIImsg[3] = 2; // P0217 Sobrecalentamiento del motor HIGH
      OBDIImsg[4] = 23; // P0217 Sobrecalentamiento del motor LOW

      CAN.sendMsgBuf(0x7E8, 0, 8, OBDIImsg);    
    }    
  }
}

If I test the code using the elm327 (bluetooth) and an app in my phone, the messages are sent/received as expected; When I connect the Carloop adapter and a sample code reader sketch the communication isn’t done.

Also, I’ve tested the carloop adapter and the same sketch in my car and the communication is performed well.

Is there any consideration I have to do in the arduino side to be compatible with the carloop adapter/library ?

UPDATE

I’m trying other approach; I’m using the can hitch connected as follows:

Particle Photon (ECU Simulator) ==> Carloop CAN Hitch ==> Female extension OBD cable ===> Carloop adapter ===> Particle electron

Again, this setup works with the ELM327; the photon receives all the requests sent by the phone app through the ELM327, but also again, the photon (the ECU simulator) doesn’t receives messages when switched to the electron.

My code is :

#include <carloop.h>

const auto OBD_REQUEST_ID      = 0x7E0;
const auto OBD_REPLY_ID        = 0x7E8;
const auto OBD_PID_SERVICE     = 0x01;

SYSTEM_THREAD(ENABLED); // To not block the main program while searching for WiFi
Carloop<CarloopRevision2> carloop; // Instantiate Carloop Object

SYSTEM_MODE(SEMI_AUTOMATIC);

int mode = 0;
int pid = 0;

void processMode1(int pid);
void processMode2(int pid);

void setup() {
    carloop.begin(); // Creates the appropriate CANChannel
    Serial.begin(9600); // Open serial connection at 9600 baud, bits per second
    Serial.print("Starting Up \n");
    
    WiFi.connect();
}
void loop() {
    CANMessage message;

    while(carloop.can().receive(message)) {
        mode = message.data[1];
        pid = message.data[2];
        
        Serial.print("Mode ");
        Serial.print(mode);
        Serial.print(" Pid ");
        Serial.println(pid);
        
        if(mode == 1) {
            processMode1(pid);
        }
    }
}

void processMode1(int pid) {
    CANMessage message;
    message.id = 0x7E8;
    message.len = 8;
        
    if(pid == 0) {
        message.data[0] = 6;
        message.data[3] = 0x88;
        message.data[4] = 0x18;
        message.data[5] = 0x80;
        message.data[6] = 0x13;
    } else if(pid == 12) {
        message.data[3] = 100 * 4 / 256;
        message.data[4] = 100 - (100 * 4 / 256);        
    } else if(pid == 13) {
        message.data[3] = 75;
    } else if(pid == 4) {
        message.data[3] = 98;
    } else if(pid == 31) {
        message.data[3] = (millis() / 1000)/256;
        message.data[4] = (millis() / 1000) - (millis() / 1000) / 256;
    } else if(pid == 47) {
        message.data[3] = 60;
    }
    
    carloop.can().transmit(message);
}

void processMode2(int pid) {
    
} 

The electron code as I wrote before works when I connect to my car. Any ideas ?

Never mind … I solved the issue. I’ll be working on a project to release the schematics, code and components soon.

I was dealing with complexities related to the carloop simulator, which is a great tool, but it’s complex to get working with it.

I wrote an app that uses a particle electron and a Carloop CAN Hitch. The wiring is as follows:

Paticle electron Can HITCH

D1 TX
D2 RX
3v3 3v3
GND GND

The CAN hitch has to be connected to H/L of the female extension cable. The ECU simulator code

Perhaps in the future I will create the schematic, but so far is pretty simple.

1 Like

@maleficarum,

Nice work on getting that going!

I have not looked at the ECU simulator code, but how well are you able to simulate a real ECU?
Are you simulating a particular ECU or just creating a generic simulator?

The ECU code is implemented to send ISO 15765-4 CAN (11 bit ID, 500 Kbaud) messages. But with some adjustements the code will work to handle:

  • ISO 15765-4 CAN (29 bit ID,500 Kbaud)
  • ISO 15765-4 CAN (11 bit ID,250 Kbaud) It would be done only changing the speed at init.
  • ISO 15765-4 CAN (29 bit ID,250 Kbaud)

Does it respond to all the OBD2 standard PIDs?

As far as I can remeber, responds to :

  • Speed
  • RPMs
  • Uptime
  • Distance since codes cleared
  • DTC codes

Can be added more, but those are the codes I needed in my implementation so far.

Hi,
It is a nice job,hows going now?
I try to follow you to do some test, firstly failed on Sketch compile with error:
/no matching function for call to ‘MCP_CAN::begin(int)’ /
can you help?
Thanks
Adam

Can you post your code ?

Thanks
I’m using your code below ’ I’m using the next code: ’ in your post.

I compiled the posted code with no errors :

using the firmware version v1.2.1-rc.3. It would be the firmware version you are using as a target.

here is the error code:
sketch_oct26c:15:37: error: no matching function for call to ‘MCP_CAN::begin(int)’

if(CAN_OK == CAN.begin(CAN_500KBPS)) {

                                 ^

In file included from C:\Users\HUA.DELLV-PC\Documents\Arduino\sketch_oct26c\sketch_oct26c.ino:2:0:

C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master/mcp_can.h:108:11: note: candidate: byte MCP_CAN::begin(byte, byte, byte)

 INT8U begin(INT8U idmodeset, INT8U speedset, INT8U clockset);       // Initialize controller parameters

       ^

C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master/mcp_can.h:108:11: note: candidate expects 3 arguments, 1 provided

C:\Users\HUA.DELLV-PC\Documents\Arduino\sketch_oct26c\sketch_oct26c.ino: In function ‘void loop()’:

sketch_oct26c:26:29: error: no matching function for call to ‘MCP_CAN::readMsgBuf(unsigned char*, unsigned char [8])’

 CAN.readMsgBuf(&len, buf); 

                         ^

In file included from C:\Users\HUA.DELLV-PC\Documents\Arduino\sketch_oct26c\sketch_oct26c.ino:2:0:

C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master/mcp_can.h:116:11: note: candidate: byte MCP_CAN::readMsgBuf(long unsigned int*, byte*, byte*, byte*)

 INT8U readMsgBuf(INT32U *id, INT8U *ext, INT8U *len, INT8U *buf);   // Read message from receive buffer

       ^

C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master/mcp_can.h:116:11: note: candidate expects 4 arguments, 2 provided

C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master/mcp_can.h:117:11: note: candidate: byte MCP_CAN::readMsgBuf(long unsigned int*, byte*, byte*)

 INT8U readMsgBuf(INT32U *id, INT8U *len, INT8U *buf);               // Read message from receive buffer

       ^

C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master/mcp_can.h:117:11: note: candidate expects 3 arguments, 2 provided

sketch_oct26c:27:17: error: ‘class MCP_CAN’ has no member named ‘getCanId’

 canId = CAN.getCanId(); 

             ^

Using library SPI at version 1.0 in folder: C:\Users\HUA.DELLV-PC\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.11\libraries\SPI
Using library MCP_CAN_lib-master in folder: C:\Users\HUA.DELLV-PC\Documents\Arduino\libraries\MCP_CAN_lib-master (legacy)
exit status 1
no matching function for call to ‘MCP_CAN::begin(int)’

I didnt include any additional library such as SPI, you only need to include Carloop, and anything else would work.

Are you trying to compile using Arduino IDE?

Yes, I used Arduino 1.8.8, what did you use?
Some one said there is earlier vision MCP_CAN.h, do you have it?

I use vscode with the paticle workbench extension. It would be the issue. In arduino IDE you need to have to add all the libraries needed, and with particle workbench all the extensions needed by carloop2 would be imported with the proper versions. Other issue would be that in the Arduino ide you cannot (as far as I know) compile and flash to particle devices, and Carloop es developed to work with particle devices.

Hi there,

I’m new to CAN but quite experenced re car electronics.

I need some help as I try to send the VIN of a CAR via CAN…
The ECU is not present and I need the VIN present for other purposes.

VIN is SALLDWBP8DA431032

How do I convert this into the proper multi-segment message like it would be sent from the ECU?
Is this a difficult task?

BR
Ralf

perhaps you can read the next cose to understand how the request is made and how the response is send by the ECU.

app-vin-reader/ at master · carloop/app-vin-reader · GitHub

hope it helps.