title: Arduino PID DC Motor Position Control
body: <p>I'm doing a control engineering project, implementing a PID motor position control for automatic antenna tracking system. The system contain a dc motor, absolute encoder, and a motor driver.</p>
  
  <p>Everything work as expected, but one thing. The motor cannot stop at set point value near 0 degree (350 - 359, 0 - 10 degree). The used code:</p>
  
  <pre><code>#include &lt;PID_v1.h&gt;
  int RPWM = 5;
  int LPWM = 6;
  int L_EN = 7;
  int R_EN = 8;
  boolean pin_state[10];
  byte input_pin[] = {1, 2, 3, 4, 9, 10, 11, 12, 13};
  int dec_position = 0;
  int dc = 0;
  double kp = 50, ki = 45, kd = 2;
  double input = 0, output = 0, setpoint = 0;
  volatile long encoderPos = 0;
  PID myPID(&amp;input, &amp;output, &amp;setpoint, kp, ki, kd, DIRECT);
  
  void setup() {
    pinMode(L_EN, OUTPUT);
    pinMode(R_EN, OUTPUT);
    pinMode(RPWM, OUTPUT);
    pinMode(LPWM, OUTPUT);
    for (byte i = 0; i &lt; 9; i++) {
      pinMode(input_pin[i], INPUT);
    }
    TCCR1B = TCCR1B &amp; 0b11111000 | 1; 
    myPID.SetMode(AUTOMATIC);
    myPID.SetSampleTime(1);
    myPID.SetOutputLimits(-255, 255);          
    digitalWrite(L_EN, HIGH);
    digitalWrite(R_EN, HIGH);
  }
  
  void loop() {
    if (Serial.available() &gt; 0) {
      String baca = Serial.readString();
      setpoint = baca.toInt();
    }
    ReadEncoder();
    input = dc;
    myPID.Compute();
    pwmOut(output);
  }
  
  void pwmOut(int out) {
    if (out &gt; 0) {
      analogWrite(RPWM, out);//Sets speed variable via PWM
    }
    else {
      analogWrite(LPWM, abs(out));//Sets speed variable via PWM
    }
  }
  
  void ReadEncoder() {
  // FOR READING ENCODER POSITION, GIVING 0-359 OUTPUT CORRESPOND TO THE ENCODER POSITION
    for (byte i = 0; i &lt; 9; i++) {
      pin_state[i] = !(digitalRead(input_pin[i]));
    }
    dec_position = (pin_state[8] * 256) + (pin_state[7] * 128) + (pin_state[6] * 64) + (pin_state[5] * 32) + (pin_state[4] * 16) + (pin_state[3] * 8) + (pin_state[2] * 4) + (pin_state[1] * 2) + pin_state[0];
    dc = map(dec_position, 0, 500, 0, 360);
  }
  </code></pre>
  
  <p>When the set point is a value between 10 - 350 the sytem worked well. But when it is not, the motor never stop rotating. </p>
  
  <p>I know the problem is due to a little position overshoot cause the encoder to read a very large error. </p>
  
  <p>For instance, if the setpoint is 0 degree, the motor rotate to reach it. Motor rotation is slowing down as its "now" position approaching 0 degree, but the system is not overshoot free. Therefore, even 1 degree overshoot cause the error value is -359 (set point - now position) and the motor rotate again to reach the desired position.</p>
  
  <p>Need help how to overcome this problem. Sorry for bad english.</p>