Problem with PID controlling

Hello,
I tried to control temperature with peltier (cooling and heating) by using H- bridge.
One way works perfectly (heating) but when it comes to cooling, PWM Output is still zero. Do you have some idea where can be problem?

Thanks

#include <PID_v1.h>

const int sensorPin = A0;

int sensorVal;
int pin1 = 5;
int pin2 = 6;

double Setpoint, Input, Output;

PID myPID(&Input, &Output, &Setpoint,0.3,0.1,0.1, DIRECT);

void setup(){

Serial.begin(9600);

analogReference(INTERNAL);
Input = analogRead(0);

pinMode(pin1, OUTPUT);
pinMode(pin2, OUTPUT);

Setpoint = 300;

myPID.SetMode(AUTOMATIC);
}

void loop(){

int sensorVal = analogRead(sensorPin);
Input = analogRead(sensorPin);

myPID.Compute();

if(sensorVal > Setpoint)
{
analogWrite(pin1,Output);
analogWrite(pin2,0);
}
else if(sensorVal < Setpoint)
{
analogWrite(pin2,Output);
analogWrite(pin1,0);
}
else {
analogWrite(pin1,0);
analogWrite(pin2,0);
}

Serial.print("sensor Value: ");
Serial.print(sensorVal);

Serial.print("PID Set: ");
Serial.print(Setpoint);

Serial.print("PWM: ");
Serial.print(Output);

float voltage = (sensorVal/1024.0)*1.1;
Serial.print(", degrees C: ");
float temperature = (voltage) * 100;
Serial.println(temperature);

delay(10);
}

Use of DIRECT in your PID means that the increasing the output can be expected to increase the input. So the PID 'knows' that it can raise the temperature by increasing the output. If the temperature is high enough, it'll decrease the output and continue to do so until it has turned of the heater.

Thus, the PID will cause heating if necessary, nothing otherwise - you'll need a more sophisticated system to control heating and cooling. Perhaps a PID for each? However I'd start with a single PID that handles the heat, as you have now and just turn on the cooling to some constant value when it gets too hot.

If you want to heat and cool you need an H-bridge on the peltier and a control input that is signed - positive values drive one way and negative the other, so normally the code to update the drive will use the sign of the control variable to select direction and absolute value of the control value to set PWM duty cycle.

So knowing that “Output” will be values 0 to 255, you want something like:

if (Output >= 128) {
  Output = (Output - 128) * 2;
  analogWrite(pin1, Output);
  analogWrite(pin2, 0);
} else {
  Output = (127 - Output) * 2;
  analogWrite(pin1, 0);
  analogWrite(pin2, Output);
}

Its much clearer to work with variables that are signed so that zero means zero, rather than have an arbitrary 128 offset, I think.

After all the error value is signed, the natural output of a PID loop is also signed.

Not to nitpick, but this looks problematic:

int sensorVal = analogRead(sensorPin); Input = analogRead(sensorPin);

Shouldn't it be something like:

unsigned int sensorVal = (analogRead (sensorPin) & 0b0000001111111111); unsigned int Input = (analogRead (sensorPin) & 0b0000001111111111);

??

No. analogRead() returns values between 0 and 1023 inclusive, representable in both int and unsigned int.

After dissecting the analogRead function, it appears you are correct. The function returns type int. I had just gotten so disciplined when writing low-level stuff I always make sure the result is error free. Certainly no harm in masking the upper bits though. Just another instruction or two.

Also, "Input" was previously assigned as type "double" so that would result in a compile error.

...just mentioning so ok227 doesn't get confused.

Sort of my point. Why read it into a "double" when all you have is a 12-bit unsigned int. Waste of RAM.

rmetzner49: After dissecting the analogRead function, it appears you are correct. The function returns type int. I had just gotten so disciplined when writing low-level stuff I always make sure the result is error free. Certainly no harm in masking the upper bits though. Just another instruction or two.

You could just read the page about analogRead()! http://arduino.cc/en/Reference/AnalogRead

Chagrin: Also, "Input" was previously assigned as type "double" so that would result in a compile error.

...just mentioning so ok227 doesn't get confused.

Its double because that's what the PID library requires, there is no compile error as you can freely cast numeric types.

You could just read the page about analogRead()!

Thank you Captain Obvious. I find it ironic someone with your knowledge would discourage research.