The Combine Forum banner

1 - 20 of 212 Posts

·
Registered
Joined
·
4,014 Posts
Discussion Starter #1
Here's a forum topic for rate control with AOG.
For what it is worth, here is the file I added to the arduino code. Below that is the modified main loop.

The meter reading is based off a tutorial located here:

How to Use Water Flow Sensor - Arduino Tutorial: 5 Steps (with Pictures)

The original formula for the rate being applied for the number of sections came from here:

How to Use a Nozzle Flow Chart, With a Surprising Twist | Sprayers 101

We have a 3way valve for our rate variation, and I am still playing with a good way to get decent control over that. Currently has a blocking loop(BAD!). Suggestions? Read about millis() function....

Feel free to look it over, or tell me to trash it! Won't hurt my feelings LOL. Any questions just ask!

Code:
 void Flow_Control(void)
{
  double flowRate = 0;
  int valve_direction = -1, number_nozzles = 0, t, temp; 
  
  
  if(!digitalRead(WORKSW_PIN) && (relay & 255)) //the master  switch is "on" and there is at least one relay on so check and change  GPA
  {
    //find sections on and calculate # nozzles on
    //#nozzles on each section of our sprayers
    if(relay & 1) number_nozzles += 3;
    else if(relay & 2) number_nozzles += 9;
    else if(relay & 4) number_nozzles += 9;
    else if(relay & 8) number_nozzles += 9;
    else if(relay & 16) number_nozzles += 9;
    else if(relay & 32) number_nozzles += 9;
    else if(relay & 64) number_nozzles += 9;
    else if(relay & 128) number_nozzles += 3;
    
    //read flow sensor 
     if((millis() - oldTime) > (flow_gain * 1000))    // Only process counters once per second
    { 
      // Disable the interrupt while calculating flow rate and sending the value to
      // the host
      detachInterrupt(sensorInterrupt);
          
      // Because this loop may not complete in exactly 1 second intervals we calculate
      // the number of milliseconds that have passed since the last execution and use
      // that to scale the output. We also apply the calibrationFactor to scale the output
      // based on the number of pulses per second per units of measure (gallons/minute in
      // this case) coming from the sensor.
      flowRate = (((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor) * 0.264172;

      actual_Flow = (flowRate * 60) / (speeed * nozzle_space *  number_nozzles); //measured g/min converted to g/hr divided by mph *  width gives measured gal/ac;
      
      if(target_Rate > actual_Flow)
      {
        //set valve to adjust open
        digitalWrite(valvedirection, 1);
      }
      else if(target_Rate < actual_Flow)
      {
        //set valve to adjust closed
        digitalWrite(valvedirection, 0);
      }
      else 
      {
        //rates are correct, do nothing
      }

      t = 1000 * abs((target_Rate - actual_Flow)); //proportional control of the valve based on how far off we are on rate
                                                   //add in integral and possibly derivative after some testing

      digitalWrite(valvePin, 1); //turn valve on

      //NOT liking this method. Try to find better way.
      while(t-- > 0); //decrement t and move valve during that time
      
      digitalWrite(valvePin, 0); //shut valve off
      
      // Note the time this processing pass was executed. Note that because we've
      // disabled interrupts the millis() function won't actually be incrementing right
      // at this point, but it will still return the value it was set to just before
      // interrupts went away.
      oldTime = millis();
      
      
        
      unsigned int frac;
      
      // Print the flow rate for this second in gal / ac
      //Serial.print("Flow rate: ");
      //Serial.print(int(flowRate));  // Print the integer part of the variable
      //Serial.print(".");             // Print the decimal point
      // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
      //frac = (flowRate - int(flowRate)) * 10;
      //Serial.print(frac, DEC) ;      // Print the fractional part of the variable
      //Serial.print("G/ac");
      
  
      // Reset the pulse counter so we can start incrementing again
      pulseCount = 0;
      
      // Enable the interrupt again now that we've finished sending output
      attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    }
  }
}

/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}
And the main loop:
Code:
  #define LED_PIN 13 
  
  #define   DIR_PIN    12  //PB4
  #define   PWM_PIN    11  //PB3
  
  #define WORKSW_PIN 4  //PD4
  #define STEERSW_PIN 10 //PB2
  
  #define RELAY1_PIN 5  //PD5
  #define RELAY2_PIN 6  //PD6
  #define RELAY3_PIN 7  //PD7
  #define RELAY4_PIN 8  //PB0
  #define RELAY5_PIN 9  //PB1
  #define RELAY6_PIN 3  //PD3
  #define RELAY7_PIN A4  //PC4
  #define RELAY8_PIN A5  //PC5
  //***********************************************************************
  #define valvedirection 2 //direction to drive flow control valve
  #define valvePin A3 //turn valve on/off
  #define flowPin A2 //bound to digital pin 2 and interrupt
  
  #define target_Rate 20 //hard coded to 20gpa
  #define flow_gain 1 //flow rate gain, increase to decrease sensitivity
  #define nozzle_flow 0.2 //flow rate in gpm @ 40psi
  #define nozzle_space 20 //spacing of nozzles in inches
  //***********************************************************************
  #define RAD2GRAD 57.2957795

  //program flow
  bool isDataFound = false, isSettingFound = false;
  int header = 0, tempHeader = 0, temp;

  byte relay = 0, workSwitch = 0, steerSwitch = 1, speeed = 0;
  float distanceFromLine = 0; // not used
  

  //steering variables
  float steerAngleActual = 0;
  int steerPrevSign = 0, steerCurrentSign = 0; // the steering wheels angle currently and previous one
  float steerAngleSetPoint = 0; //the desired angle from AgOpen
  int steeringPosition = 0, steeringPositionZero = 512; //from steering sensor
  float steerAngleError = 0; //setpoint - actual
  float steerSensorCounts = 40;

  //inclinometer variables
  int tilt = 0, roll = 0;

  //pwm variables
  int pwmDrive = 0, drive = 0, pwmDisplay = 0;
  float pValue = 0, iValue = 0, dValue = 0;
  byte minPWMValue = 10;
 
  //PID variables
  float Ko = 0.0f;  //overall gain
  float Kp = 0.0f;  //proportional gain
  float Ki = 0.0f;//integral gain
  float Kd = 0.0f;  //derivative gain 

  //integral values - **** change as required *****
  int   maxIntErr = 200; //anti windup max
  int maxIntegralValue = 20; //max PWM value for integral PID component 

  //error values
  float lastError = 0, lastLastError = 0, integrated_error = 0, dError = 0;
  //***********************************************************************
  //sprayer values
  byte sensorInterrupt = 0;  // 0 = digital pin 2
    
  // The Raven flow sensor outputs approximately 72 pulses per
  // gal/minute of flow
  float calibrationFactor = 72;
  
  volatile byte pulseCount = 0;  
  
  float actual_Flow = 0;
  //unsigned int flowMilliLitres = 0;
  //unsigned long totalMilliLitres = 0;
  
  unsigned long oldTime = 0;
  //***********************************************************************


void setup()
{
  //analogReference(EXTERNAL);
  pinMode(LED_PIN, OUTPUT); //configure LED for output
  pinMode(RELAY1_PIN, OUTPUT); //configure RELAY1 for output //Pin 5
  pinMode(RELAY2_PIN, OUTPUT); //configure RELAY2 for output //Pin 6
  pinMode(RELAY3_PIN, OUTPUT); //configure RELAY3 for output //Pin 7
  pinMode(RELAY4_PIN, OUTPUT); //configure RELAY4 for output //Pin 8
  pinMode(RELAY5_PIN, OUTPUT); //configure RELAY5 for output //Pin 9
  pinMode(RELAY6_PIN, OUTPUT); //configure RELAY6 for output //Pin 3
  pinMode(RELAY7_PIN, OUTPUT); //configure RELAY7 for output //Pin A4
  pinMode(RELAY8_PIN, OUTPUT); //configure RELAY8 for output //Pin A5
  
  pinMode(DIR_PIN, OUTPUT); //D11 PB3 direction pin of PWM Board

  //keep pulled high and drag low to activate, noise free safe    
  pinMode(WORKSW_PIN, INPUT_PULLUP);   //Pin D4 PD4
  pinMode(STEERSW_PIN, INPUT_PULLUP);  //Pin 10 PB2
  //***********************************************************************
  //sprayer
  pinMode(valvePin, OUTPUT);
  pinMode(valvedirection, OUTPUT);
  pinMode(flowPin, INPUT);
  digitalWrite(flowPin, HIGH);
  //***********************************************************************
  Serial.begin(19200);  //open serial port
   
  //PWM rate settings Adjust to desired PWM Rate
  //TCCR1B = TCCR1B & B11111000 | B00000001;    // set timer 1 divisor to     1 for PWM frequency of 31372.55 Hz
  //TCCR1B = TCCR1B & B11111000 | B00000010;    // set timer 1 divisor to     8 for PWM frequency of  3921.16 Hz
  TCCR1B = TCCR1B & B11111000 | B00000011;    // set timer 1 divisor to    64 for PWM frequency of   490.20 Hz (The DEFAULT)
  //TCCR1B = TCCR1B & B11111000 | B00000100;    // set timer 1 divisor to   256 for PWM frequency of   122.55 Hz
  //TCCR1B = TCCR1B & B11111000 | B00000101;    // set timer 1 divisor to  1024 for PWM frequency of    30.64 Hz

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
} 

void loop()
{
  // header high/low, relay byte, speed byte, high distance, low distance, high delta, low delta, PID Settings byte
  if (Serial.available() > 0 && !isDataFound && !isSettingFound) //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) isDataFound = true;     //Do we have a match? 
    if (header == 32764) isSettingFound = true;     //Do we have a match? 
  }
  
  //Header has been found, presumably the next 6 bytes are the data
  if (Serial.available()> 5 && isDataFound)
  {  
    isDataFound = false;    
    relay = Serial.read();   // read relay control from AgOpenGPS

    //actual speed times 4
    speeed = Serial.read()>>2;  //single byte

    //distance from the guidance line in mm
    distanceFromLine = (float)(Serial.read() << 8 | Serial.read());   //high,low bytes     

    //set point steer angle * 10 is sent
    steerAngleSetPoint = (float)(Serial.read() << 8 | Serial.read()); //high low bytes 
    steerAngleSetPoint /=10.0;
    
    workSwitch = digitalRead(WORKSW_PIN);  // read work switch
    steerSwitch = digitalRead(STEERSW_PIN); //read auto steer enable switch open = 0n closed = Off
    SetRelays();
    
    //sprayer control here
    Flow_Control();
    
    //analogReference(EXTERNAL);
      
    //steering position and steer angle
    analogRead(A0); //discard initial reading
    steeringPosition = analogRead(A0);
    delay(1);
    steeringPosition += analogRead(A0);
    delay(1);
    steeringPosition += analogRead(A0);
    delay(1);
    steeringPosition += analogRead(A0);
    delay(1);
    steeringPosition = steeringPosition >> 2; //divide by 4    
    steeringPosition = ( steeringPosition - steeringPositionZero);   //read the steering position sensor

    //convert position to steer angle. 4 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 *****
    // remove or add the minus for steerSensorCounts to do that.
    steerAngleActual = (float)(steeringPosition)/-steerSensorCounts;    

    //inclinometer
    delay(1);
    analogRead(A1); //discard
    delay(1);
    tilt = analogRead(A1);
   delay(1);
    tilt += analogRead(A1);
   delay(1);
    tilt += analogRead(A1);
   delay(1);
    tilt += analogRead(A1);

    tilt = tilt >> 2; //divide by 4

    //inclinometer goes from -25 to 25 from 0 volts to 5 volts
    tilt = map(tilt,0,1023,-500,500);

    //the steering part - if not off or invalid
    if (distanceFromLine == 32020 | distanceFromLine == 32000             //auto Steer is off if 32020, invalid if 32000
          | speeed < 1 | steerSwitch == 0 )                                                //Speed is too slow, motor or footswitch out of  place or pulling pin low
    {
      pwmDrive = 0; //turn off steering motor
      motorDrive();

      //send to AgOpenGPS - autosteer is off
      Serial.print(steerAngleActual);
      Serial.print(",");    
      Serial.print(Kp);
      Serial.print(",");    
      Serial.print(Ki,2);
      Serial.print(",");    
      Serial.print(Kd);
      Serial.print(",");    
      Serial.print(Ko);
      Serial.print(",");    
      Serial.println(tilt); //tilt

      //Uncomment these two lines once figure out AOG end
      //Serial.print(",");
      //Serial.print(actual_Flow);  // Print the sprayer flow rate to AOG
    }
     
    else          //valid spot to turn on autosteer
    {
      bitSet(PINB, 5);              //turn LED on showing in headingDelta loop      

      //calculate the steering error
      steerAngleError = steerAngleActual - steerAngleSetPoint;                    

      //do the pid
      calcSteeringPID();                                                                                                             
      motorDrive();    //out to motors the pwm value

      //send to agopenGPS
      Serial.print(steerAngleActual);
      Serial.print(",");    
      Serial.print((int)pValue);
      Serial.print(",");    
      Serial.print((int)iValue);
      Serial.print(",");    
      Serial.print((int)dValue);
      Serial.print(",");    
      Serial.print(pwmDisplay);
      Serial.print(",");
      Serial.println(tilt);   //tilt

      //Uncomment these two lines once figure out AOG end
      //Serial.print(","); 
      //Serial.print(actual_Flow);  // Print the sprayer flow to AOG  
    } 
  }  

  //Header has been found, presumably the next 8 bytes are the settings
  if (Serial.available() > 7 && isSettingFound)
  {  
    isSettingFound = false;

    //change the factors as required for your own PID values
    Kp = (float)Serial.read() * 1.0;   // read Kp from AgOpenGPS
    Ki = (float)Serial.read() * 0.1;   // read Ki from AgOpenGPS
    Kd = (float)Serial.read() * 1.0;   // read Kd from AgOpenGPS
    Ko = (float)Serial.read() * 0.1;   // read Ko from AgOpenGPS
    steeringPositionZero = 412 + Serial.read();  //read steering zero offset
    minPWMValue = Serial.read(); //read the minimum amount of PWM for instant on
    maxIntegralValue = Serial.read(); //
    steerSensorCounts = Serial.read()*0.1; //sent as 10 times the setting displayed in AOG
  }

  
}
My main concerns at this point:

