Mitsubishi Outlander PHEV heater

Mitsubishi hybrid drive unit hacking
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

arber333 wrote: Mon Feb 05, 2024 4:41 pm Like i said heater wants to go all the way to 85deg if you let it. Thats a waste of power. I wanted to use a limit to lower this to 55 as the kj are less there = less kWh.
May i use your posted code to setup my loop instead of pot? It should work on any teensy...? Or do you use teensy?
Sorry mate I'm a bit confused by this. With Turbopete's code the water temp seems to rise to the desired temperature then it turns off. I set it to 51C and watched it rise to that temp, then it turned off until it dropped to 50C then turned on again.

Would it help reduce energy drain (and help it last longer) if the current was then dropped to keep the temp constant? It seemed to be on full power so over shot the desired temp by 1 or 2 deg C but I guess this would be less of an issue with the water pumping through a heater matrix.
I need a bigger hammer!
User avatar
EV_Builder
Posts: 1199
Joined: Tue Apr 28, 2020 3:50 pm
Location: The Netherlands
Has thanked: 16 times
Been thanked: 33 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by EV_Builder »

Isn't there a CAN Log available from a real PHEV from which we can learn a bit if it regulates?
Converting an Porsche Panamera
see http://www.wdrautomatisering.nl for bespoke BMS modules.
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

arber333 wrote: Mon Feb 05, 2024 6:19 pm I went through the code quickly and eliminated anything connected with pot.
I used Heater_pin which is the same pin as A0 analog, only digital side... i think it is D14
Then i removed reading of desired temperature as i find it unneccesary. I removed cconnected conditional as well.

The way this code works is to transmitt complete 0x188 telegram each 100ms. If we toggle the switch to GND(pullup) it will command heater to turn ON. It reads its own temperature and govern the loop by 5deg hysteresis if not turning OFF when reaching 55deg. You can of course set any temperature in code. You could even use the pot to set variable for desired temperature and use a different pin to start the process. I may go and write another code...

See if it works directly as you can load the pot directly to GND to activate the pin with the same circuit. But i would change to toggle switch soon.
CODE: SELECT ALL

#include <mcp_can.h>
#include <SPI.h>
#include <TaskScheduler.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define INVERTPOT true
#define OPENINVERTERCONTACTORS //uncomment to check can bus for Open Inverter opmode for contactors, prevents heating over precharge resistor
#ifdef OPENINVERTERCONTACTORS
unsigned long inverterLastRec;
byte inverterStatus;
#endif
unsigned long temperatureLastRec;


#define MAXTEMP 85
#define MINTEMP 40
bool enabled = false;
bool hvPresent = false;
bool heating = false;
int power = 20;
uint8_t Heatertemp = 0;
//const int potPin = A0;
const int Heater_pin = D14; //What is the equivalent digital input to A0?
const int ledPin = 3;

long unsigned int canId;
unsigned char len = 0;
unsigned char buf[8];
char msgString[128]; // Array to store serial string



#define CAN_INT 2 // Set INT to pin 2
MCP_CAN CAN(10); // Set CS to pin 10

void ms10Task();
void ms100Task();
void ms1000Task();

Task ms10(10, -1, &ms10Task);
Task ms100(100, -1, &ms100Task);
Task ms1000(1000, -1, &ms1000Task);

Scheduler runner;

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

// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
displayOff();
Serial.println("Outlander Heater Control");
pinMode(ledPin, OUTPUT);
pinMode(Heater_pin,INPUT_PULLUP); // set Heater pin to input with using built in pull up resistor

//while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_8MHz)) // init can bus : baudrate = 500k
//while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ))
// Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
if(CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
// Serial.println("MCP2515 Initialized Successfully!");
Serial.println("CAN BUS Shield init ok!");
else
// Serial.println("Error Initializing MCP2515...");
Serial.println("CAN BUS Shield init fail");

CAN.setMode(MCP_NORMAL); // Set operation mode to normal so the MCP2515 sends acks to received data.

pinMode(CAN_INT, INPUT); // Configuring pin for /INT input

// Serial.println("MCP2515 Library Receive Example...");


Serial.println("CAN BUS Shield init ok!");

runner.init();

runner.addTask(ms10);
ms10.enable();

runner.addTask(ms100);
ms100.enable();

runner.addTask(ms1000);
ms1000.enable();

}

