PID for Danfoss proportional valve

Did you see this post from grabik and also the next posts from him?


PID calculation:

pValue = steerSettings.Kp * steerAngleError *steerSettings.Ko;

/* //Derivative
dError = steerAngleError - lastLastError;
dValue = Kd * (dError) * Ko;

//save history of errors
lastLastError = lastError;
lastError = steerAngleError;

drive = pValue;// + dValue;
pwmDrive = (constrain(drive, -255, 255));

//add throttle factor so no delay from motor resistance.
if (pwmDrive < 0 ) pwmDrive -= steerSettings.minPWMValue;
else if (pwmDrive > 0 ) pwmDrive += steerSettings.minPWMValue;

if (pwmDrive > 255) pwmDrive = 255;
if (pwmDrive < -255) pwmDrive = -255;

8 byte PWM resolution on arduino nano(255) , for driver direction DIR pin, and PWM ,DIR pin LOW left side -255 max write to PWM 255 , right side DIR pin HIGH 255 max write to PWM 255 for max duty cycle.

For Danfoss valve not need DIR pin for change direction.

Sorry for not mentioning… Yes, I also included the

pwmDrive = pwmDrive / 4;
pwmDrive = pwmDrive + 128; // add Center Pos.

as explained in that topic. That got the IBT_2 working with the valve, but does not necessarily get AgOpenGPS working with the valve.

From reading through that topic, it also appears to me that he is not using Integral.

According to the following text from the pid for dummies, it is not important to have derivative.

Derivative Action – predicting the future

OK, so the combination of P and I action seems to cover all the bases and do a pretty good job of controlling our system. That is the reason that PI controllers are the most prevalent. They do the job well enough and keep things simple. Great.

But engineers being engineers are always looking to tweak performance.

They do this in a PID loop by adding the final ingredient: Derivative Action.

So adding derivative action can allow you to have bigger P and I gains and still keep the loop stable, giving you a faster response and better loop performance.

If you think about it, Derivative action improves the controller action because it predicts what is yet to happen by projecting the current rate of change into the future. This means that it is not using the current measured value, but a future measured value.

The units used for derivative action describe how far into the future you want to look. i.e. If derivative action is 20 seconds, the derivative term will project the current rate of change 20 seconds into the future.

The big problem with D control is that if you have noise on your signal (which looks like a bunch of spikes with steep sides) this confuses the hell out of the algorithm. It looks at the slope of the noise-spike and thinks:

“Holy crap! This process is changing quickly, lets pile on the D Action!!!”

And your control output jumps all over the place, messing up your control.

Of course you can try and filter the noise out, but my advice is that, unless PI control is really slow, don’t worry about switching D on.

Maybe a delay on power (so signal can be built up first)
If sharp turn is always to same side, it could be a Danfoss thing when powered on. Could be checked by applying center voltage to signal when turning power on. Edit: center voltage meaning 6v if you have 12v as supply)

Isn’t the Danfoss supposed to have an analog signal in since it has its own PWM generator with LVDT feedback?

That’s my understanding as well. You need DC supply voltage on one pin and then a control voltage on the other. Hysteresis shouldn’t exist as there’s a displacement feedback in the valve controller.

Here’s some discussion & working setups in another thread .ino for PCB+MD13S+Danfoss valve You should see something like 25-75% of U_DC in U_S, check out the pictures towards the back of the thread from @Kaupoi and @Larsvest

We tried putting PWM to the U S pin, and everything worked. A lot of analog input controllers out there accept true analog, and they also accept PWM.
Danfoss PWM connection

I think I have the PID ‘turn on’ figured out. Now to test it yet. :face_with_raised_eyebrow:

The Integral can not be calculating while not steering, since it would build up to the Integral max over time, even if off of the AB line by 1%, for instance.

The ‘last’ value of the Derivative needs to be saved constantly, as this will be used to calculate the Derivative once the steering is on again.

The only value used for PID is the P, the rest have been used for other purposes like low and high max pwm etc.

I understand they “work” with PWM, but have your tried with an analog signal? For example if you sent a 50% duty cycle, half the time the danfoss would think wide open , the other half closed - that would work however with the LVDT feedback I’m not so sure that is the best scenario for its feedback control.

All i’m saying is worth a try.

I’d like to disagree on the theory that the Danfoss thinks it should be wide open half the time and closed half the time with 50% duty cycle. We can get it to steer left by putting 12Vdc to the U DC and U S pins, but putting 12V to the U DC pin and 0 Vdc to the U S pin does nothing. We can get it to steer right by connecting the Nano’s 3V or 5V pin to the U S pin. The 3V steers faster to the right than the 5V. But like I said before, 0V on the signal pin gets ignored.

I recall the signal is 0.25 - 0.75 times U_DC, so with 12 volts 3 volts full the other way and 9 volts the other.

1 Like

Yes exactly. Outside of those limits, it should do nothing. It would seem the Danfoss was designed for use with like a potentiometer type of installation (analog signal) for flow control. Being 1/2 DC allows you flow in two directions without needing a corresponding negative supply.

Anyway, i hope someone at least tries the type of input signal the valve was designed for.

I am using an IBT2 to control the steering on an 8330 with Danfoss. I have 12v on the Udc pin, and the pwm signals from the arduino sets the Us. 6V steers straight ahead, 9V to the left and 3V to the right. I have some pics JD 8230 hydraulic steering . Its not a clean setup but it has been working nice on my one field test cultivating. @theGtknerd i noticed while i was originally setting up that with 1 hz on gps it was all over the place, but now at 10hz its smooth. Any chance that could be an issue for you? I have been using v3.9 with the coffeetrac button ino. I think that with the code written like i have it below that it seems to be working fine on my bench test setup but no actual field experience yet. I am a total arduino beginner so if anything in this coding seems wrong please let me know.

Autosteer PID

void motorDrive(void)
// Used with Cytron MD30C Driver
// Steering Motor
// Dir + PWM Signal
if (aogSettings.CytronDriver)
pwmDisplay = pwmDrive;

  //fast set the direction accordingly (this is pin DIR1_RL_ENABLE, port D, 4)
  if (pwmDrive >= 0) bitSet(PORTD, 4);  //set the correct direction
    bitClear(PORTD, 4); 
    pwmDrive = -1 * pwmDrive;  

  //write out the 0 to 255 value 
  analogWrite(PWM1_LPWM, pwmDrive);

{ // Danfoss: PWM 25% On = Left Position max (below Valve=Center)
// Danfoss: PWM 50% On = Center Position
// Danfoss: PWM 75% On = Right Position max (above Valve=Center)
// Used with IBT 2 Driver for Danfoss
// Dir1 connected to BOTH enables
// PWM Left + PWM Right Signal

pwmDrive = pwmDrive / 4;
pwmDrive = pwmDrive + 128; // add Center Pos.

pwmDisplay = pwmDrive;
analogWrite(PWM1_LPWM, pwmDrive),  // apply varying voltage to the Usignal valve pin
digitalWrite(PWM2_RPWM, HIGH);     // apply 100% DC current to Udc


danfoss should indeed do nothing when outside the 0.25-0.75 Udc on the Us pin (safety for ground or supply shorts) .
Udc should also be stabilized (not directly from battery/alternator).
When Udc is been fed with stable 12V, one can use a industry standard 0-10V analog signal to control Us.

So, after a hectic summer, and a still busy winter, I will post an update.

We got the Danfoss valve to work using the code I posted on Github. My friend (who owns the tractor) also spoke directly with a Danfoss representative, who tested a PVE valve on the test bench. The Danfoss tech guy recommended using PWM 4KHZ or higher. This said, our Danfoss valve worked fine on the default PWM speed. Well, that is after we had the PID set up properly. The end result was that we had to turn up the minimum PWM quite a bit, and keep fairly low values in the PID. Sorry, I don’t have all those values with me. However, this only worked with old versions of AOG, which brings me to:

We wanted to use the newest AOG (several reasons, I forget what all). When I discovered the ESP32 project that doesn’t use steer characteristics info coming from AOG, but can be set in the built in webUI, we switched to the ESP32. So far we are happy with the performance, and I am now working toward a PCB to plug the ESP32 into as our setup looks crummy, and we experience occasional disconnects. It’s not surprising, given the state of wires in our setup.

There’s some small changes I made to the ESP32 code, and when I have proved the code/PCB a bit, I will see about making a GitHub repository to share the PCB, code and BOM. Until next time, gotta run…


Interesting explanation!
This one also very “visual”…


Oh PID. Before AOG I built one of those 2 wheeled balancing robots, worked really well and of course used the full pid control. Then I started dong autosteer - and realized that most of what i learned for normal PID did not apply. I have yet to figure out why.

Looking at some other commercial systems they use multiple P, PI, PD loops to compensate for all the problems a second order control system like steering brings. It seems the more “perfect” you try to make autosteer - the worse it works. I find it all a bit frustrating that it is more art then theory.


It’s become my understanding that PID is only suitable when all the system processes & reactions remain predictable without any random external influences. It seems to work pretty good for adjusting the autosteer wheel angle but when I tried to use it as a cruise control for our sprayer then there’s too much that changes such as ground resistance and load weight, things like that.

1 Like

Especially the derivative term.

In the last 7 years I have setup around 12 vacuum pumps with a VFD and vacuum transducer. The only math that works for vacuum pumps is PID. People have tried anything from gain/bias to linear mapping, but it ultimately is not successful or low resolution. I admit a lot of my success in PID and controlling vacuum with pump speed was good fortune and not necessarily because I’m that good.

And then I decided to control my house temperature with PID. The coal boiler feeds in coal according to the PID, based on the feedback from the room temperature. So I learned some more about the whys and wherefores to PID. In this case I had to throttle the update speed, because heat transferred to water and then transferred to radiant heat is slow by nature. So sometimes PID calculation speed has to be matched to the process.

I also found that some ABB motor drives (VFD) have a PID loop for the sensor, and then they have a PID loop for the motor speed. These drives are a nightmare to setup. Basically you set the motor speed PID as tight as you can without tripping error codes, and then tune the sensor loop to control and stabilize the process.

One thing that took me a while to wrap my head around is that PID has a setpoint, and the feedback is used to create an error value. So lets say you want the wheels pointing to 50° and they are at 55° :
error = 55-50 (5)
P = 10
P * error (50)
And that’s only the tip of the iceberg. There’s I and D yet… When this all gets tuned properly, it is a charming system.

In some cases you need to limit the max Integral, usually when the generator/pump/valve is high capacity and the controlled system is small or responds quickly. The Derivative is to control fast changes on the feedback, or abrupt changes to values in the PID. The Derivative counteracts the Proportional, helping smooth the output.