Don't want to hog too much of the arduino's time doing valve movements. Currently testing with a delay loop for the valve movement = BAD.

Running out of pins fast with everything wired... a Mux would help for the boom controls, but maybe another arduino just for the valve and rate control? But then harder to communicate with AOG if going that route.

Adding in the appropriate stuff to AOG....would make it all cleaner and easier, except for the guy who has to code it. Anything much past C and Assembly is a challenge for me.

Still needs more actual testing....
 

·
Registered
Joined
·
4,014 Posts
Discussion Starter #2
How well does the rate control work? I did some experiments a couple of years ago with a flow meter (paddle wheel hall sensor that generated a ppm signal) and an actuator running a ball valve. It was super hard and I never did get it working right. Part of the problem was slop in my valve mechanism. I probably should have tried to use an actual sprayer valve. One of the problems I had was that when the valve was shut, pressure would build up in the line, expanding it slightly, and then when i opened the valve, I initially got a large rush of volume so it was nearly impossible to dial into a certain flow rate. In fact I couldn't even do it by hand, and humans are the best PID loops around. I was just using my house water in my experiments. So about 40 psi.

As to arduino doing too much, I think a rate controller PID loop is probably something you want to dedicate an entire arduino to, which will do that and nothing else.
 

·
Registered
Joined
·
5,856 Posts
Some thoughts.

The example program is simply a monitoring program, once per second is sufficient just to display, but for control you have to spped up and do your loop at least 20 times a second.
You can use an I2C GPIO module to run your relays, then you can have hundreds of lines if you want. http://www.robotshop.com/ca/en/i2c-to-gpio-module.html

I wouldn't disable the interrupt, just let it keep accumulating ticks from flow meter, the errors will add up, many ticks will pass by while your main routine is fiddling around. The ISR only takes a couple clock cycles and comes right back to your executing program. Also, if you change your ISR mode to CHANGE, then you can get twice the counts - for free!!! The arduino is probably spinning its wheels 90% of the time.

Sprayer control has a long tau - the valve should adjust fairly slowly and be extremely forgiving since there is a lot of delay in the system.

If there was position feedback on the valve, you could use feedforward in your pid loop, and then use the main loop to fine tune. You could calculate the valve opening by using pressure reading, speed, and booms open. But none of the commercial systems do that, they may tell you its putting on 5 gal/acre, but it takes a while to get there, ie the display is fudged. One time its high, the next its low, in the end its all about right. The law of averages.

So start it out adjusting very slowly because the last thing you want is oscillation.

Yes,, blocking loops are bad.... Set up an out loop that measures milliseconds, once the time has elapsed, then run your loop. Like so

