AgOpenGPS - adding rate control - The Combine Forum
 102Likes
Reply
 
LinkBack Thread Tools
post #1 of 211 (permalink) Old 10-31-2017, 11:32 AM Thread Starter
Senior Member
 
Join Date: Sep 2009
Location: S. AB
Posts: 3,418
Mentioned: 5 Post(s)
Quoted: 842 Post(s)
AgOpenGPS - adding rate control

Here's a forum topic for rate control with AOG.
Quote:
Originally Posted by Wedge View Post
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
  }

  
}
Quote:
Originally Posted by Wedge View Post
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....


torriem is offline  
Sponsored Links
Advertisement
 
post #2 of 211 (permalink) Old 10-31-2017, 11:39 AM Thread Starter
Senior Member
 
Join Date: Sep 2009
Location: S. AB
Posts: 3,418
Mentioned: 5 Post(s)
Quoted: 842 Post(s)
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.

Wedge likes this.
torriem is offline  
post #3 of 211 (permalink) Old 10-31-2017, 01:19 PM
Senior Member
 
Join Date: Aug 2012
Location: Vermilion Alberta Canada
Posts: 5,530
Mentioned: 6 Post(s)
Quoted: 2417 Post(s)
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;
    }    
}

Last edited by BrianTee; 10-31-2017 at 01:47 PM.
BrianTee is offline  
Sponsored Links
Advertisement
 
post #4 of 211 (permalink) Old 10-31-2017, 10:09 PM
Senior Member
 
Join Date: Mar 2017
Location: Clatskanie, Oregon
Posts: 131
Mentioned: 0 Post(s)
Quoted: 47 Post(s)
Quote:
Originally Posted by torriem View Post
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...
Wedge is offline  
post #5 of 211 (permalink) Old 10-31-2017, 10:13 PM
Senior Member
 
Join Date: Mar 2017
Location: Clatskanie, Oregon
Posts: 131
Mentioned: 0 Post(s)
Quoted: 47 Post(s)
Quote:
Originally Posted by BrianTee View Post
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!
BrianTee likes this.
Wedge is offline  
post #6 of 211 (permalink) Old 11-01-2017, 11:28 AM Thread Starter
Senior Member
 
Join Date: Sep 2009
Location: S. AB
Posts: 3,418
Mentioned: 5 Post(s)
Quoted: 842 Post(s)
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).
torriem is offline  
post #7 of 211 (permalink) Old 11-01-2017, 05:59 PM
Senior Member
 
Join Date: Mar 2017
Location: Clatskanie, Oregon
Posts: 131
Mentioned: 0 Post(s)
Quoted: 47 Post(s)
Quote:
Originally Posted by torriem View Post
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?
Wedge is offline  
post #8 of 211 (permalink) Old 11-01-2017, 06:07 PM
Senior Member
 
Join Date: Mar 2017
Location: Clatskanie, Oregon
Posts: 131
Mentioned: 0 Post(s)
Quoted: 47 Post(s)
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.
Wedge is offline  
post #9 of 211 (permalink) Old 11-01-2017, 08:39 PM
Senior Member
 
Join Date: Jan 2011
Location: Mundare Alberta
Posts: 1,027
Mentioned: 2 Post(s)
Quoted: 269 Post(s)
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.
Wedge likes this.
Beerwiser is offline  
post #10 of 211 (permalink) Old 11-01-2017, 09:35 PM
Senior Member
 
Join Date: Aug 2012
Location: Vermilion Alberta Canada
Posts: 5,530
Mentioned: 6 Post(s)
Quoted: 2417 Post(s)
Quote:
Originally Posted by Wedge View Post
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?

Attached Files
File Type: zip AutoSteer.zip (12.6 KB, 39 views)
BrianTee is offline  
Sponsored Links
Advertisement
 
Reply

Quick Reply
Message:
Options

Register Now



In order to be able to post messages on the The Combine Forum forums, you must first register.
Please enter your desired user name, your email address and other required details in the form below.

User Name:
Password
Please enter a password for your user account. Note that passwords are case-sensitive.

Password:


Confirm Password:
Email Address
Please enter a valid email address for yourself.

Email Address:
OR

Log-in










Thread Tools
Show Printable Version Show Printable Version
Email this Page Email this Page



Posting Rules  
You may post new threads
You may post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

 
For the best viewing experience please update your browser to Google Chrome