The Combine Forum banner

DIY AutoSteer with AgOpenGPS

521K views 2K replies 123 participants last post by  penny199666 
#1 · (Edited)
So i thought i would start a topic that concerns just with AutoSteer. Hardware/software be it PI or arduino, is self contained and only uses AgOpenGPS for some parameters. In fact any front end could generate the ABLine or Contour data for it.

AgOpenGPS sends out 9 bytes on the autosteer port.

Header - 2 bytes - Signed integer, value 32766 or 127 high byte + 254 low byte. Purpose: As a header for upcoming sentence.

Relay Control - 1 byte - Byte, value 0 to 255 defines how many of the 8 sections required to be on. bit 0 LSB is section 1, bit 7 MSB, section 8.
Example 0000 0011 (3) -> Section #1 and Section #2 are on, Sections 3 thru 8 are off

Speed - 1 byte - Byte value 0 to 255, speed in km/h * 4.0.

DistanceFromGuidanceLine - 2 bytes - Signed integer, high byte then low byte. Value is in millimeters from guidance line. Positive denotes right side of line, Negative denotes left side of line.
Special numbers, if value is:
32020, it means autosteer in AgOpenGPS is turned off.
32000 means Autosteer is on but there is no guidance line to calculate a distance from.

HeadingError - 2 bytes - Signed integer, high byte then low byte. Value is in radians * 10,000.
Positive denotes heading toward the guidance line, Negative denotes heading away from guidance line.

PID gain value byte. The LSB bit 0 --> 0 means decrease, 1 means increase
Bits 1 thru 7 are the individual gains or parameters.
Bit 1 - Proportional gain
Bit 2 - Integral gain
Bit 3 - Derivative gain
Bit 4 - Overall gain

The use of binary rather then text means it isn't readable to humans, is more complex, but is much faster. The header bytes allow showing the start of new information. Accurate consistent data is important and since its just a stream of bytes, its important to know where the sentence starts. The GPS Data window in AgOpenGPS shows what is being sent. I will edit this page as required to reflect any changes in sentence structure.

https://github.com/farmerbriantee/AgOpenGPS

https://www.youtube.com/user/FarmerBrianTee
 
See less See more
#2 · (Edited)
So to jump right in, start at the beginning, getting the right information....

Here is some Arduino code for discussion on parsing the sentence.

Code:
void setup() { setup here }

void loop()
{
  // header high/low, relay byte, speed byte, high distance, low distance, high delta, low delta

  if (Serial.available() > 0 & !isHeaderFound) //find the header, 127H + 254L = 32766
  {
    int temp = Serial.read();
    header = tempHeader << 8 | temp;               //high,low bytes to make int
    tempHeader = temp;                             //save for next time
    if (header == 32766) isHeaderFound = true;     //Do we have a match? 
   }
  
  //Header has been found, presumably the next 6 bytes are the data
  if (Serial.available()> 5 & isHeaderFound)
  {
        relay = Serial.read();   // read relay control from AgOpenGPS
        speeed = Serial.read();  //single byte
        distanceError = (float)(Serial.read() << 8 | Serial.read());   //high,low bytes     
        headingError = (float)(Serial.read() << 8 | Serial.read());     //high low bytes 
        isHeaderFound = false;
        isDataReady = true;              
  }        
       
  if (isDataReady)
{
..... We have solid data, and we know its the most current so do the next PID loop
}

} //end of main arduino loop
  {
Is this a good way to take a stream of numbers, find the start of them - consistently, load up the stream into variables, and then and only then allow the module to process data to control the autosteer loop? It is non blocking in any way, even if the port is disconnected it won't go wild because it always needs new data set to true to do the PID loop, and won't get locked up if no new data arrives. Seems to work very well.

Btw, speed is speeed as a variable because speed is an Arduino keyword.
 
#3 · (Edited)
In order to work right, I think that the Integral and Derivative part of the calculation needs to be done at a fixed frequency, you can't do 10 times/sec once, and then only 2times/sec, because the value of the Kd and Ki loose "consistency". If you can live without the integral part, then no problem (I'm starting without it). Maybe a way to solve it is to disconnect autosteering after 1sec of invalid data? I think it can also be good to add a "stop autosteering" input, so you can stop it with a foot switch or something.
 
#4 ·
You should be getting data every 200 msec with a 5 hz nmea and 100 with a 10 hz. The only time you miss data is if something went really wrong, but 99.99% of the time it should just be there.

In good programming though, that is the easy part, the actual program, the hard part is anticipating all the things that can go wrong and be able to handle them gracefully.
 