This is from a balancing robot, read an imu, read wheel encoders, pid's for the motors etc. Nothing is ever blocked.

LOOP_TIME is how many microseconds you want each loop to be
Once the accumulated loop time exceeds that, then run your routine and you also get the bonus of having a time value for integration etc of how long the last time span was. Or you can just assume it was the LOOP_TIME that has passed and leave out all time calculations.
The loop count variable can be used to do other things, like at the bottom to be multiples of the actual inner loop time. This is when you could display accumulated volume for example once per second.
Nothing ever has to wait for a process to hang and wait for an answer, that is critical. That main, non blocking loop, timed properly needs to be the foundation of your loop routine.

Hope this helps, super cool project! Although now you're probably sorry you asked!

Code:
void loop()
{
    currentTime = micros();
    unsigned int time = currentTime;

    if (currentTime - lastTime >= LOOP_TIME)
    {        
        dT = currentTime - lastTime;
        lastTime = currentTime;
        loopCount++;                //every 10 ms is a count

        if (!dmpReady) return;    // if programming failed, don't try to do anything

        //get the roll from the IMU
        if (imu.getFIFOCount() > 17) getRobotPitch();

        if (abs(countL) < 50) {
            setPoint = 0;
            throttle = 0;
        }
        if (countL > 50) {
            throttle = 10;
            setPoint = 30;
        }
        if (countL < -50) {
            throttle = -10;
            setPoint = -30;
        }

        calcPID(setPoint,robotPitch); //PID         
        motorDrive();        //drive the motor
    }

    if (loopCount > 5 ) {
        //flash the LED13
        bitSet(PINB, 5);
        serialOut_GUI();
        getTuning();
        loopCount = 0;
        count = 0;
    }    
}
 