void displayTemperature(void) {
display.clearDisplay();
display.setTextSize(3); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 10);
display.print(currentTemperature);
display.print("/");
// display.print(targetTemperature);

if (power == 2) {
display.fillRect(0, 0, 10, SCREEN_HEIGHT, SSD1306_WHITE);
} else if (power == 1) {
display.fillRect(0, SCREEN_HEIGHT/2, 10, SCREEN_HEIGHT, SSD1306_WHITE);
}

display.display(); // Show initial text
}

void displayOff(void) {
display.clearDisplay();
display.setTextSize(3); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.setCursor(40, 10);
display.println(F("Off"));
display.display(); // Show initial text
}


void ms10Task() {
//send 0x285
uint8_t canData[8];
canData[0] = 0x00;
canData[1] = 0x00;
canData[2] = 0x14;
canData[3] = 0x21;
canData[4] = 0x90;
canData[5] = 0xFE;
canData[6] = 0x0C;
canData[7] = 0x10;

CAN.sendMsgBuf(0x285, 0, sizeof(canData), canData);
}

void ms100Task() {
int sensorValue = analogRead(potPin);

// if (INVERTPOT) {
// if (sensorValue < 923) {
// enabled = true;
// } else {
// enabled = false;
// }
// } else {
// if (sensorValue > 100) {
// enabled = true;
// } else {
// enabled = false;
// }
// }

//if heater is not sending feedback, disable it, safety and that
if (millis() - temperatureLastRec > 1000) {
enabled = false;
Serial.println("No Temperature recieved");
}

// if (INVERTPOT) {
// targetTemperature = map(sensorValue, 1023, 100, MINTEMP, MAXTEMP);
// } else {
// targetTemperature = map(sensorValue, 100, 1023, MINTEMP, MAXTEMP);
// }

//send 0x188
#ifdef OPENINVERTERCONTACTORS
bool contactorsClosed = inverterStatus == 0x01;
if (!contactorsClosed) {
enabled = false;
}
#else
bool contactorsClosed = true;
#endif

digitalWrite(ledPin, enabled);

if (enabled) {
displayTemperature();
} else {
displayOff();
}


if (contactorsClosed && enabled) {
uint8_t canData[8];
if(digitalRead(Heater_pin) == LOW) { // if heater pin is ON
canData[0] = 0x03; }
else {
canData[0] = 0x00;
}
canData[1] = 0x50;
if(Heatertemp > 55) { // if temp is higher than 55deg
canData[2] = 0x00;
}
else if(Heatertemp > 50) { // if temp is higher than 50deg
canData[2] = 0x32; // seems to be current command (dec/10)
}
else {
canData[2] = 0xA2;
}
canData[3] = 0x40;
canData[4] = 0x00;
canData[5] = 0x00;
canData[6] = 0x00;
canData[7] = 0x00;

CAN.sendMsgBuf(0x188, 0, sizeof(canData), canData);
} else {
power = 0;
}

}


void ms1000Task() {
Serial.println("Heater Status");
Serial.print("HV Present: ");
Serial.print(hvPresent);
Serial.print(" Heater Active: ");
Serial.print(heating);
Serial.print(" Water Temperature: ");
Serial.print(Heatertemp);
Serial.println("C");
Serial.println("");
Serial.println("Settings");
Serial.print(" Heating: ");
Serial.print(enabled);
Serial.print(" Inverter: ");
Serial.print(inverterStatus);
Serial.println("");
Serial.println("");

}

