PID does not sense negative values.

Hello. I am trying to set up a system of Servomotor and a combo board (gyro + accelerometers). I am using PID and the setups is such: setpoint is zero degrees, input is angle from the combo board and output is Amplitude of rotation of servo arm on my servo. I made it work, but it only works when incline the combo board in one direction and gives positive angles. however, when incline the other way and it gives negative angles PID does not do anything. Is there any solution to that?

Looks as extract from encrypt comms in CERN, something related to Large Hadron Collider 8)

Is my question unclear?


I am working on a project, which involves PID controller, Arduino, IMU combo board (gyro + accelerometer) and a servomotor. The aim is to keep IMU horizontal at zero degrees, when it inclines amplitude of oscillation of a servo arm on my servomotor increases and when IMU is back in horizontal position amplitude is zero. I set my PID as such: Input = angles from IMU, Output = Amplitude, Setpoint = 0 degrees. It works fine in one direction when angles from IMU are positive, however, in the other direction when angles are negative PID does not respond. Could anyone help me to find a solution for that problem?

Here is a code to make it easier to understand:

#include <PID_v1.h>

#include <FreeSixIMU.h>
#include <FIMU_ADXL345.h>
#include <FIMU_ITG3200.h>

#include <Wire.h>

double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint,2,5,1, REVERSE);

int Ampl = 0;

float angles[3]; // yaw pitch roll

// Set the FreeSixIMU object
FreeSixIMU sixDOF = FreeSixIMU();

void setup() { 
  Input = angles[2];
  Setpoint = 0.00;
  sixDOF.init(); //begin the IMU

void loop() { 

  Input = angles[2];  
  myPID.SetOutputLimits(0, 180);
  Ampl = Output;
  Serial.print(" | ");  
  Serial.print(" | ");
  Serial.print(" | ");

I managed to solve this problem by introducing two PIDs in the code and multiplying input for one of them by (-1), however, it is not an elegant solution and I am still looking for a solution using single PID?

I don't think it's related to your problem, but I think the call to SetOutputLimits() should be in setup(), not in loop().

I can't see any reason why that wouldn't work for negative input values. Can you post some examples of the trace output with positive and negative input values?

For example:

Angle Amplitude 10 10 20 20 80 80 0 0 -10 0 -30 0 -80 0

I made it up myself, but this is what I see is going on when reading a serial monitor.

Well, you've set the output limits to 0, 180, so it can't go negative. What do you expect it to do in that case?

I did not want getting any negative amplitudes. I was expecting it to increase amplitude when angle is not zero.

dvl12: I did not want getting any negative amplitudes. I was expecting it to increase amplitude when angle is not zero.

It can't 'increase amplitude when angle is not zero' when the angle is negative, because you've prevented it from outputting a negative value. The PID has run into the end stops that you have defined, and it can't go any further.

Please show a real example of where it has produced the wrong behaviour and explain what you wanted it to do.

It would seem that you would want the output limits to be -90 to 90. Then, add 90 to the actual output to get a value between 0 and 180 to write to the servo.

What, exactly, is PID doing for you?