·
Registered
Joined
·
131 Posts
How well does the rate control work? I did some experiments a couple of years ago with a flow meter (paddle wheel hall sensor that generated a ppm signal) and an actuator running a ball valve. It was super hard and I never did get it working right. Part of the problem was slop in my valve mechanism. I probably should have tried to use an actual sprayer valve. One of the problems I had was that when the valve was shut, pressure would build up in the line, expanding it slightly, and then when i opened the valve, I initially got a large rush of volume so it was nearly impossible to dial into a certain flow rate. In fact I couldn't even do it by hand, and humans are the best PID loops around. I was just using my house water in my experiments. So about 40 psi.

As to arduino doing too much, I think a rate controller PID loop is probably something you want to dedicate an entire arduino to, which will do that and nothing else.
Torriem, Thanks for setting up the new thread! Just getting in for the night so you beat me to it!

I am using a Raven 60P flowmeter along with the 3 way 12v valve designed for our flexicoil sprayer. Everything is already mounted and we have been running off an Ag leader controller, but we just bought an identicle sprayer and upgraded it so now I want two controllers.

I did come across your work while surfing the net to see if it had already been done, but you had mentioned you had problems with it so I decided to take a shot on my own. The code pasted is a rough version that needs the valve control dialed in and the display dealt with. I am definitely leaning towards a seperate arduino for the rate control at this point...
 