#5 ·
I think there is merit to separating the maths and the control elements.
I.e, the PID loop/Fuzzy inference system produces a desired steering angle at the whatever rate it receives the data. If it misses a packet, no problem, just let the control loop get on with the latest good data. If more than 1s worth of packets dropped, kill the output.
This desired steering angle is then acted upon in the control loop, which compares it against the measured steering angle and outputs appropriate PWM to the valve. This happens quite quickly, say at 25Hz. Any faster and I think the valve would struggle to react in time.
 
#6 ·
I think the oscillating frequency of the steering system is probably around 1 hz. Basic PID theory says we need a sampling frequency at ten times that as a minimum, or 10 hz. Its going to take some tricky math to get it stable with a 5 hz nmea signal.
 
#9 ·
You guys are brilliant. I am a total greenhorn when it comes to GPS and auto-steer. I know nothing about nothing, and would love to know more than that! I left the ag dealer back in 2000, when precision farming was in it's infancy. I don't want to hijack this thread, but can you point me in a direction of where I can start to learn?
 
#10 ·
Brian:

Good idea with the new thread. Should keep the AOG thread cleaner since we are working on a slightly different stage now!

A couple questions for anyone:

-Will it hurt anything if, rather than computing the PID on a timing, we just ran it every time we got new information? Potentially a little more wild depending on data? This leads into filtering the output......

-What is everyone using to dial in their coefficients in the controller? I have put together a PID controller that I have just been running on the Ardunio w/AOG and watching the writeback values to AOG while steering. Gets a rough approximation, until I can put together a physical control system.

-Should we as a group decide on a specific output format(or two) from the control system? Maybe pwm? Range? Are we checking a steering sensor? Specifics help in design!

One more for Brian:

Is it necessary to have both a section control and an autosteer communication option in AOG if the section control is sent through the autosteer as well? Maybe wrap them into one? Or are we looking ahead to $$$$ unlocks here? Hahaha!
 
#12 ·
Brian:
-Should we as a group decide on a specific output format(or two) from the control system? Maybe pwm? Range? Are we checking a steering sensor? Specifics help in design!
I'm using the PWM to drive a DC motor, the range would be an option for those who wish to try with servos?

For the steering sensor I'm planing to use an encoder attached to the autosteer motor + a reed relay for "zero" sensing.
Whe can always have a "low level layer", so we normalize the steering sensor input (be it encoder, potentiometer...) to the PID function.
 
#16 ·
Nice video! I like the ability to adjust PID values in the fly. Much easier for tuning then using a serial console manually or reprogramming constantly. Would there be any usefulness with saving the PID values with the rest of the tractor config data? Maybe being able to send those values to the Arduino at the initial connection? I'm thinking ahead to when I'll have AOG in our fleet of tractors, Arduinos and tablets might get swapped around but I'd like the tractor config to stay with the tractor settings. I'm also thinking of using something like Dropbox to sync between tractors.
 
#17 ·
A video showing an actual steering motor hooked up and a quick look at the circuits. BTW, the steering position sensor will be used to limit the angular velocity of the turns. The faster you go the lower the amount of steering should be allowed. So if the PID loop wants to turn it more then that limit, you just zero it. Code not written yet, but that's pretty easy. Since there is a foot of snow on the ground, got some time to fiddle.

Video showing the setup.

 
#20 ·
As far as control goes, Matt Reimer used a standard PWM 12V motor controller to drive the two solenoids for his autonomous tractor. PWM on one solenoid to steer in one direction, and the other to steer in the other direction I'm presuming.

I can't remember what valve block Matt was using.
 
#22 ·
If you've got a spare spool it may be wise to use a standard proportional valve, 3 position, all 4 ports blocked in the centre. Works on older open centre systems too, placed in parallel with the Orbitrol. These are fairly inexpensive (£650).

CCLS systems need a pre-compensated valve with P connected to LS in all positions other than centre. Quite a rare part though I think, spoke to my local hydraulic supplier and even they didn't know where to start! A possible bodge would be to use a separate solenoid valve which fires in tandem with the proportional valve, and connects P to LS when active.

I'm planning to do my testing on an older open centre tractor so I can put the research on the back-burner for a while until I at least have a working autosteer using cheaper components
 
#24 ·
#26 ·


Initial testing! Couldn't get AOG to output anything useful so sent some 'dummy' data out of the arduino. All completely untuned, as you can see, but the concept works! Note that i the video I said '30 degrees' when I actually mean 30%; where 0% is full left and 100% is full right steer.