void loop() {
// put your main code here, to run repeatedly:
runner.execute();
//if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
//{
//CAN.readMsgBuf(&canId, &len, buf); // read data, len: data length, buf: data buf
//unsigned int canId = CAN.getCanId(); this line can be removed
//if (canId == 0x398) {

if(!digitalRead(CAN_INT)) // If CAN_INT pin is low, read receive buffer
{
CAN.readMsgBuf(&canId, &len, buf); // Read data: len = data length, buf = data byte(s)

if((canId & 0x80000000) == 0x80000000) // Determine if ID is standard (11 bits) or extended (29 bits)
sprintf(msgString, "Extended ID: 0x%.8lX DLC: %1d Data:", (canId & 0x1FFFFFFF), len);
else
sprintf(msgString, "Standard ID: 0x%.3lX DLC: %1d Data:", canId, len);

//Serial.print(msgString);

if((canId & 0x40000000) == 0x40000000){ // Determine if message is a remote request frame.
sprintf(msgString, " REMOTE REQUEST FRAME");
//Serial.print(msgString);
} else {
for(byte i = 0; i<len; i++){
sprintf(msgString, " 0x%.2X", buf);
//Serial.print(msgString);
}
}
// unsigned int canId = CAN.getCanId();
if (canId == 0x398) {
//Heater status
if (buf[5] == 0x00) {
heating = false;
power = 0;
} else if (buf[5] > 0) {
heating = true;
}
//hv status
if (buf[6] == 0x09) {
hvPresent = false;
} else if (buf[6] == 0x00) {
hvPresent = true;
}

//temperatures
unsigned int temp1 = buf[3] - 40;
unsigned int temp2 = buf[4] - 40;
if (temp2 > temp1) {
Heatertemp = temp2;
} else {
Heatertemp = temp1;
}
temperatureLastRec = millis();
}
#ifdef OPENINVERTERCONTACTORS
if (canId == 0x02) {
inverterLastRec = millis();
inverterStatus = buf[0];
}
#endif

}

#ifdef OPENINVERTERCONTACTORS
#endif
}


Thanks for this as it tidies things up nicely but to be honest I like the idea of seeing the temp requested and current temp in the display, plus having a pot to adjust the temperature seems like a good idea, even if it is only until I figure out what the ideal temperature is.
I received a couple of displays in the post today and managed to hook one up.

To my amazement I managed to do it right first time and it just works. :D

IMG_20240207_133836357_BURST000_COVER.jpg
BTW the green cable is just shorting out the pins in the MCP2515 to enable the CAN network termination. Even with only a single 120R terminating resistor it works fine but I'll ensure both are connected in the final installation.
I need a bigger hammer!
arber333
Posts: 3265
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 234 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Alibro wrote: Wed Feb 07, 2024 2:07 pm To my amazement I managed to do it right first time and it just works.
Nicely done. I am glad it worked right away.
Alibro wrote: Wed Feb 07, 2024 2:07 pm having a pot to adjust the temperature seems like a good idea, even if it is only until I figure out what the ideal temperature is.
Yes i had to test the end temperature a couple of times as 50deg was ok with 0deg outside, but when -7 in the morning 55deg coolant would perform much better. But i still like to keep my control loops simple without too much sensors and inputs.
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

arber333 wrote: Wed Feb 07, 2024 2:37 pm Yes i had to test the end temperature a couple of times as 50deg was ok with 0deg outside, but when -7 in the morning 55deg coolant would perform much better. But i still like to keep my control loops simple without too much sensors and inputs.
I agree about keeping things simple so I will give myself the option of doing this when installing it. I don't think I will have the POT in the car to keep the installation as clean as possible and would probably never use it anyway once the correct temperature for my car is set.

Have you been able to use any of the heat coming from the heater casing? I was wondering about routing the air feed for the heater fan past the heater as there is so much wasted heat coming from it.
I need a bigger hammer!
arber333
Posts: 3265
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 234 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Alibro wrote: Wed Feb 07, 2024 2:50 pm Have you been able to use any of the heat coming from the heater casing? I was wondering about routing the air feed for the heater fan past the heater as there is so much wasted heat coming from it.
What do you mean by that? Use the heat for heating the battery by air? You could use the lower tubes that extend to the rear seats maybe...
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