·
Registered
Joined
·
131 Posts
Some thoughts.

The example program is simply a monitoring program, once per second is sufficient just to display, but for control you have to spped up and do your loop at least 20 times a second.
You can use an I2C GPIO module to run your relays, then you can have hundreds of lines if you want. I2C to GPIO Module - RobotShop

I wouldn't disable the interrupt, just let it keep accumulating ticks from flow meter, the errors will add up, many ticks will pass by while your main routine is fiddling around. The ISR only takes a couple clock cycles and comes right back to your executing program. Also, if you change your ISR mode to CHANGE, then you can get twice the counts - for free!!! The arduino is probably spinning its wheels 90% of the time.

Sprayer control has a long tau - the valve should adjust fairly slowly and be extremely forgiving since there is a lot of delay in the system.

If there was position feedback on the valve, you could use feedforward in your pid loop, and then use the main loop to fine tune. You could calculate the valve opening by using pressure reading, speed, and booms open. But none of the commercial systems do that, they may tell you its putting on 5 gal/acre, but it takes a while to get there, ie the display is fudged. One time its high, the next its low, in the end its all about right. The law of averages.

So start it out adjusting very slowly because the last thing you want is oscillation.

Yes,, blocking loops are bad.... Set up an out loop that measures milliseconds, once the time has elapsed, then run your loop. Like so

This is from a balancing robot, read an imu, read wheel encoders, pid's for the motors etc. Nothing is ever blocked.

LOOP_TIME is how many microseconds you want each loop to be
Once the accumulated loop time exceeds that, then run your routine and you also get the bonus of having a time value for integration etc of how long the last time span was. Or you can just assume it was the LOOP_TIME that has passed and leave out all time calculations.
The loop count variable can be used to do other things, like at the bottom to be multiples of the actual inner loop time. This is when you could display accumulated volume for example once per second.
Nothing ever has to wait for a process to hang and wait for an answer, that is critical. That main, non blocking loop, timed properly needs to be the foundation of your loop routine.

Hope this helps, super cool project! Although now you're probably sorry you asked!

Brian, thanks for the input! I welcome any thoughts since I know my skills still need work.

I am going to play with a couple avenues of approach with this. Any other input is welcome!
 

·
Registered
Joined
·
4,014 Posts
Discussion Starter #6
I wrote what I felt was a good, generic, PPM measuring library for Arduino. My code is here: https://github.com/torriem/ppmreader/. The code is generic and has no hardware interface, but you drive it with an interrupt service routine that should call onTrigger(). I would welcome improvements, comments, or concerns (maybe it's a completely flawed algorithm).
 

·
Registered
Joined
·
131 Posts
I wrote what I felt was a good, generic, PPM measuring library for Arduino. My code is here: https://github.com/torriem/ppmreader/. The code is generic and has no hardware interface, but you drive it with an interrupt service routine that should call onTrigger(). I would welcome improvements, comments, or concerns (maybe it's a completely flawed algorithm).
Line 57 in get_ppm() you were thinking about disabling interrupts while running that routine but mentioned noise. How much noise were you getting?

It looks really similar to any of the other examples for reading flow meters I have seen. You mentioned that it had difficulties with a garden hose supply, but your valve had slop? What valve were you using?
 

·
Registered
Joined
·
131 Posts
Now, I am leaning towards making this a seperate unit specifically for rate control. If I understand correctly, softwareserial can enable us to communicate from one arduino to another even when using the usb. Thoughts on using a master/slave setup vs. two arduinos on two usb cables? All the rate control needs are the speeed and relay variables from AOG, and display the rate somewhere.
 