Next steps:

GUI - Add sliders for adjustment of parameters e.g. PWM floor (minimum PWM value for the valve to turn on)
Tune parameters such as input and output weights (and maybe tweak the membership functions, rules etc of the fuzzy system)
Remove arduino - for a more streamlined system. Only there because I didn't have time to code all the stuff in Python
Steering movement sensor - Automatic disengagement when steering wheel movement detected. Could possibly do it in code where it detects when it is 'fighting' the operator, although will need some careful programming to avoid disengaging when hitting a bump, etc.

All in all though, I call that a successful first test!
 
#27 · (Edited)
I've uploaded the latest AgOpen with the Arduino code under steer. It should work. You have to be within 3 or 4 meters of ABLine, and reasonable heading.

Hopefully it will work for you.

The Arduino code is very different in this one. It uses headings calculated based on distance from line, as opposed to a distance only and PID. Its a strange version of feed forward PID with the heading error being the control. That way there should be significantly reduced error by following a changing heading rather then trying to shoot for a line. Wish i had more time to play with this.

Your test looks great.
 
#28 ·
Sorry Brian, couldn't get that to work either, won't even show the arduino data in the setup window. Not to worry though, i'm going to leave it for a few months until after exams/harvest, and just refine what I've got, maybe get a few boards made up. Hopefully will be able to resume testing in the autumn and winter. Thank you for all the hard work and effort you've put into this!

My code is up on Github if anyone wants to have a look (try not to laugh too hard!) :)
https://github.com/charlesquick/FuzzySteer
 
#29 · (Edited)
What exactly does the R code do? What is the principle by which it operates?

EDIT: Here's a link that describes the general idea, and compares it a bit to PID:
https://en.wikipedia.org/wiki/Fuzzy_control_system

So if I understand your code correctly, the pwm output for the steering valve is currently coming from the Pi, from python, and the steering angle is coming from the arduino, correct? The arduino is passing information from the tablet, combined with the steering angle sensor reading to the Pi over the second serial link, which then does the fuzzy control calculations to determine the desired steering angle, and then outputs PWM to the motor controller board. So really if you had a way of doing analog input on the Pi, you could eliminate the arduino entirely. Did I get that right? Is the Pi Python code real time enough to work reliably
 
#30 · (Edited)
Torriem,
Yes you're absolutely correct. I only used the arduino because I was running out of time and it was easier to use Brian's existing serial code and make use of the Arduino's ADC. The Pi should definitely be fast enough to handle the calculations in real time, this is helped by the fact that the R code runs in a separate thread. The system takes a few seconds to load initially, but after that it seems pretty quick. If you like, I can run some tests to put a number on exactly how fast.

Edit:

You might be wondering how to decipher the .fis file:

Inputs distance, delta and speed are categorised into the relevant membership functions as defined in the 3 [input] sections. For example, distance = -323, delta = 52, speed = 6 will be sorted as follows:

distance only falls under the 'neg_low' membership function, to a degree of around 0.3
delta is 'pos_zero' to a degree 0.5 and 'pos_low' to a very small degree
speed is 0.6 'low' and 0.4 'med'

The [rules] section goes like this: IF (antecedent 1) AND (antecedent 2) AND (antecedent 3) THEN (consequent 1). Zero means undefined (so speed isn't evaluated in most of the rules)

i.e. 1 1 0, 9 (1) : 1 equates to distance, delta, speed, output, weight (always 1), evaluation type (1 = AND, 2 = OR). So it translates to IF (distance is neg_hi) AND (delta is neg_hi) THEN (output is pos_hi).

Evaluate all of these rules to the membership degrees we calculated earlier and then take the centre of the output and out pops your steer value.

I hope this helps you understand what I've done :) If you search youtube for Fuzzy Logic there's a few good videos on the subject too.
 
#31 ·
I believe the pi by itself would do the job. Especially if you ran freeRTOS on it. Much better, faster, and versatile environment then the Arduino.

I would say that the pi not being able to do this isn't the pi's fault, its the technique used. Absolutely, chop the arduino out.

I see an MCP3008 in your very near future
 
#32 ·
Definitely using the MCP3008, already got some on order ;)
I'm going to keep using Unix on the Pi, as it's also being used as an NTRIP correction receiver, and I really don't like the idea of porting that over to RTOS. The Pi 3 has 4 cores, so assuming my application will make good use of multithreading in the future then there won't be much difference between using Raspbian lite or RTOS?
 
This is an older thread, you may not receive a response, and could be reviving an old thread. Please consider creating a new thread.
Top