I was thinking of feeding the air that goes into the cabin over the coolant heater. That way the air would be warmed a little even before it reached the heater matrix as the casing for it gets very warm. I suspect putting the outlander heater into a box so all the hot air could be drawn into the cabin could cause safety issues but maybe a shroud half way around it that feeds into the hvac inlet would be OK.
I need a bigger hammer!
arber333
Posts: 3265
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 234 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

Alibro wrote: Wed Feb 07, 2024 4:54 pm I was thinking of feeding the air that goes into the cabin over the coolant heater.
Physics says air is not a good medium to transpost heat. You would do better if you would isolate the heater from outside and put a heat exchanger into a battery compartment. Possibly a heater matrix from a small car? That and a simple fan will help use any energy that is left from the cabin compartment. I can feel high temperature on return line still.
You could use 3way valve to open the return path to the battery if needed and have it closed if not.
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

arber333 wrote: Wed Feb 07, 2024 5:05 pm Physics says air is not a good medium to transpost heat.
It was just a thought that the casing of the Outlander heater gets very hot and all this heat is wasted so if we could scavenge even a little by simply diverting the intake for the HVAC it might be worth doing. In my case I have a lot of work to do just to remove the non functioning Leaf heater and mounting the Outlander heater so will not be spending a lot of time on it. ;)
I need a bigger hammer!
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Just in case anyone is following this thread and needs to know what components to purchase these are the parts that worked for me.

Arduino Nano (I used a genuine one)---------------- https://amzn.to/3uA3str
MCP2515 CAN module (8Mhz)------------------------- https://amzn.to/487fZm6
I2C OLED Display Module 0.91" 128 x 32 pixels----- https://amzn.to/49ov9V1
4k7 POT--------------------------------------------------- https://amzn.to/3wbe42v ** Edit - A 1k linear POT works much better than 4K7 **
Traco Power 5V TSR 1-2450---------------------------- https://ebay.us/JHKUnI
Outlander 12V and CAN Connector------------------- https://ebay.us/2cH3c5 ** This is not the connector I bought but it appears to be the same. **

MCP2515----------------Nano
INT........................D2
SCK.......................D13
SI.........................D11
SO........................D12
CS........................D10
GND......................GND
VCC......................5V

OLED Display------------Nano
SDA.......................A4
SCK.......................A5
GND......................GND
VCC......................5V

POT----------------------Nano
Pin 1.....................5V
Pin 2 (wiper)...........A0
Pin3.....................GND

If you want to use TurboPete's code be aware it will not send the "On" message 0x188 until it sees 'Contactor on) from the VCU.
If you don't have this connected you will need to comment out the first line with "OPENINVERTERCONTACTORS" in it plus line 231 "Serial.print(inverterStatus);"
In my case I have the heater connected such that it only gets power after the positive contactor is enabled.

This is the code already amended.

Code: Select all

#include <mcp_can.h>
#include <SPI.h>
#include <TaskScheduler.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define INVERTPOT true
// #define OPENINVERTERCONTACTORS //uncomment to check can bus for Open Inverter opmode for contactors, prevents heating over precharge resistor
#ifdef OPENINVERTERCONTACTORS
unsigned long inverterLastRec;
byte inverterStatus;
#endif
unsigned long temperatureLastRec;


#define MAXTEMP 85
#define MINTEMP 40
unsigned int targetTemperature = 0;
bool enabled = false;
bool hvPresent = false;
bool heating = false;
int power = 20;
int currentTemperature = 0;
const int potPin = A0;
const int ledPin = 3;

long unsigned int canId;
unsigned char len = 0;
unsigned char buf[8];
char msgString[128];                        // Array to store serial string



#define CAN_INT 2                              // Set INT to pin 2
MCP_CAN CAN(10);                               // Set CS to pin 10

void ms10Task();
void ms100Task();
void ms1000Task();

