Results 1 to 10 of 10

Thread: Encoder period/rate moving average

  1. #1
    Join Date
    Dec 2008
    Posts
    19

    Default Encoder period/rate moving average

    In the SetMinRate problem thread http://forums.usfirst.org/showthread.php?t=12050 there is a lot of discussion re encoder period averaging. Apparently, the encoders are set up to do a moving average of pulses to determine the average period used to derive rate. This is defaulted to one period but Joe H. has suggested a way to extend this to be any number of pulses between 1 and 127. This is a very valuable tool to handle the noise problems seen with encoders. I would like to use this thread to develop prototype changes to the Encoder class that we all can use. I suggest we add the following simple method to Encoder() class that goes something like this:

    void Encoder::SetMovingAveragePulseCount(UINT32 max_count)
    { //check if 1=<max_count<=127 TODO: should throw an error flag here with message if max_count invalid
    if (max_count<1) max_count = 1;
    else if (max_coount>127) max_count = 127;
    if(m_counter)
    {m_counter->writeTimerConfig_AverageSize(max_count, &status);} //x1
    else
    {m_encoder->writeTimerConfig_AverageSize(max_count, &status);}//x2 OR x4
    }


    Also, since the encoder pulse widths are asymmetric, using a single pulse to determine periods leads to some very large rate errors. See thread http://www.chiefdelphi.com/forums/sh...ad.php?t=74763 . I would recommend that in InitEncoder(bool reverseDirection, EncodingType encodingType) that we always average over one full period as a default. I.E.
    x1: m_encoder->writeTimerConfig_AverageSize(1, &status);
    x2: m_encoder->writeTimerConfig_AverageSize(2, &status);
    x4: m_encoder->writeTimerConfig_AverageSize(2, &status);// This is 2 because of FPGA error which reads only B chan for timing.

    This should drop the noise rates by at least a factor of 3 when using x2 or x4.
    Last edited by vamfun; 03-03-2009 at 05:05 AM. Reason: Updated void Encoder

  2. #2
    Join Date
    Sep 2008
    Location
    National Instruments: Austin, TX
    Posts
    445

    Default Re: Encoder period/rate moving average

    FYI, there is a bug in FPGA 1.0.0 that only phase B is used for timing (position is decoded at 4x). So for the purposes of timing, it should be treated as 2x until the FPGA is updated. You can see a note about that in the WPILib source for the timer functions of the Encoder class such as SetMaxPeriod() and GetPeriod().

  3. #3
    Join Date
    Dec 2005
    Posts
    4

    Default Re: Encoder period/rate moving average

    This is a great thread, it's too bad it is not in the library.

    After reading this I creaded constant
    #define MAXCOUNT 25

    changed the cases to look like this

    case k4X:
    m_counter->writeTimerConfig_AverageSize(MAXCOUNT, &status);
    case k2X:
    m_counter->writeTimerConfig_AverageSize(MAXCOUNT, &status);
    case k1X:
    m_counter->writeTimerConfig_AverageSize(MAXCOUNT, &status);

    I know it's a little dirty but I'll probably create a function after I do initial testing tomorrow.

  4. #4
    Join Date
    Sep 2008
    Location
    National Instruments: Austin, TX
    Posts
    445

    Default Re: Encoder period/rate moving average

    Don't forget that the 4x version needs to set on the m_encoder member, not the m_counter.

  5. #5
    Join Date
    Dec 2008
    Posts
    19

    Default Re: Encoder period/rate moving average

    Ok, ran the first tests today with the new SetMovingAveragePulseCount routine. Ran data with Pulse count = 10 and 50. The rate sigma was 2.29 and 1.95 respectively. The sigma reduction ratio is .85 . I would have expected a factor of 1/sqrt(5) or .44. So not sure this is working.

    We just extended the class to include our new function. Any comments?

    Here is what we are doing in the code:
    class OurRobot : public SimpleRobot
    {
    RobodoxEncoder *leftGearbox;
    }

    OurRobot(void)
    {


    leftGearbox = new RobodoxEncoder(4,1,4,2, false, Encoder::k1X);
    leftGearbox->SetDistancePerPulse((3.0*PI)/250);
    leftGearbox->SetMinRate (1.);//sets minimum rate to 1 in/sec
    leftGearbox->SetMovingAveragePulseCount(50);//Here is where we set the moving average pulses to 50.
    leftGearbox->Start();
    }


    ********************Encoder Source code************************

    RobodoxEncoder.h

    #ifndef ROBODOX_ENCODER_H
    #define ROBODOX_ENCODER_H

    #include "ChipObject.h"
    #include "CounterBase.h"
    #include "SensorBase.h"
    #include "Counter.h"
    #include "PIDSource.h"
    #include "Encoder.h"


    class RobodoxEncoder : public Encoder
    {
    public:
    //RobodoxEncoder();
    RobodoxEncoder(UINT32 aChannel, UINT32 bChannel, bool reverseDirection=false, EncodingType encodingType = k4X);
    RobodoxEncoder(UINT32 aSlot, UINT32 aChannel, UINT32 bSlot, UINT32 _bChannel, bool reverseDirection=false, EncodingType encodingType = k4X);
    RobodoxEncoder(DigitalSource *aSource, DigitalSource *bSource, bool reverseDirection=false, EncodingType encodingType = k4X);
    RobodoxEncoder(DigitalSource &aSource, DigitalSource &bSource, bool reverseDirection=false, EncodingType encodingType = k4X);
    ~RobodoxEncoder();
    //double GetRate();
    void SetMovingAveragePulseCount(int max_count);

    };

    #endif

    *******************source file**********************

    RobodoxEncoder.cpp

    #include "RobodoxEncoder.h"


    RobodoxEncoder::RobodoxEncoder(UINT32 aChannel, UINT32 bChannel, bool reverseDirection, EncodingType encodingType)
    :Encoder(aChannel, bChannel, reverseDirection, encodingType){
    }

    RobodoxEncoder::RobodoxEncoder(UINT32 aSlot, UINT32 aChannel, UINT32 bSlot, UINT32 _bChannel, bool reverseDirection, EncodingType encodingType)
    :Encoder(aSlot, aChannel, bSlot, _bChannel, reverseDirection, encodingType){

    }

    RobodoxEncoder::RobodoxEncoder(DigitalSource *aSource, DigitalSource *bSource, bool reverseDirection, EncodingType encodingType)
    :Encoder(aSource, bSource, reverseDirection, encodingType){

    }

    RobodoxEncoder::RobodoxEncoder(DigitalSource &aSource, DigitalSource &bSource, bool reverseDirection, EncodingType encodingType)
    :Encoder(aSource, bSource, reverseDirection, encodingType){

    }

    RobodoxEncoder::~RobodoxEncoder(){
    }

    void RobodoxEncoder::SetMovingAveragePulseCount(int max_count)
    { //check if 1=<max_count<=127 TODO: should throw an error flag here with message if max_count invalid
    if (max_count<1) max_count = 1;
    else if (max_count>127) max_count = 127;
    if(m_counter)
    m_counter->m_counter->writeTimerConfig_AverageSize(max_count, &status); // Counter object within Encoder -> tCounter within Counter
    else
    m_encoder->writeTimerConfig_AverageSize(max_count, &status);
    }

  6. #6
    Join Date
    Dec 2008
    Posts
    19

    Default Re: Encoder period/rate moving average

    Joe H. ,
    Got a good way to check if we have the timer count set correctly with a simple print? Something like


    int countMax = 599encoder->m_counter->readTimerConfig_AverageSize(&status); ???

  7. #7
    Join Date
    Dec 2005
    Posts
    4

    Default Re: Encoder period/rate moving average

    Quote Originally Posted by Joe Hershberger View Post
    Don't forget that the 4x version needs to set on the m_encoder member, not the m_counter.
    oops... Copy / Paste Error

  8. #8
    Join Date
    Sep 2008
    Location
    National Instruments: Austin, TX
    Posts
    445

    Default Re: Encoder period/rate moving average

    Quote Originally Posted by vamfun View Post
    Joe H. ,
    Got a good way to check if we have the timer count set correctly with a simple print? Something like


    int countMax = 599encoder->m_counter->readTimerConfig_AverageSize(&status); ???
    Assuming you weren't accessing a private member, sure.

    You should be able to call read on any register that has it defined in the header file to read the current configuration of the register in the FPGA. That can be a good debugging tool while developing library functions.

  9. #9
    Join Date
    Dec 2005
    Posts
    4

    Default Re: Encoder period/rate moving average

    When I try to compile WPILIb I get an error saying.

    'class Counter' has no member named 'writeTimerConfig_AverageSize'

    So I had to edit both counter.cpp and encoder.cpp.

  10. #10
    Join Date
    Dec 2008
    Posts
    19

    Default Re: Encoder period/rate moving average

    Quote Originally Posted by kingofl337 View Post
    When I try to compile WPILIb I get an error saying.

    'class Counter' has no member named 'writeTimerConfig_AverageSize'

    So I had to edit both counter.cpp and encoder.cpp.
    we solved this with

    m_counter->m_counter->writeTimerConfig_AverageSize(max_count, &status); // Counter object within Encoder -> tCounter within Counter

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •