Example Source Code:
OOPIC II+ Simple Odometry
![]()
Description
This example demonstrates the use of a virtual circuit that automatically stops the servo when the encoder reaches a certain count.
It uses this prinicple to drive the robot in a 6" square pattern.
Download
ww01_oopic2p_square.osc (fixed line termination problem, 10/2/2005)
Source Code
'------------------------------------------------
'OOPIC II+ WheelWatcher Drive in a Square Example
'
' This example assumes the robot platform contains two RC servos modified for
' continuous rotation, two WW-01 boards, and one OOPIC II+ controller board.
' The IOLines used are appropriate for a MarkIII controller; adjust the IOLines
' to suit your robot.
'
' Noetic Design, Inc.
' Rev 1.00 - 7/12/2004
'
' NOTE: this example does not use the DIR and CLK lines -- it uses the OOPIC oQencode objects
' to do the same thing.
' IOLine 13 = Left WheelWatcher DIR
' IOLine 12 = Right WheelWatcher DIR
' IOLine 8 = Left WheelWatcher CLK
' IOLine 17 = Right WheelWatcher CLK (for PIC use RA4/Exp 1, but this is LSDA for the OOPIC, so use RC1 for OOPIC)
' IOLine 27 = Left CHA
' IOLine 26 = Left CHB
' IOLine 25 = Right CHA
' IOLine 24 = Right CHB
' IOLine 10 = Left Servo
' IOLine 9 = Right Servo
'
' NOTE: this example does not use the following line sensors or proximity sensors,
' beyond setting them up.
' IOLine 7 = Left Line Sensor
' IOLine 6 = Center Line Sensor (N/C)
' IOLine 5 = Right Line Sensor
' IOLine 4 = Left Eye (Left GP2D02)
' IOLine 3 = Right Eye (Right GP2D02)
'----------------------------------------
Dim lww As New oQencode
Dim rww As New oQencode
Dim ls As New oServo
Dim rs As New oServo
Dim rc As New oCompare
Dim lc As New oCompare
Dim lw As New oWire
Dim rw As New oWire
Dim rstop As New oWord
Dim lstop As New oWord
Dim re As New oA2D
Dim le As New oA2D
Dim rl As New oDio1
Dim ll As New oDio1
'-------------------------------------------
' Perform One Time Hardware Setup
'-------------------------------------------
Sub Setup()
oopic.pullup = 1 ' pull up (to logic high) the PIC B port lines using the PIC's weak internal pullups
' set up quadrature encoder objects
lww.IOLine1 = 27
lww.IOLine2 = 26
lww.Operate = cvTrue
rww.IOLine1 = 25
rww.IOLine2 = 24
rww.Operate = cvTrue
' set up servos
ls.IOLine = 10
ls.Center = 23 ' means 31 = 1.5ms, 0 = .638ms, 63 = 2.39ms
ls.Operate = cvTrue
ls = 31 ' neutral
rs.IOLine = 9
rs.Center = 23
rs.Operate = cvTrue
rs = 31 ' neutral
' set up the right virtual circuit
rstop = rww ' assume we are at the goal for now
rc.Input.Link(rww) ' compare the current right wheel watcher count
rc.ReferenceIn.Link(rstop) ' to the right stop variable
rc.Fuzziness = 8 ' allow up to an error of 8 ticks
rc.Operate = 1
rw.Input.Link(rc.Between) ' when rww is between rstop +/- fuzziness, then turn off the servo
rw.Output.Link(rs.Operate)
rw.InvertIn = 1 ' this inverts the sense of between -- servo is on when not between
rw.Operate = 1
' set up the left virtual circuit
lstop = lww ' assume we are at the goal for now
lc.Input.Link(lww) ' compare the current right wheel watcher count
lc.ReferenceIn.Link(lstop) ' to the right stop variable
lc.Fuzziness = 8 ' allow up to an error of 8 ticks
lc.Operate = 1
lw.Input.Link(lc.Between) ' when rww is between rstop +/- fuzziness, then turn off the servo
lw.Output.Link(ls.Operate)
lw.InvertIn = 1 ' this inverts the sense of between -- servo is on when not between
lw.Operate = 1
' set up ranging sensors (not used in this example):
le.IOLine = 0 ' same as 4
le.Operate = cvTrue
re.IOLine = 3
re.Operate = cvTrue
' set up line following sensors (not used):
ll.IOLine = 7
ll.Direction = cvInput
rl.IOLine = 5
rl.Direction = cvInput
End Sub
'-------------------------------------------
' SetRightDriveDistance
'
' This subroutine takes two parameters:
' dir: set to 1 for forward, 0 for backward
' dist: set in terms of encoder ticks; with
' the oQencode object, you get 64 ticks
' per wheel rotation.
'
' We use the following objects:
' rww: the quadrature encoder object, which counts
' encoder ticks
' rs: the right servo
' rstop: the goal value for the encoder count
' rc: a compare object, used to determine
' when the goal is reached
' rw: a wire, to connect the result of the
' comparison to the operation of the
' servo.
'
' How it works:
' We turn off the servo to ensure the motor is stopped.
' We connect the count of the encoder (rww)
' to the input of the comparison object.
' We calculate a stopping point based on the
' desired direction and distance, then
' link that to the comparison object too.
' We use the fuzziness feature of oCompare to
' tolerate a little error in the counter
' since the robot can't "stop on a dime."
' We then link, using a wire, the output of
' the comparison to the running of the servo.
' We invert the wire's value, so that the servo
' runs until the comparison is reached.
'-------------------------------------------
Sub SetRightDriveDistance(dir As Byte, dist As Word)
rs.Operate = 0
' NOTE: the right wheel counts backwards compared to the left, when moving the robot forwards,
' so we correct for that here. That way, dir = 1 means forward for both wheels.
if dir = 1 then
rstop = rww - dist
rs = 0
else
rstop = rww + dist
rs = 63
end if
End Sub
'-------------------------------------------
' SetLeftDriveDistance
'
'-------------------------------------------
Sub SetLeftDriveDistance(dirl as Byte, distl As Word)
ls.Operate = 0
if dirl = 0 then
lstop = lww - distl
ls = 0
else
lstop = lww + distl
ls = 63
end if
End Sub
'-------------------------------------------
' WaitDone
'
' Wait until both servos are turned of,
' which indicates that they have both reached
' their goals.
'-------------------------------------------
Sub WaitDone()
Do
if Not rs.Operate then
if Not ls.Operate then
exit do
end if
end if
Loop
End Sub
'-------------------------------------------
' Main
'
' This simple example uses the above subroutines to drive the robot in a
' 6" square pattern.
' The resulting pattern will be followed well, but errors will accumulate
' over time due to wheel slippage and lack of velocity and acceleration
' control, as well as the need to use the fuzziness feature of oCompare.
' A more complex example would include these as well.
'
' How do we calculate how many ticks to count on the encoders? Here's how.
' The example robot's wheel base is 3.5":
' 3.5 * PI ~= 11" wheel base circumference
' To spin in place 90 degrees, move each wheel by 1/4 of the wheel base
' circumference = 11/4 = 2.75", with both wheels turning in opposite directions.
' (Another option is to leave one wheel stopped, and move the other forward by
' 11/2 = 5.5".)
' Now we need to figure out how to convert this distance required into
' ticks of the encoder. The example robot's wheels are 2.75" in diameter:
' 2.75 * PI = 8.64" wheel circumference
' with oQencode, we get 64 ticks per turn, leaving:
' 64/8.64 = 7.40 ticks per inch
' so, to spin in place 1/4 turn, we need to count:
' 7.40 ticks per inch * 2.75" = 20 ticks.
' To move 6" forward, we need to count:
' 7.40 ticks per inch * 6" = 44 ticks.
'-------------------------------------------
Sub Main()
Setup
Do
' drive a distance
SetLeftDriveDistance(1, 44) ' drive both wheels forward 6"
SetRightDriveDistance(1, 44)
ls.Operate = 1 ' now, start both motors at the same time.
rs.Operate = 1
WaitDone
OOPIC.Delay = 85 ' give it time to stop.
' Spin in place 1/4 turn:
SetLeftDriveDistance(1, 20)
SetRightDriveDistance(0, 20) ' turn clockwise 1/4 turn
ls.Operate = 1
rs.Operate = 1
WaitDone
OOPIC.Delay = 85
' Alteratively, move just the left wheel:
' SetLeftDriveDistance(1, 41)
' ls.Operate = 1
' WaitDone
' OOPIC.Delay = 85
Loop
End Sub
©2004-2005 Noetic Design, Inc. All Rights Reserved. Nubotics and WheelWatcher are trademarks of Noetic Design, Inc.