Task ms10(10, -1, &ms10Task);
Task ms100(100, -1, &ms100Task);
Task ms1000(1000, -1, &ms1000Task);

Scheduler runner;

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

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
      Serial.println(F("SSD1306 allocation failed"));
      for(;;); // Don't proceed, loop forever
    }
    displayOff();
    Serial.println("Outlander Heater Control");
    pinMode(ledPin, OUTPUT);
    
    //while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_8MHz))              // init can bus : baudrate = 500k
    //while (CAN_OK != CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ))
      // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
//    Serial.println("MCP2515 Initialized Successfully!");
      Serial.println("CAN BUS Shield init ok!");
  else
//    Serial.println("Error Initializing MCP2515...");
      Serial.println("CAN BUS Shield init fail");
      
  CAN.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN_INT, INPUT);                            // Configuring pin for /INT input
  
 // Serial.println("MCP2515 Library Receive Example...");
 

    Serial.println("CAN BUS Shield init ok!");

    runner.init();

    runner.addTask(ms10);
    ms10.enable();

    runner.addTask(ms100);
    ms100.enable();

    runner.addTask(ms1000);
    ms1000.enable();

}

void displayTemperature(void) {
  display.clearDisplay();
  display.setTextSize(3); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 10);
  display.print(currentTemperature);
  display.print("/");
  display.print(targetTemperature);

  if (power == 2) {
      display.fillRect(0, 0, 10, SCREEN_HEIGHT, SSD1306_WHITE);
  } else if (power == 1) {
      display.fillRect(0, SCREEN_HEIGHT/2, 10, SCREEN_HEIGHT, SSD1306_WHITE);
  }

  display.display();      // Show initial text
}

void displayOff(void) {
  display.clearDisplay();
  display.setTextSize(3); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(40, 10);
  display.println(F("Off"));
  display.display();      // Show initial text
}


void ms10Task() {
  //send 0x285
   uint8_t canData[8];
   canData[0] = 0x00;
   canData[1] = 0x00;
   canData[2] = 0x14;
   canData[3] = 0x21;
   canData[4] = 0x90;
   canData[5] = 0xFE;
   canData[6] = 0x0C;
   canData[7] = 0x10;

   CAN.sendMsgBuf(0x285, 0, sizeof(canData), canData);
}

void ms100Task() {
  int sensorValue = analogRead(potPin);

  if (INVERTPOT) {
    if (sensorValue < 923) {
      enabled = true;
    } else {
      enabled = false;
    }
  } else {
    if (sensorValue > 100) {
      enabled = true;
    } else {
      enabled = false;
    }
  }

  //if heater is not sending feedback, disable it, safety and that
  if (millis() - temperatureLastRec > 1000) {
    enabled = false;
    Serial.println("No Temperature recieved");
  }

  if (INVERTPOT) {
      targetTemperature = map(sensorValue, 1023, 100, MINTEMP, MAXTEMP);
  } else {
      targetTemperature = map(sensorValue, 100, 1023, MINTEMP, MAXTEMP);
  }

    //send 0x188
  #ifdef OPENINVERTERCONTACTORS
  bool contactorsClosed = inverterStatus == 0x01;
  if (!contactorsClosed) {
    enabled = false;
  }
  #else
  bool contactorsClosed = true;
  #endif

  digitalWrite(ledPin, enabled);

  if (enabled) {
    displayTemperature();
  } else {
    displayOff();
  }
   

  if (contactorsClosed && enabled && currentTemperature < targetTemperature) {
   uint8_t canData[8];
   canData[0] = 0x03;
   canData[1] = 0x50;
   canData[3] = 0x4D;
   canData[4] = 0x00;
   canData[5] = 0x00;
   canData[6] = 0x00;
   canData[7] = 0x00;

   //switch to lower power when reaching target temperature
   if (currentTemperature < targetTemperature - 10) {
    canData[2] = 0xA2;
    power = 2;
   } else {
    canData[2] = 0x32;
    power = 1;
   }
   
    CAN.sendMsgBuf(0x188, 0, sizeof(canData), canData);
  } else {
    power = 0;
  }

}


