Results 1 to 6 of 6
  1. #1
    300+ Forum Addict Tom_G_2010's Avatar
    Join Date
    Mar 2011
    Location
    Central Mass
    Posts
    437
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Question Need Help with Analog Read Stability

    I have written a sketch to read and control my Elevator Trim Wheel. The Trim Wheel is connected to both a stepper motor and a 10 turn precision potentiometer.

    When the Auto Pilot Altitude Hold is engaged the stepper motor causes the trim wheel to rotate tracking with the trim changes FSX is making. When Altitude Hold is off the Trim wheel can be operated by hand and the attached potentiometer is used to send trim adjustments to FSX via Sim Connect "A18" and "A19" commands.

    The stepper motor portion of the code is working great. But, I am running into a problem with the non auto pilot hand control of the trim wheel which I thought would have been the easiest part of it. At certain points in the trim adjustment it is acting like the potentiometer is teetering in between two values and the result is that the sketch starts to send lengthy streams of sim connect codes to FSX that are rapidly alternating in value between "A18" and "A19"

    I don't have an Oscilloscope to monitor the pot input to see if it might be power supply noise or ripple. If it is noise or ripple would a tantalum cap at the input help keep it clean. I really don't think that's the case. I'm using a reasonable quality pc power supply, but I can't rule it out yet either.

    If it's not noise on the input then is their something I can do in the code to deal with this. I added the "almost equals" function and that helped a great deal, but I still have spots in the pot rotation that will trigger this oscillation. If I increase the almost equals delta to +/-2 it stops almost completely but then my trim wheel read is too choppy and I miss just enough steps that I don't have full range control in either direction.

    I was also thinking about something like a debounce timer routine but there again I am afraid that it might interfere with times when I am intentionally rotating trim wheel through a wide range.

    Any ideas would be greatly appreciated. THANKS!

    Here's the relevant portion of the code. I'll insert the full sketch below this.

    Code:
    void OTHER(){
    
      eTrimPotPstn = analogRead(A1);                      // Reads the potentiometer
      eTrimPotMap = map(eTrimPotPstn,0,1023,-100,100);    // Maps pot value to FS2Multi Trim Range
    
      if(AP_AltLock == 0 && eTrimStprClbrt == LOW){       // Check Alt Hold off & calibrate sub routine is off
        if(!almostEqual(eTrimPotMap,eTrimPotMapLast ,1)){ // Is change in pot greater than +/- 1
          if(eTrimPotMap > eTrimPstn){                    // Is change an increase
            int IncSteps = eTrimPotMap - eTrimPstn;       // Calculate the amount of increase
            for(int Fcnt=0;Fcnt < IncSteps;Fcnt++){       // for loop sends trim steps to FSX
              Serial.println("C18");
              delay(10);
            }
          }
          else if(eTrimPotMap < eTrimPstn){               // Same as above but for decreases
            int IncSteps = eTrimPstn - eTrimPotMap;
            for(int Fcnt=0;Fcnt < IncSteps;Fcnt++){
              Serial.println("C19");
              delay(10);
            }
          }
          eTrimPotMapLast = eTrimPotMap;                 // Stores the last value read
    // Syncs up the stepper motor position tracking with the new pot position
          eTrimStpr.setCurrentPosition(eTrimPotMap * eTrimStpr_Scaler); 
        }
      }
    }
    
    // Here's the "Almost Equals" sub routine used in the if statements above.
    
    boolean almostEqual(int a, int b, int DELTA) {
        return abs(a - b) <= DELTA;
      }
    And here's the full code.

    Code:
    
    // Stepper Motor Library
    #include 
    AccelStepper eTrimStpr(AccelStepper::FULL4WIRE,7,10,11,12);
    
    
    // Stepper Motor Enable pins
    int eTrimStprEnblA = 8;
    int eTrimStprEnblB = 9;
    
    
    boolean eTrimStprClbrt = HIGH;  // Flag for stepper motor calibration sub routine 
    int AP_Engaged = 0;                // Auto Pilot Engage Status
    int AP_AltLock = 0;                  // Altitude Hold Status
    
    
    String ExtVal;
    int ExtInt;
    int CodeIn;
    
    
    int eTrimPstn = 0;                    // current elevator trim position
    int eTrimPstnLast = 1;              // Last elevator trim position
    int stpToPstn = 0;                   // position to move stepper to
    int eTrimPotPstn;                    // position of potentiometer
    int eTrimPotMap;                     // mapped value of potetiometer
    int eTrimPotMapLast;               // Last mapped position
    int eTrimStpr_Scaler = 20;        // scales the 0.9 degree stepper give the needed 10 turn range for the trim wheel
    
    
    void setup(){
    
    
      pinMode(eTrimStprEnblA,OUTPUT);
      pinMode(eTrimStprEnblB,OUTPUT);
      digitalWrite(eTrimStprEnblA, LOW);   //Disable stepper so that trim adjust can be done by hand
      digitalWrite(eTrimStprEnblB, LOW);
    
    
      eTrimStpr.setMaxSpeed(400);         // Set maximum speed of stepper motor when fully accelerated
      eTrimStpr.setAcceleration(100);      // Set rate of acceleration
    
    
      Serial.begin(115200);
    }
    
    
    void loop() {
    
    
      {OTHER();}
      {SIMCONNECT();}
      {ENCODERS();}
    
    
      if (Serial.available()) { 
        CodeIn = getChar();
        if (CodeIn == '=') {
          EQUALS();
        } 
        if (CodeIn == '<') {
          LESSTHAN();
        }
        if (CodeIn == '?') {
          QUESTION();
        }
        if (CodeIn == '/') {
          SLASH();
        }
      }
    }
    
    
    void OTHER(){
    
    
      eTrimPotPstn = analogRead(A1);                               // ** As described above in this post
      eTrimPotMap = map(eTrimPotPstn,0,1023,-100,100);    // ** 
    
    
      if((AP_Engaged == 1 && AP_AltLock == 1) || eTrimStprClbrt == HIGH){  // Is Auto pilot & Alt Hold engaged, or is calibrate sub routine active
        digitalWrite(eTrimStprEnblA, HIGH);   // Activate stepper motor
        digitalWrite(eTrimStprEnblB, HIGH);    // Activate stepper motor
        eTrimStpr.run();                             // runs the stepper motor if the step to position is other than the current position
      }
      else{
        digitalWrite(eTrimStprEnblA, LOW);   //disable the stepper motor if AP & AL or calibrate are not active
        digitalWrite(eTrimStprEnblB, LOW);
      }
    
    
      if(AP_AltLock == 0 && eTrimStprClbrt == LOW){               // ** the remainder of tis loop is as described above in the post
        if(!almostEqual(eTrimPotMap,eTrimPotMapLast ,1)){
          if(eTrimPotMap > eTrimPstn){
            int IncSteps = eTrimPotMap - eTrimPstn;
            for(int Fcnt=0;Fcnt < IncSteps;Fcnt++){
              Serial.println("C18");
              delay(10);
            }
          }
          else if(eTrimPotMap < eTrimPstn){
            int IncSteps = eTrimPstn - eTrimPotMap;
            for(int Fcnt=0;Fcnt < IncSteps;Fcnt++){
              Serial.println("C19");
              delay(10);
            }
          }
          eTrimPotMapLast = eTrimPotMap;
          eTrimStpr.setCurrentPosition(eTrimPotMap * eTrimStpr_Scaler);
        }
      }
    }
    void SIMCONNECT(){
    
    
    }
    void ENCODERS(){
    
    
    }
    void EQUALS(){
    
    
      CodeIn = getChar();
    
    
      switch(CodeIn) {
    
    
      case 'a':
        GetString(1);
        AP_Engaged = ExtVal.toInt();
        break;
    
    
      case 'k':
        GetString(1);
        AP_AltLock = ExtVal.toInt();
        break;
    
    
      }  
    }
    
    
    void LESSTHAN(){
    
    
      CodeIn = getChar();
    
    
      switch(CodeIn) {
    
    
      case 'H':
        GetString(4);                       // Reads 4 characters from the extraction and stores them in ExtVal
        eTrimPstn = ExtVal.toInt();    // Sets variable to the integer conversion of ExtVal
        if(eTrimStprClbrt == HIGH){    // Is Initial calibration needed
          Calibrate_TrimPstnStpr();     // If so run claibration sub routine
        }
        if(eTrimPstn != eTrimPstnLast && eTrimStprClbrt == LOW){     // If not in calibrate mode and trim value has changed
          stpToPstn = (eTrimPstn - eTrimPotMap) *eTrimStpr_Scaler; // calculate the needed movement of the stepper motor
          eTrimStpr.move(stpToPstn);                                           //tell the stepper motor to move
        }
        else{
          if(eTrimPotMap != eTrimPstn){            //run the stepper fine tune sub routine when the stepper is not being actively used
            FineTuneStepper();
          }
        }
        eTrimPstnLast = eTrimPstn;                 // Store the last value read
        break;
      }
    }
    
    
    
    
    void Calibrate_TrimPstnStpr(){                     //Calibration sub routine
    
    
      digitalWrite(eTrimStprEnblA, HIGH);            //Enable the stepper motor
      digitalWrite(eTrimStprEnblB, HIGH);
    
    
      ZeroStepper();                                       // Run Sub Routine to move the stepper motor to the zero position
      FineTuneStepper();                                 // Run the Fine Tune Sub Routine
      
      digitalWrite(eTrimStprEnblA, LOW);            // Disable the stepper motor
      digitalWrite(eTrimStprEnblB, LOW);
    
    
      eTrimPotPstn = analogRead(A1);                             // Set the initial value of the pot position variable
      eTrimPotMap = map(eTrimPotPstn,0,1023,-100,100);  // Map the pot position value to the FS2Multi Trim Range
      eTrimPstnLast = eTrimPotMap;                                // Set the initial last position values
      eTrimPotMapLast = eTrimPotMap;
      eTrimStprClbrt = LOW;                                           // Indicate that the calibration routine is now done
    }
    
    
    void ZeroStepper(){                                                               // Zero Stepper Sub Routine
      eTrimPotPstn = analogRead(A1);                                             // Read the potentiometer value
      eTrimPotMap = map(eTrimPotPstn,0,1023,-100,100);                  // Map the pot position value to the FS2Multi Trim Range
      eTrimStpr.setCurrentPosition(eTrimPotMap * eTrimStpr_Scaler);   // Set the current position value for the stepper to match the pot position
      eTrimStpr.moveTo(0);                                                           // Tell the stepper to Move to the zero position
      while(eTrimStpr.currentPosition() != 0){                                    // A while loop that keeps issuing the run command until the stepper arrives at zero
        eTrimStpr.run();
      }
    }
    
    
    void FineTuneStepper(){                                                         //Fine Tune sub routine
      eTrimPotPstn = analogRead(A1);                                             // Read the Pot Value
      eTrimPotMap = map(eTrimPotPstn,0,1023,-100,100);                  // Map the pot value
      eTrimStpr.setCurrentPosition(eTrimPotMap * eTrimStpr_Scaler);   // Adjust the stepper motors position value to match
    }
    
    
    boolean almostEqual(int a, int b, int DELTA) {
        return abs(a - b) <= DELTA;
      }
    char getChar()
    {
      while(Serial.available() == 0);
      return((char)Serial.read());
    }
    void GetString(int ChrCnt){
    
    
      ExtVal = "";                    // Clear Display Value Variable
      for(int Fcnt=0;Fcnt < ChrCnt;Fcnt++){  // For Loop to retrieve extraction
        ExtVal += getChar();
        delay(10);
      }
    }
    https://www.facebook.com/mycessnasim PC: Intel Core i7 Haswell @ 3.8GHz, 8Gb Ram, Win 7 64Bit, dual SSDs, GeFroce 780 SIM: FSX w/Aclrtn Pk, FSUIPC4, ASN, UTX, GEX, REX 4

  2. #2
    75+ Posting Member



    Join Date
    Sep 2013
    Location
    California, USA
    Posts
    109
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Need Help with Analog Read Stability

    Tom,
    Would it help to define eTrimPotMap as a float?

  3. #3
    300+ Forum Addict Tom_G_2010's Avatar
    Join Date
    Mar 2011
    Location
    Central Mass
    Posts
    437
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Need Help with Analog Read Stability

    Quote Originally Posted by SteveL View Post
    Tom,
    Would it help to define eTrimPotMap as a float?
    I just looked up the map function in the Arduino Reference and it doesn't look like changing that variable to a float will work.

    Here's what the reference says:
    The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged.
    But you have me thinking now about perhaps creating my own mapping function that will handle a float. I'll have to experiment with that this evening after work.
    https://www.facebook.com/mycessnasim PC: Intel Core i7 Haswell @ 3.8GHz, 8Gb Ram, Win 7 64Bit, dual SSDs, GeFroce 780 SIM: FSX w/Aclrtn Pk, FSUIPC4, ASN, UTX, GEX, REX 4

  4. #4
    New Member
    Join Date
    Apr 2014
    Location
    Australia
    Posts
    1
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Need Help with Analog Read Stability

    Hi Tom,

    I had similar issues with a 10K pot I attached.
    What I found was the Arduino's Analog inputs drifted slightly (for what ever reason, I haven't looked into it - as yet), so I just added an offset (buffer), and if my input changed (-or+ the offset) then I acted on it.

    here is a snippet:
    if (CurrentElevatorTrimVal <= (PreviousElevatorTrimVal - _trimoffset) || CurrentElevatorTrimVal >= (PreviousElevatorTrimVal + _trimoffset)) {

    I currently have the offset to int 10.

    Bruce.

  5. #5
    150+ Forum Groupie
    Join Date
    Nov 2013
    Location
    Evansville, Indiana
    Posts
    243
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Need Help with Analog Read Stability

    In passing, I have thought about building a motorized trim wheel at some point.
    I was thinking of using a rotary encoder instead of a pot.
    I will only ever be, half the Geek that I wished I was.
    TheGeekForge.Com

  6. #6
    300+ Forum Addict Tom_G_2010's Avatar
    Join Date
    Mar 2011
    Location
    Central Mass
    Posts
    437
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Need Help with Analog Read Stability

    I am not near my flight sim pc right now so I don't have the code handy, but I did finally work this out.

    As I mentioned above I did finally replace the MAP function with a bit of home grown code that maps as a float rather than being limited to an integer as the canned MAP function is.

    I also noticed the drift in the analog reference. I know there's a way to deal with that by sampling the reference but I haven't dug too deeply into that. In the interim I wrote a small Fine Tune routine that seems to make up for most of it.

    So, I have a 10 turn 10k pot linked to the shaft of my stepper motor and the two play very nice together. Every now and then I get a a little of the oscillation but nothing too problematic and I suspect I can eliminate that when I deal the the drift issue.

    When I get the Flight Sim PC fired up I'll post the current code.
    https://www.facebook.com/mycessnasim PC: Intel Core i7 Haswell @ 3.8GHz, 8Gb Ram, Win 7 64Bit, dual SSDs, GeFroce 780 SIM: FSX w/Aclrtn Pk, FSUIPC4, ASN, UTX, GEX, REX 4