A Robotics Project Page
Google
 
Web    www.PhilBot.com
My other sites
  • OurCoolHouse
  • Phil's Resume
  • Web Portfolio

  • [Home] [Projects] [Hardware] [Software] [Books] [Links] [Downloads]


    BOB: Software: Lesson E - Optical Wheel Rotary Encoder.          [Back to BOB Software]        [Back to BOB index]

    This lesson shows the basic method for interfacing to a Quadrature encoder to the OOPic.  BOB has two Quad Encoders, one for each wheel.  To see more about the mechanics and fabrication of this encoder visit my [TMG Encoder] page.  Rotary wheel encoders are found on most high-end robots, so I thought it was important for BOB to have them so I could experiment with different control methods.  In this lesson I illustrate a simple way to make pre-programmed movements.  This is a very simple form of  "Closed Loop" control, where feedback is used to determine when the required action is complete.

    Perhaps a quick tutorial about Quad Encoders is a good idea here. 

    If you have a wheel or cog with slots in it, and you put a single optical sensor on the wheel looking through the slot, you will be able to tell how fast/far the wheel is turning, but you won't be able to tell which direction it's turning.  This is OK on something like a drill, but no good on a robot that can change direction.  By adding a second sensor near the first one, you can tell which way the wheel is turning by noticing which sensor sees the slot first.  A true Quadrature Encoder would have the slot and sensors arranged so that each sensor produces a square wave, and those waves overlap by 90 degrees (dividing the wheel into quarters).  But in BOB's case one of the cogs has a 90 degree slot in it, and the two sensor are next to each other.  Not the ideal configuration, but it works just fine.  Since the encoder gear is early in the gear reduction, each revolution of the gear is a fraction of a wheel turn.

    The OOPic has a built in object called oQEncoder that is perfect for our uses.  It attaches to two optical encoders and it maintains a 16 bit count.  It counts up when the cog rotates one way, and counts down when the cog rotates the opposite way.

    As always, in this program (PBot_BOB-E_VC6.osc) I start using the I/O definitions described on the main BOB [Software page].   These are:

    //-------------------------------------------------------
    // BOB I/O Port definitions
    //-------------------------------------------------------
    Const   IO_LED_GROUP            = 1;    // LED I/O Group 1    (Lines 8-15)
    Const   IO_LED_NIBBLE           = 1;    // LED I/O High Nible (Lines 12-15)

    Const   IO_MOTOR_LEFT_FWD       = 24;   // Left Motor H-Bridge High
    Const   IO_MOTOR_LEFT_REV       = 25;   // Left Motor H-Bridge Low
    Const   IO_MOTOR_LEFT_PWM       = 18;   // Left Motor PWM control

    Const   IO_MOTOR_RIGHT_FWD      = 26;   // Right Motor H-Bridge High    
    Const   IO_MOTOR_RIGHT_REV      = 27;   // Right Motor H-Bridge Low 
    Const   IO_MOTOR_RIGHT_PWM      = 17;   // Right Motor PWM control

    Const   IO_ENCODER_LEFT_FRONT   = 31;   // Left A I/R optical interruptor
    Const   IO_ENCODER_LEFT_BACK    = 30;   // Left B I/R optical interruptor
    Const   IO_ENCODER_RIGHT_FRONT  = 29;   // Right A I/R optical interruptor
    Const   IO_ENCODER_RIGHT_BACK   = 28;   // Right B I/R optical interruptor

    Here are the Objects that I define for this Lesson:

    //-----------------------------------------------------------------
    // User Objects.  Use these to access BOB hardware.
    //-----------------------------------------------------------------
    oCountDownO ActionTimer = New oCountDownO;  // User Timer   

    // Wheel sensor and driver Objects
    oQencode LeftClicks     = New oQencode;     // Value for Left Encoder
    oQencode RightClicks    = New oQencode;     // Value for Right Encoder

    // LED Object (accessed as group of 4 bits)
    oDIO4       LEDs        = New oDIO4;        // Driver for LEDs

    // Wheel motor driver Objects
    oDCMotor2 LeftMotor     = New oDCMotor2;    // Driver for the Left Wheel
    oDCMotor2 RightMotor    = New oDCMotor2;    // Driver for the Right Wheel

    In my programs, I always use the SetupIO( ) function configure the OOPic "Objects" required to interface to the hardware. 
    In this case it's all pretty much just IO assignments.

    //-----------------------------------------------------------------
    //  SetupIO()
    //  Configure all the IO Objects here
    //-----------------------------------------------------------------
    Void    SetupIO( Void )
    {
        // --------------------------------
        // setup the ActionTimer Timer for 1/10th Second ticks 
        // Preload counter with 5 second delay
        // --------------------------------
        ActionTimer.PreScale    = CLOCK_PRESCALE;
        ActionTimer.ClockIn.Link(ooPIC.Hz60);
        ActionTimer             = FIVE_SECONDS;
        ActionTimer.Operate     = cvTrue;

        // --------------------------------
        // setup the Wheel Encoders
        // --------------------------------
        LeftClicks.Value    = 0;
        LeftClicks.IOLine1  = IO_ENCODER_LEFT_FRONT ;
        LeftClicks.IOLine2  = IO_ENCODER_LEFT_BACK ;
        LeftClicks.Operate  = cvTrue;

        RightClicks.Value   = 0;
        RightClicks.IOLine1 = IO_ENCODER_RIGHT_FRONT ;
        RightClicks.IOLine2 = IO_ENCODER_RIGHT_BACK ;
        RightClicks.Operate = cvTrue;
        
        // --------------------------------
        // setup the LED Drivers
        // --------------------------------
        LEDs.IOGroup            = IO_LED_GROUP ;
        LEDs.Nibble             = IO_LED_NIBBLE ;
        LEDs.Direction          = cvOutput ;

        // --------------------------------
        // setup the Wheel Drivers
        // --------------------------------
        LeftMotor.Value     = 0;
        LeftMotor.PreScale  = SLOW_PWM;     
        LeftMotor.Mode      = cvOn;     // Active Braking
        LeftMotor.Brake     = cvOff;
        LeftMotor.IOLine1   = IO_MOTOR_LEFT_FWD;
        LeftMotor.IOLine2   = IO_MOTOR_LEFT_REV;
        LeftMotor.IOLineP   = IO_MOTOR_LEFT_PWM;
        LeftMotor.Unsigned  = cvFalse;
        LeftMotor.Period    = PWM_PERIOD;
        LeftMotor.Operate   = cvTrue;
        
        RightMotor.Value    = 0;
        RightMotor.PreScale = SLOW_PWM;
        RightMotor.Mode     = cvOn;     // Active Braking
        RightMotor.Brake    = cvOff;
        RightMotor.IOLine1  = IO_MOTOR_RIGHT_FWD;
        RightMotor.IOLine2  = IO_MOTOR_RIGHT_REV;
        RightMotor.IOLineP  = IO_MOTOR_RIGHT_PWM;
        RightMotor.Unsigned = cvFalse;
        RightMotor.Period   = PWM_PERIOD;
        RightMotor.Operate  = cvTrue;
    }

    So all I need to do now is tell BOB to move and I should be able to see the Left and Right Click (encoder values) change. Since I only have 4 LEDs, it makes sense to tell BOB to move the Left Wheel forward 15 clicks and stop, then move the Right Wheel 15 clicks and stop.  I'll then repeat this forever.  While I'm waiting for each encoder's value to reach 15, I'll display the current value on the 4 LEDs.  I expect BOB to wiggle forward as the LED's count from 0 to 15.  Here's the main program.

    //-----------------------------------------------------------------
    //  BOB Main Program
    //-----------------------------------------------------------------
    Void Main(Void)
    {
        // Always set up the required IO and VC's first.
        SetupIO();
        
        // Wait for 5 second "Start Up" to elapse
        While(ActionTimer.NonZero);

        // Run Wheel Test
        While (cvTrue)
        {
            // Move Left wheel foward 15 clicks
            
            // Reset count and start rotation
            LeftClicks.Value = 0;
            Drive(50, 0, 0);
            
            // Loop waiting for clicks to reach 15
            While (LeftClicks.Value < 15)
            {
                // Display clicks on LEDs
                LEDs.Value = LeftClicks.Value ;
            }
            Brake();
            
            
            // Move Right wheel foward 15 clicks
        
            // Reset count and start rotation
            RightClicks.Value = 0;
            Drive(0, 50, 0);
            
            // Loop waiting for clicks to reach 15
            While (RightClicks.Value < 15)
            {
                // Display clicks on LEDs
                LEDs.Value = RightClicks.Value ;
            }
            Brake();
        }
    }
     

    I took a little movie of BOB doing the [Wiggle Dance]. It was interesting to play with different motor speeds to see how fast the encoders could count.  The encoders had no trouble keeping up with the Tamiya gearbox's top speed with my standard drive voltage.  I knew that there was a dead band of low drive voltages that did not have enough oomph the start the wheels turning.  So already my mind was working on a way to get speed feedback from the encoders so I could just crawl along reliably :).  More on that later...

    Next, in [Lesson F] I will look at doing similar closed loop position feedback using virtual circuits.

     

    Web content is copyright © PhilBot.com 2005, Deep Creek Lake, MD.
    Contact: Phil Malone 301.387.2331, webmaster@PhilBot.com