WAS with Ackermann steering


I mounted my WAS (Delphi) like this:

I mounted it directly on the hydraulic cylinder because I was thinking that whatever the type of my steering, the displacement of the cylinder rod will be symetric if I turn left or right (the rod will get in or get out from the same distance).
In fact, I was totally wrong. The maximum rod course is 20.5cm (full turn left or right). But when I drive straight forward, the rod of the left and right cylinder are 13cm out. It means that, when I full turn left or right :

  • The rod of the inner turn cylinder is 13cm retraced
  • The rod of the outer turn cylinder is out of 7,5cm

Consequence, du to this Ackermann configuration, the max rotation angle of my WAS is different when I full steer left or right. As my WAS is mounted on the right wheel, the rotation angle is bigger when I drive full right.

I thinks, for following an A-B line it’s not a problem, has I think the max angle set point will be something like +/- 10°.
But the difficulty will comes with U turn. Actually, with this configuration, I have to turn full right and setup the count per degre to obtain my max steering angle (40° on my Fiat 115-90). But consequently when I full turn left, Arduino measure a steering angle of somthing like 30° instead of 40°.
So to avoid any trouble, I the autosteer configuration I will have to limit the max steering angle at 30°. So the tractor will have a turn radius different in a left or right uturn and in one side I loose some maneuverability of my tractors.

Does anyone have encounter the same difficulty with the same type of steering and has some advises or solutions, to compensate this asymmetry du to Ackermann steering ?

I look at the Arduino code to try to anderstand how the steering angle is calculated and how it’s use for driving the motor and to see if I could find a solution.
I saw that the steer angle is calculated with the following code:

steeringPosition = (steeringPosition - steerSettings.steeringPositionZero);   //read the steering position sensor
//convert position to steer angle. 32 counts per degree of steer pot position in my case
//  ***** make sure that negative steer angle makes a left turn and positive value is a right turn *****
#if WAS_Invert
    steerAngleActual = (float)(steeringPosition) / steerSettings.steerSensorCounts;
    steerAngleActual = (float)(steeringPosition) / -steerSettings.steerSensorCounts;

I saw that steerSettings.steeringPositionZero is define in the struc type « storage » call steerSettings, initialised with the value SteerPosZero (define in the setup zone) and after updated with the « Wheel Angle Sensor Zero » compensation received from AOG through USB/RS232.
steerSettings.steerSensorCounts is also define in the same struc type, initialised at 30 (with AS1115) and after updated with the « Count per Degree » value comming from AOG.

If I draw the line angle=f(counts) with a standard steer, we have something like this:

To calculate the angle, the arduino code center the curve on zero, so the line is somthing like y=a*x with the slop « a » that correspond to the « Count per degree »:

But in case of my Ackermann steering, because of the assymetrical rotation, the previous line does’nt work for one side of the line (max count and min count aren’t symetrical compared to steerPositionZero), as illustrated in the following graph:

In fact, the line angle=f(count) has a different slope depending if we are left or right side of steerPositionZero: the Count Per Degree is different.

So, a solution what I was thinking is to use a different counts per degree if we are left or right of the steerPositionZero.

If we define in the Struct type Storage steerSetting :

  • steerSensorCountsLeft (count per degree for left turn)
  • steerSensorCountsRight (count per degree fot right turn)

The code could become:

steeringPosition = (steeringPosition - steerSettings.steeringPositionZero);   //read the steering position sensor
//convert position to steer angle. 32 counts per degree of steer pot position in my case
//  ***** make sure that negative steer angle makes a left turn and positive value is a right turn *****
if (steering Position >= 0) {   
  #if WAS_Invert
   	 steerAngleActual = (float)(steeringPosition) / steerSettings.steerSensorCountsRight;
            steerAngleActual = (float)(steeringPosition) / -steerSettings.steerSensorCountsRight;
else {
  #if WAS_Invert
   	 steerAngleActual = (float)(steeringPosition) / steerSettings.steerSensorCountsLeft;
             steerAngleActual = (float)(steeringPosition) / -steerSettings.steerSensorCountsLeft;

After the steerAngleActual is used by the PID and motordrive fuction to drive the motor.

Do you think it could work ? Or it’s a bad idea that will lead to disaster ? I would like to have your opinion before making a try.
I think I have enough knowledge to edit the Arduino code to add this function to make a try. But I haven’t enough knowledge to edit AOG to define inside 2 adjustable parameters steerSensorCountsLeft & steerSensorCountsRight and send it to USB. So I could make the try only by manually define the values in the Arduino code.

Thank for your advises, or any other proven solution that work with Ackermann steering.


With a bit of floating point math, you can calculate the angle of the virtual wheel in the center of the axle:
esp32-aog/inputs.cpp at master · doppelgrau/esp32-aog · GitHub line 313 to 338.
And regarding your question: the larger the difference between reality and what AOG thinks is the reality, the larger the error. But I have no feeling if two different counts/degree would be “good enough”.

1 Like

Mounting WAS this way eliminates Ackerman.
WAS_install kopio
A bit bad drawing but hope it helps.


In this picture if was is connected to the end of the steering cylinder (rod), there would be no need to calculate Ackermann, as it moves same distance to both sides.

I think it’s a two steering cylinder system.

No there is no other connection bar to the other wheel.
But in the picture at the top, there is a connection bar, and if you attach was to the middle of this bar, you would have same movement to both sides.

Yes , no connection bar , but watch again I can see the base of cylinder . I really think it s two cylinder . Or a 3 wheel tractor :wink: ?

I really like this solution, as I have the same problem, using the Fendts WAS: to left 46.7° to right 39° but should be the same.
I did the easy way Math did.

@BrianTee_Admin should be integrated in aog directly: left/right adjustment

Some IH/Case tractors have the cylinder house built in the 4 wheel drive center. The “tell” is the ball joint at the end of cylinder rod.

Yes. Now the was rod is connected (almost) on the line between kingpin and tie rod end, so it works the same way; eliminates ackerman.

My tractor is a Valtra 665 with a 2-headed steering cylinder. No separate tie rod.

I don’t think you are right. Wherever you mount it out at the steering wheel, it still moves in a circle the Ackermann way.
Try to move cylinder the last 20mm to right and measure movement of was, then the last 20mm to left and measure movement of was
Or was counts from straight ahead and to max left, then straight ahead to max right, probably not the same, due to the Ackermann.

When the outer was rod is mounted on the wheel hub as shown in my picture, the mounting point moves in the Ackermann way. And so it should do. In this way, it eliminates the Ackermann effect at the other end of the rod when the first WAS arm is mounted parallel to the direction of travel.
My installation is not perfect. It has errors of a few millimeters, so the difference in steering angles varies by a few percent left and right. In addition, the first rod may need to be slightly shorter.
However, this configuration works well and I haven’t seen any reason to start fine-tuning it.

I’ve had the same problem on SAME front axle
(not easy to put sensor due to geometry and wheel mud protections)
The response was completely non linear (-70 to 40 °)
In the arduino I add this piece of code, it divides the response of the sensor in 3 areas :
left (-40°) to -5°, -5 ° to + 5° and +5° to right (40°) and I’ve calibrate the output to
100 steps / deg.
I’ve add a third part of linear response close to the straight line regulation (-5° to 5°)
For programming the values, I’ve measured the response and angle at full left, mid and right
and put it in the map corrections.
It seems to work for me …
/* With Map /
if (steeringPosition < 1000) /
-5° value /
steeringPosition = map(steeringPosition, -9500, 1000, -4000, -500); /
-9500 is full left /
if (steeringPosition < 3000) /
+5° value /
steeringPosition = map(steeringPosition, 1000, 3000, -500, 500); /
2000 is center /
steeringPosition = map(steeringPosition, 3000, 7900, 500, 4000); /
7900 is full right */
//map(value, fromLow, fromHigh, toLow, toHigh); integer math


Thank a lot for all your answers. Lots of datas to analyse and choose the more adapted to my mounting.

@doppelgrau thank for your part of code. I looked quickly but it’s a little bit more complicated: I have to look more carrefully.
I agree with the lost of accuracy using a left/right count per degree.
In my case: right turn (side where I have biggest WAS rotation angle), the count per degre is 35 and the mesured angle is 43.22°.
When I turn full left, the mesured angle is -27.69°. So If I calculate the count per degree for left turn to reach 40°, it shall be 50.
But no idea what could be the impact on the error.
20200119_125519 20200119_125531

@Kaupoi, if I undestoof well your mounting, you locally recreate a ackermann geometry for the WAS ?

@MTZ8302 What is your feedback with the method with a left and right count per degree ?

@Francois Thank also for your code. Again, I will look carrefully your code, because at the moment I am not sure to well understood it. But I am not familiar with the map function.

@Larsvest I am not sure to anderstand I you speak about the steering picture of Kaupoi or mine ?
In my case, as @Tooki57 said, I have 2 cylinder: one for the left wheel an one for the right wheel. Each are linked to the front axle. Left/right cylinder:
And the cylinder have’nt a symetrical displacement:
When drive straight foward, both are 13cm out (max course 20,5cm). And when I full turn left or right, the rod insite the turn is fully rectrated (so displaced of 13cm) and the rod of the wheel outside the turn is fully extand (so displaced of 7,5cm).



I haven’t saw that you have a connection bar between left and right wheel .

Why don t you put the W A S on it ?? Then the ackermann problem will be minimal , and will be the same count/degree on left and right .

The picture at the top is your picture, so I definitely agree with Tooki57

1 Like

Yes, exactly. Eliminating Ackermann by Ackermann.

Am I missing something!?
Looking at @Math setup, the was is mounted on the cylinder with connecting rode at the end so there can’t be any Ackermann effect. (only in was linkages)
I think the problem is trying to get too much travel on the was rotation, try making the was arm longer.

Ok I’m bad…surprising how much clearer things look once drawn up in Fusion360!

Ackerman error can be death with both mechanical linkages as Kaupoi is doing it and also with code.

Kaupois linkage is to my knowledge almost perfect. It has some edge case errors, doesn’t it?
All the rod lengths should be in scale with the steering track rod, radius arm, and front axle lengths. If they aren’t in scale, then the sensor joint geometry starts to have errors in near full turning angles, if that makes sense…

When calculating error with code, one must understand that Ackerman error is not linear, it has one sweet spot and elsewhere it is almost correct. But it still can be calculated whit trigonometry and the basic idea for those calculations is shown in the linked file.

I’m writing a program that calculates this error and shows the real steering angle, just so you can play with the values and see how it’s working… I’ve come to notice that coding is like creating art. It never gets finished!

Ackerman error