·
Registered
Joined
·
1,350 Posts
Just some thoughts on the physical mounting. Any sprayer I have built with different brands of controllers all want the flow meter some distance away from the flow control valve. Wanting to make life easy and a bit lazy I did mount the flow meter and flow control within 12" of each other on a turf sprayer. The teejet controller could not keep any sort of accuracy. Separate them 24" and all works good. I am just wondering if that could be causing grief when doing anything home made.
 

·
Registered
Joined
·
5,856 Posts
Now, I am leaning towards making this a seperate unit specifically for rate control. If I understand correctly, softwareserial can enable us to communicate from one arduino to another even when using the usb. Thoughts on using a master/slave setup vs. two arduinos on two usb cables? All the rate control needs are the speeed and relay variables from AOG, and display the rate somewhere.
Why do you think you require 2 arduinos? I've attached the latest AutoSteer module. It does IMU readings, inclinometer readings, full pid, motor driving, communication to and from AOG, Kalman filtering.... I think its uses about 5% of its capacity, the rest of the time it just loops doing nothing.

Would you like me to chop out all the autosteer stuff and leave the basic routine of the timed loop and communication to and from AgOpenGPS?
 

Attachments

·
Registered
Joined
·
4,014 Posts
Discussion Starter #11
Line 57 in get_ppm() you were thinking about disabling interrupts while running that routine but mentioned noise. How much noise were you getting?
I don't think I saw any noise at all, honestly. It's all about averages anyway. I don't think disabling interrupts is necessary, since the get_ppm() calculations are fairly short and quick.
It looks really similar to any of the other examples for reading flow meters I have seen. You mentioned that it had difficulties with a garden hose supply, but your valve had slop? What valve were you using?
I just used a 3/4" banjo valve fixed in a metal frame. I removed the plastic handle and stuck on a metal handle that I drove with a 2" linear actuator driven by a mosfet h-bridge driver using pwm input from arduino. It actually worked all right. As I mentioned, I couldn't even get a good flow rate with my hand on the valve, and humans are actually very good at PID control. I can't remember what flow rate I was actually shooting for... maybe I was trying for too low a rate that couldn't be done with the pressures my line was under. I recall I did use a nozzle to make sure I had back pressure.

Anyway, some time I'd like to try again!
 

·
Registered
Joined
·
131 Posts
Why do you think you require 2 arduinos? I've attached the latest AutoSteer module. It does IMU readings, inclinometer readings, full pid, motor driving, communication to and from AOG, Kalman filtering.... I think its uses about 5% of its capacity, the rest of the time it just loops doing nothing.

Would you like me to chop out all the autosteer stuff and leave the basic routine of the timed loop and communication to and from AgOpenGPS?
Fair points Brian! I should have checked the amount that the arduino is currently doing(or not doing!). I guess my current brainblock is finding a reliable way to mesh flow control in without affecting what is there. More play time I guess!

I think I can gut AOG and give it a whirl. Need to get a stable flow version together then find a good way to patch back in to a stable version of AOG.

Hmmm I see rain in the forecast heheheh....
 

·
Registered
Joined
·
131 Posts
Just some thoughts on the physical mounting. Any sprayer I have built with different brands of controllers all want the flow meter some distance away from the flow control valve. Wanting to make life easy and a bit lazy I did mount the flow meter and flow control within 12" of each other on a turf sprayer. The teejet controller could not keep any sort of accuracy. Separate them 24" and all works good. I am just wondering if that could be causing grief when doing anything home made.
I am going to hazard it might be due to valve-induced swirl in the water pattern affecting the flow readings? Probably a good sciency explanation out there.......... all of our meters are about 10' down the way so that shouldn't be an issue!
 

·
Registered
Joined
·
5,856 Posts
Have you thought about using PWM nozzles? Feed a constant pressure, use the flowmeter to just confirm volume delivered.

