Trouble with PID when controlling a thermolectric assembly

I've attached a thermoeletric assembly (basically a peltier with a huge heatsink and fan on the "hot" side) to an Arduino UNO R3 and a BTS7960 motor driver following the schematics found here. I also have a thermistor that monitors the temperature of the "cold" side of the peltier which I wired an programmed following this tutorial.

My aim is now to use PID to cool down the peltier to a given setpoint temperature and mantain said temperature. The peltier can of course also heat up by inverting the polarity (that's why I used an H-bridge), so ideally the PID should be able to switch to heating if for some reason the setpoint is overshot.

I've tested both the thermistors and the peltier attached to the H-bridge and they seem to be working properly: If I activate a certain amount of PWM on the heating pin I can feel my peltier getting hotter and the thermistor reads an increasing temperature. The opposite works for the cooling pin.

I therefore wrote the following code to integrate the PID in the process, but it does not work: the PID does not slow down close to the setpoint, it overshoots, and it keeps cooling the peltier.

I've tried to fiddle with the P,I,D coefficients but the most I could obtain was either a repetition of the described behaviour, either a control that was not working (always 0).

Following the code I'm using. What am I doing wrong?

#include <PID_v1.h>
int ThermistorPin = 1;
int Vo;
float R1 = 10000;
float logR2, R2;
float c1 = 1.138443396e-03, c2 = 2.325201394e-04, c3 = 0.9469069744e-07;
double T, Setpoint, Output;
PID myPID(&T, &Output, &Setpoint,Setpoint*2,Setpoint*0.1,Setpoint*0.1, REVERSE);

void setup() {
Serial.begin(9600);
  pinMode(heatingPWM, OUTPUT);
  pinMode(coolingPWM, OUTPUT);
  pinMode(heatingEnable, OUTPUT);
  pinMode(coolingEnable, OUTPUT);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-255,255);
  Setpoint=10;
  digitalWrite(heatingEnable, LOW);
  analogWrite(heatingPWM, 0); 
  digitalWrite(coolingEnable, LOW); 
  analogWrite(coolingPWM, 0); 
}

void loop() {

  Vo = analogRead(ThermistorPin);
  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  T = T - 273.15;
  myPID.Compute();
  Serial.print("Temperature: "); 
  Serial.print(T);
  Serial.println(" °C");  
  Serial.print("PID Value: ");
  Serial.println(Output);
  if (Output<0) {
      digitalWrite(coolingEnable, HIGH); 
      analogWrite(coolingPWM, 0);   
      digitalWrite(heatingEnable, HIGH);
      analogWrite(heatingPWM, Output);
      Serial.println("Heating");
  }
  else {
      digitalWrite(heatingEnable, HIGH);
      analogWrite(heatingPWM, 0); 
      digitalWrite(coolingEnable, HIGH); 
      analogWrite(coolingPWM, Output); 
      Serial.println("Cooling");
  };
Serial.print("Setpoint: ");
Serial.println(Setpoint);
delay(500);
}

You need a similar massive heat sink on the cold side. The Peltier can only move a little bit of heat from the ceramic because it has a very low amount of heat. You need to replenish that heat by the cold side heat sink, which can be a thick aluminum plate.

Sorry, forgot to mention that. I have also a thick aluminum plate on the cold side and that's where the thermistor's head is embedded. Anyhow that's not really the problem, in fact, the peltier gets too cold for the setpoint.
I'm sure that either the problem is in the coding either in the combination of arduino + motor shield, because the thermoelectric assembly was working fine with a commercial control board (until said board broke down, hence the need of DIY a control board...)

Put in Serial.print statements to make sure that measurements and response make sense. Check the signs of the error terms, as the sign is not standardized.

Overshoot is expected if Kp is too high.

Rather than "fiddle" with the PID constants, the search phrase "PID tuning" will lead you to tutorials on systematically adjusting them.

A PID for heating or cooling is not easy to fit, due to the inevitable time lag. A simple two-point regulator can do as well.

Easily taken into account by measuring the system response time, and adjusting the sample rate and PID constants appropriately.

What about the ambient temperature?