Bidirectional PID Controller

Hello everyone,

That you can get a picture of what I am trying to achieve, I'll quickly describe my project: I want to achieve magnetic levitation with this design:

So to control the magnet's direction, I have put a motor driver into the circuit. At the beginning, without the flying pencil, I measure the magnetic field and then I give this value to the PID controller as the Setpoint. Now I measure the magnetic field with my hall sensor every ms and give that value to the PID which then gives back a suggested output value.

So far so good. Let's say I attached the MotorIn1 to PIN 10 and MotorIn2 to PIN11. Since the PID calculates with the difference, integral and the derivative I can't simply do what I did here:

  //Der Input ist grösser als der Kalibrierungswert
  if(Input>Setpoint) {
    analogWrite(motorIn1,Output);
    analogWrite(motorIn2,0);
  }
  //Der Input ist geringer als der Kalibrierungswert
  if(Input<Setpoint){
    analogWrite(motorIn1,0);
    analogWrite(motorIn2,255);

Since this would only work for a D controller. Now my question is: How can I make that the PID controller gives me a value between -255 and 255 so I can call the different MotorInputs? (Since the Input can both be lower and higher than Setpoint)
Or if that has been discussed to death, could you give me a google keyword, since looking for bidirectional PID gives no valuable results.

P.S.
I often hear that PID is overkill for such small things, I already did my own, simple controller which only takes the difference to the setpoint and the change per ms into account (derivative). Not the integral and therefore the acceleration. So I felt that maybe a better algorithm may help (Eventhough I most likely will have to adjust the design anyways.)

Thanks for your help!

The entire code for reference:

#include <PID_v1.h>

const int motorIn1 = 11;
const int motorIn2 = 10;
const int analogPin = A0;

int debug = 0;

//Differenzierung zwischen aggresiver Korrektur und konservativer Korrektur
double driftmax = 5.0;

//Erstellung der Variablen für den PID Controller
double Input, Output, Setpoint;

//Tuning Parameter
double aggKp=3, aggKi=1, aggKd=1.2;

//Erstelle den PID Controller
PID myPIDDirect(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);


void setup() {
  //Schalte den PID Controller an
  myPIDDirect.SetMode(AUTOMATIC);

  //Tuning Settings
  myPIDDirect.SetTunings(aggKp, aggKi, aggKd);
  
  pinMode(motorIn1,OUTPUT);
  pinMode(motorIn2,OUTPUT);
  
  //Initzialisiere Debugkonsole zum Auslesen der Werte
  Serial.begin(9600);
  
  //Berechne den Kalibrierungswert (Setpoint)
  for(int i = 0; i<10; i++) {
    Setpoint = Setpoint + measure();
    delay(1);
  }
  Setpoint/=10.0;
}

void loop() {
  debug++;
  
  //Messung vornehmen
  Input = measure();
  
  //Betrag der Abweichung ermitteln
  double drift = abs(Setpoint-Input);
  
  myPIDDirect.Compute();
  
  //Der Input ist grösser als der Kalibrierungswert
  if(Input>Setpoint) {
    analogWrite(motorIn1,Output);
    analogWrite(motorIn2,0);
  }
  //Der Input ist geringer als der Kalibrierungswert
  if(Input<Setpoint){
    analogWrite(motorIn1,0);
    analogWrite(motorIn2,255);
  }
  
  //Debug
  if((debug%500)==0) {
    Serial.print("Kalibrierung: ");
    Serial.println(Setpoint);
    Serial.print("Measurement:  ");
    Serial.println(Input);
    Serial.print("Correction:   ");
    Serial.println(Output);
    Serial.println();
  }
}

double measure() {
  double temp_mes = 0;
  int counts = 0;
  for (int i = 0; i < 10; i++) {
    temp_mes+=(analogRead(analogPin));
    counts++;
    delay(0.1);
  }
  return (temp_mes/counts);
}

How can I make that the PID controller gives me a value between -255 and 255 so I can call the different MotorInputs?

What are you measuring?

    delay(0.1);

RTFM.

PaulS:
What are you measuring?

    delay(0.1);

RTFM.

Yeah I should have specified that. I measure the value from the hall sensor. This indicates the drift the pen has from the calibrated point.

Yeah, I changed it to DelayMicroseconds() function. Sorry, that's quite embarrassing.

You can set the Output limits. Set them to -255 to +255 (the default is 0 to +255).

  if(Output < 0) {
    analogWrite(motorIn1, -Output);
    analogWrite(motorIn2, 0);
  } else {
    analogWrite(motorIn1, 0);
    analogWrite(motorIn2, Output);
  }

Yeah I should have specified that. I measure the value from the hall sensor. This indicates the drift the pen has from the calibrated point.

But it does not tell you the direction of the drift. It is that drift, in some specific direction, that you are trying to control, isn't it?

PaulS:
But it does not tell you the direction of the drift. It is that drift, in some specific direction, that you are trying to control, isn't it?

Yeah, it is the direction of it (and velocity and acceleration).

If the magnet is for example on the right side of it, I have a value above the Setpoint, on the left side it's below it. That's because the magnet faces the Hallsensor with the North side in one case in the other with the south side.
So the magnetic field vectors change direction when the magnet passes the Setpoint.