AOG is all metric in the background, so it will be spitting out liters/hectare. Not many countries use non metric so it just makes sense to keep all the calcs in all programs in metric and just display the not metric as a final step.
 

·
Registered
Joined
·
131 Posts
My father is still head sprayer operator and getting him to accept technology upgrades is....challenging. He still insists on the foam markers even though we have the gps guidance and auto shutoff and all that. Frustrating. PWM nozzles are going to be a tough sell with him. If I get something working for this, then maybe have an alternate configuration for PWM?

Good point on the conversions. Less manipulations, less chance for errors.

P.S.
This technology is for myself when I run the equipment ;)
 

·
Registered
Joined
·
5,856 Posts
Wedge, i think i misunderstood you, when you said you were going to use "another" arduino for rate control did you mean two for rate control or one for rate and one for autosteer? I'm thinking the latter. I'm kinda slow!

AgOpenGPS started out with the goal of turning a relay or two on or off for my air seeder. Never dreamt it would need 3 or 4 USB connections and multiple arduinos. Maybe there is a better way.
 

·
Registered
Joined
·
4,014 Posts
Discussion Starter #17
Well when you can show him that precise control of the nozzles and sections can literally save chemical and money, maybe he'll go for it. Just like auto steer has become second nature to us, I'm sure he can get used to automatic section control as well. It sure has revolutionized our operation just to have what we have!

Relating to what Brian said about PWM nozzles, even with normal nozzles, spray rates are dictated primarily by pressure. It doesn't matter how many sections or nozzles are turned on, if you maintain a certain pressure, you'll get a certain gal/ac rate at each nozzle. But of course no one calibrates their nozzles, so as they wear, things do get out of spec and most guys never know.

What beerwiser said about separating the flow sensor and the valve makes a lot of sense. I think I had my flow sensor about 1.5 ft from the valve. I tried it on either side of the valve and still had problems! I guess I need a better test stand than my bath tub. Next year when I have a nice heated shop all winter, I might give it another attempt. Having a general, open source rate controller is another piece of the replacing-proprietary-technology puzzle. Be it liquid rates or shaft speed rate (a drill). It goes hand in hand with what AOG does and the next step once you get a functioning rate controller is variable rate. Every section really needs its own rate controller. Even if you do per-nozzle shut off control, I think having a 10 foot group of nozzles controlled overall by a dedicated rate controller is probably sufficient.
 

·
Registered
Joined
·
92 Posts
Are you all using ball valves for flow regulation? Surely a Ramsey valve would be easier to regulate as it relies upon air pressure and 2 solenoid valves, rather than a mechanical linkage. They are used on most sprayers around here.
 

·
Registered
Joined
·
4,014 Posts
Discussion Starter #19 (Edited)
Interesting. Never heard of that before. My sprayers use ball valves driven by a gear motors. Most sprayers use that kind of set up as far as I know. Like this: http://www.sprayerdepot.com/Shop-by-Category/Banjo-2-Way-Electric-Valves. There are two kinds of valves, on-off, and regulating. The rate controller runs a regulating valve. And some older sprayers use a three-way regulating valve, which diverts excess flow back to the tank to keep pressure from building too high.

Ramsey valves look very interesting. I wonder why they aren't more widely used in North America?
 

·
Registered
Joined
·
131 Posts
Wedge, i think i misunderstood you, when you said you were going to use "another" arduino for rate control did you mean two for rate control or one for rate and one for autosteer? I'm thinking the latter. I'm kinda slow!

AgOpenGPS started out with the goal of turning a relay or two on or off for my air seeder. Never dreamt it would need 3 or 4 USB connections and multiple arduinos. Maybe there is a better way.
One for rate and one for the autosteer(and everything else that it is currently doing)!

Then it just becomes necessary to grab speeed and width information, either from the autosteer arduino or directly from AOG. If I move pins around I should be able to find enough space to run a comm line between arduinos.
 
1 - 20 of 212 Posts
Top