void ms1000Task() {
  Serial.println("Heater Status");
  Serial.print("HV Present: ");
  Serial.print(hvPresent);
  Serial.print(" Heater Active: ");
  Serial.print(heating);
  Serial.print(" Water Temperature: ");
  Serial.print(currentTemperature);
  Serial.println("C");
  Serial.println("");
  Serial.println("Settings");
  Serial.print(" Heating: ");
  Serial.print(enabled);
  Serial.print(" Desired Water Temperature: ");
  Serial.print(targetTemperature);
  Serial.print(" Inverter: ");
//  Serial.print(inverterStatus); Uncomment to check can bus for Open Inverter opmode for contactors, prevents heating over precharge resistor
  Serial.println("");
  Serial.println("");

}

void loop() {
  // put your main code here, to run repeatedly:
  runner.execute();
  //if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
  //{
       //CAN.readMsgBuf(&canId, &len, buf);    // read data,  len: data length, buf: data buf
       //unsigned int canId = CAN.getCanId(); this line can be removed
       //if (canId == 0x398) {

if(!digitalRead(CAN_INT))                         // If CAN_INT pin is low, read receive buffer
  {
    CAN.readMsgBuf(&canId, &len, buf);      // Read data: len = data length, buf = data byte(s)
    
    if((canId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
      sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (canId & 0x1FFFFFFF), len);
    else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", canId, len);
  
    //Serial.print(msgString);
  
    if((canId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.
      sprintf(msgString, " REMOTE REQUEST FRAME");
      //Serial.print(msgString);
    } else {
      for(byte i = 0; i<len; i++){
        sprintf(msgString, " 0x%.2X", buf[i]);
        //Serial.print(msgString);
      }
    }
 //       unsigned int canId = CAN.getCanId();
        if (canId == 0x398) {
          //Heater status
          if (buf[5] == 0x00) {
            heating = false;
            power = 0;
          } else if (buf[5] > 0) {
            heating = true;
          }
          //hv status
          if (buf[6] == 0x09) {
            hvPresent = false;
          } else if (buf[6] == 0x00) {
            hvPresent = true;
          }

          //temperatures
          unsigned int temp1 = buf[3] - 40;
          unsigned int temp2 = buf[4] - 40;
          if (temp2 > temp1) {
            currentTemperature = temp2;
          } else {
            currentTemperature = temp1;
          }
          temperatureLastRec = millis();
        }
        #ifdef OPENINVERTERCONTACTORS
        if (canId == 0x02) {
          inverterLastRec = millis();
          inverterStatus = buf[0];
        }
        #endif

    }

    #ifdef OPENINVERTERCONTACTORS
//      if(inverterLastRec + 500 < millis()) {
//        inverterStatus = 0;
//      }
    #endif
  }
I need a bigger hammer!
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

I used some vero board to make this a bit more robust.
IMG_20240210_134259946.jpg
IMG_20240210_134330876.jpg
I also added a buck converter to lower the voltage to around 6V as I wasn't sure the Nano would be happy with 14.4V. What are your thoughts on this guys and should I do the same for the Due and Uno in the low voltage junction box?

I'll probably have to cut and splice some of the wiring when installing but wanted to test I hadn't cocked something up first.
I need a bigger hammer!
User avatar
marcexec
Posts: 122
Joined: Tue May 14, 2019 12:52 pm
Location: Dublin, Ireland
Has thanked: 536 times
Been thanked: 45 times

Re: Mitsubishi Outlander PHEV heater

Post by marcexec »

I'd measure the difference in power draw between buck converter vs direct. In general lower consumption would mean less heat, so more reliable. OTHO you're introducing another point of failure, if it fails open that is.
A motorcyclist is never late, Frodo Baggins. Nor is he early. He arrives precisely when he means to.
Getting started guide for Celeron55's iPDM56
My Suzuki RF400 build @ES
Honda IMA & Lebowski howto
Image
User avatar
crasbe
Posts: 243
Joined: Mon Jul 08, 2019 5:18 pm
Location: Germany
Has thanked: 44 times
Been thanked: 107 times

Re: Mitsubishi Outlander PHEV heater

Post by crasbe »

You could simply set the Buck converter to 5V and connect it's output to the +5V pin of the Arduino Nano instead of the VIN pin.
That bypasses the internal LDO completely.
That would be the better strategy anyway, because 6V is right on the edge of the permissible input voltage. The dropout voltage of the LM1117IMPX-5.0 is greater than 1.0V at room temperature.


And no, the LDO wouldn't really love 14.4V input voltage. Even though it might not explode immediately, the tiny package of the LDO on the Arduino Nano is not able to dissipate much heat.


A word of caution in regards to the LM2596 buck converter you have used: They usually come with a faked chip which has a lower efficiency (not really relevant for your case) due to a lower switching frequency. The catch is that sometimes (not always, because you can't predict what the Chinese put on there) the boards come with mismatched capacitors and inductors, resulting in a higher-than-usual output noise. That in turn can lead to unreliable operation, which is less than desirable in an automotive application.


My recommendation are these cute, integrated step-down converters from TRACO (and many other suppliers) like this one: https://www.mouser.de/ProductDetail/TRA ... oeVA%3D%3D

The Mouser link is just an example, idk where to buy stuff in the UK.
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Sorry guys I somehow managed to unsubscribe from the topic and missed your replies.

So the consensus is Arduino's don't like 14.4V and cheap Chinese buck converters may not be reliable. I'm not surprised at the answers so will follow your advice and come up with a better solution.
I need a bigger hammer!
User avatar
marcexec
Posts: 122
Joined: Tue May 14, 2019 12:52 pm
Location: Dublin, Ireland
Has thanked: 536 times
Been thanked: 45 times

Re: Mitsubishi Outlander PHEV heater

Post by marcexec »

Alibro wrote: Tue Feb 13, 2024 4:07 pm So the consensus is Arduino's don't like 14.4V and cheap Chinese buck converters may not be reliable. I'm not surprised at the answers so will follow your advice and come up with a better solution.
Just found my Digikey order, I'm using an isolated one on the motorbike for the Lebowski/Honda IMA to step down 4S / 16.8V: https://www.digikey.ie/en/products/deta ... 3/16348346
A motorcyclist is never late, Frodo Baggins. Nor is he early. He arrives precisely when he means to.
Getting started guide for Celeron55's iPDM56
My Suzuki RF400 build @ES
Honda IMA & Lebowski howto
Image
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Digikey, Mouser, Farnell etc are great for bigger orders but for small orders charge a lot for delivery and handling.
I found the same one on Ebay for a similar price but less for postage.
https://ebay.us/6tqMZ5
I need a bigger hammer!
arber333
Posts: 3265
Joined: Mon Dec 24, 2018 1:37 pm
Location: Slovenia
Has thanked: 80 times
Been thanked: 234 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by arber333 »

I have very good results using those shady china items for years now...
https://www.aliexpress.com/item/1005006 ... 09442613_8
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

crasbe wrote: Mon Feb 12, 2024 2:49 pm You could simply set the Buck converter to 5V and connect it's output to the +5V pin of the Arduino Nano instead of the VIN pin.
That bypasses the internal LDO completely.
That would be the better strategy anyway, because 6V is right on the edge of the permissible input voltage. The dropout voltage of the LM1117IMPX-5.0 is greater than 1.0V at room temperature.


And no, the LDO wouldn't really love 14.4V input voltage. Even though it might not explode immediately, the tiny package of the LDO on the Arduino Nano is not able to dissipate much heat.


A word of caution in regards to the LM2596 buck converter you have used: They usually come with a faked chip which has a lower efficiency (not really relevant for your case) due to a lower switching frequency. The catch is that sometimes (not always, because you can't predict what the Chinese put on there) the boards come with mismatched capacitors and inductors, resulting in a higher-than-usual output noise. That in turn can lead to unreliable operation, which is less than desirable in an automotive application.


My recommendation are these cute, integrated step-down converters from TRACO (and many other suppliers) like this one: https://www.mouser.de/ProductDetail/TRA ... oeVA%3D%3D

The Mouser link is just an example, idk where to buy stuff in the UK.
I didn't expect the first part of this answer until I checked the input voltage of Arduino Uno and found it is recommended 7V to 12V with a limit of 6V to 20V. The Nano is just 7V to 12V with no reference to max limit. I had wrongly assumed the Nano would be OK with 5V or 6V input.
Having been burned before (almost literally) by a cheap Chinese voltage converter I'm not keen for a repeat performance so have ordered a few of the Traco's
I need a bigger hammer!
User avatar
marcexec
Posts: 122
Joined: Tue May 14, 2019 12:52 pm
Location: Dublin, Ireland
Has thanked: 536 times
Been thanked: 45 times

Re: Mitsubishi Outlander PHEV heater

Post by marcexec »

Alibro wrote: Tue Feb 13, 2024 10:14 pm Having been burned before (almost literally) by a cheap Chinese voltage converter I'm not keen for a repeat performance so have ordered a few of the Traco's
+1, wrong place to save (deep in the car and soon forgotten...)
A motorcyclist is never late, Frodo Baggins. Nor is he early. He arrives precisely when he means to.
Getting started guide for Celeron55's iPDM56
My Suzuki RF400 build @ES
Honda IMA & Lebowski howto
Image
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

I put up a photo earlier showing a circuit to control the heater but as mentioned we didn't like the cheap Chinese buck converter I used to bring the voltage down from 14.4V to 6V for the Arduino.
As suggested by Crasbe this is a Traco power TSR 1-2450 5V step down voltage regulator that is designed to handle up to 36V.
IMG_20240220_111824518.jpg
IMG_20240220_111846935.jpg
Screenshot from 2024-02-20 12-13-13.png
They are more expensive than the Chinese buck converter but I figured I should use something a bit more quality.
Also as suggested I connected it directly to the 5V pin as the Arduino needs a minimum 6V at Vin.
Thanks again for your support and guidance guys.
Now I need to get off me Ar$e and install it. :(
I need a bigger hammer!
Alibro
Posts: 856
Joined: Sun Feb 23, 2020 9:24 am
Location: Northern Ireland
Has thanked: 270 times
Been thanked: 149 times
Contact:

Re: Mitsubishi Outlander PHEV heater

Post by Alibro »

Here is a quick update of the heater situation now I have it installed.

It works! :D

The longer version includes a minor disaster and a change in design.
While testing I managed to drop some solder on the board while it was running. This caused the operation to be somewhat sub-optimal so after first replacing the MCP2515 I then had to replace the Arduino and of course it was no longer soldered to the vero board.
Originally I had planned to mount the board under the bonnet and feed wires through to the dash but while staring at the new pile of wires I had an idea.
IMG_20240323_135944263 (1).jpg
IMG_20240323_140040908 (1).jpg
IMG_20240324_132329160 (1).jpg
IMG_20240324_132338036 (1).jpg
IMG_20240324_132348088_HDR.jpg
IMG_20240325_183157618.jpg
OK so neat it isn't but this was more a proof of concept than a final installation. In order to tweak the code I will need to remove the Arduino as I didn't give myself enough room to plug in a cable but that can wait a bit. I have plenty of other things to work at in the meantime.

Jamie/TurboPete's code works great however in my application I might need to adjust the temperature difference before the heater switches to half power. It looks like it switches to half power while around 10°C below requested temp. This means if I request 55°C it only gets to around 50°C which is not quite enough. I find myself turning it up to 61 or 62°C to get the desired 55°C.
I assume this will change as we get into late Spring so for now I am keeping the adjustment and code as is. I have a second ash tray that I can use if I decide to use Arber333's code without a POT.
I need a bigger hammer!
Post Reply