Go to Post I got Vista with mine. It's like getting moldy fruitcake for Christmas. - Koko Ed [more]
Home
Go Back   Chief Delphi > Technical > Programming
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
 
 
Thread Tools Rate Thread Display Modes
Prev Previous Post   Next Post Next
  #1   Spotlight this post!  
Unread 31-03-2004, 00:49
gnormhurst's Avatar
gnormhurst gnormhurst is offline
Norm Hurst
AKA: gnorm
#0381 (The Tornadoes)
Team Role: Programmer
 
Join Date: Jan 2004
Location: Trenton, NJ
Posts: 138
gnormhurst will become famous soon enoughgnormhurst will become famous soon enough
trentonDrive.c: our joystick/wheel drive code

I thought I'd share this bit of code. This is a single-joystick control routine for a robot chassis that uses two-wheel, two-motor drive. This is the version we are using in competition.

Its features include:

Squaring the motor values (not the joystick axes). This desensitizes
the joystick and compensates for the non-linear speed vs.
voltage function of the drill motors.

Turning radius independent of speed. The X Axis sets the ratio of the
wheel speeds, not the difference.

Y axis dead band independent of Victor deadband. Victor
deadband bypassed in software. No x axis deadband.

Dynamic rounding for an extra 2 bits of resolution for better slow-speed
control.

No floating point math.

I have been very pleased with how this code performs. It probably won't work on your machine without some modification (e.g. my motors are on pwm10 and pwm11) -- your mileage may vary. But since so many robots use two-wheel drive, it might be useful to many people.

Zipped code is attached.

Code:
#include "trentonDrive.h"

int clipInt( int in, int lowLimit, int highLimit );

#define RUN_MOTORS 1

// global joystick calibration values.  
//
unsigned char xMax = 254;
unsigned char xMin =   0; 
unsigned char xMid = 127, yMid = 127; 
unsigned char xHalfRange = 128; 

#define ROUNDING_BITS 2
#define ROUNDING_CYCLES ( 1 << ROUNDING_BITS )

#define HALF_DEAD_BAND 3  
#define CENTER_VALUE 127

#define LEFT_MOTOR  pwm11
#define RIGHT_MOTOR pwm10

#define SIGN( x )  ( ((x) > 0 ) ? +1 : -1 ) 
#define ABS( x )  ( ((x) > 0 ) ? (x) : (-x) ) 



/*******************************************************************************
* FUNCTION NAME: trentonDrive 
* PURPOSE:       Interfaces one joystick to the motors for manual driving.
*
* X & Y axes are linear here; the *wheel* values are squared.  
*
* I think the motors' speed vs. voltage curve flattens out at high speed,
* so squaring the motors tends to make it more linear.  Part of the problem
* of control at high speeds is that making a small change to the motor
* voltage doesn't make much difference when the curve has a low slope.  Squaring
* the motors helps this.
*                
*
* CALLED FROM:   this file, Default_routine
* ARGUMENTS:     xAxis, yAxis: joystick values in.
*                leftWheel, rightWheel: PWM values out
* RETURNS:       nothing
*******************************************************************************/


void
trentonDrive( unsigned char xAxis, unsigned char yAxis )
{
  int tmp;
  static unsigned char fracCycle = 0;  // for dynamic rounding

  unsigned char xx, yy;
  char signX, signY;
  long innerWheel, outerWheel;
  long left, right; // wheels

  unsigned char xMid = 127;
  unsigned char yMid = 127;



  // break the x & y axes into absolute value and sign.
  //
  tmp = ( (int) xAxis ) - xMid;
  signX = SIGN( tmp );  
  xx    = ABS ( tmp ); 

  tmp = ( (int) yAxis ) - yMid;
  signY = SIGN( tmp );  
  yy    = ABS ( tmp );  

  // give the y axis a deadband so the motors
  // will stop when you let go!
  //
  if ( yy < HALF_DEAD_BAND )
    signY = 0;
  

  // The main feature of this routine is that
  // for a given x axis position, the ratio of the
  // wheel speeds is independent of the y axis.  This
  // means that the turning radius won't change as you
  // change the speed of a turn.  
  //
  // The outer wheel goes faster in a turn.
  //
  // When the X axis is all the way left, the left
  // wheel will stop and the robot will turn on the 
  // left wheel at a speed determined by the y axis.
  // The same goes for the right.

  // these have a range as big as 2^7 
  //
  outerWheel = (xHalfRange + (long)(xx)) * yy / xHalfRange; 
  innerWheel = (xHalfRange - (long)(xx)) * yy / xHalfRange;  


  // square the wheel values 
  // This compensates for the non-linear speed/voltage
  // relationship of the motors.
  //
  // The range will be (2^7 * 2^7) = 2^14
  //
  outerWheel *= outerWheel;
  innerWheel *= innerWheel;

  // re-range it, 2^14 to 2^9
  // the "+ 16" is like adding 0.5 before rounding.
  // 
  outerWheel = ( outerWheel + 16 ) >> 5;
  innerWheel = ( innerWheel + 16 ) >> 5;

  // apply sign of Y axis to both wheels
  //
  outerWheel *= signY;
  innerWheel *= signY;

  // Use sign of x axis to determine if left
  // or right wheel is the outer wheel of the turn.
  //
  if ( signX > 0 )
  {
    left  = (int) outerWheel;
    right = (int) innerWheel;    
  }
  else
  {
    right = (int) outerWheel;
    left  = (int) innerWheel;    
  }


  // The Victor speed controllers have a deadband of about +/- 7 that
  // we will now bypass.  We are still at the *4 range, so we use 4*7=28.
  // 
  if ( left < 0 )
      left -= 28;
  else if ( left > 0 )
      left += 28;

  if ( right < 0 ) 
      right -= 28;
  else if ( right > 0 )
      right += 28;


  // dynamic rounding dither
  //
  fracCycle++;
  if ( fracCycle >= ROUNDING_CYCLES )
    fracCycle = 0;
  
  // add 0,1,2,3,0,1,2,3,...
  // this dynamic rounding hopes to achieve an extra 2 bits of
  // control granularity
  //
  left  = (left  + fracCycle ) / 4;  // must use division, not right shift, 
  right = (right + fracCycle ) / 4;  // because these are signed values.


  // limit the range and send it out
  //
  RIGHT_MOTOR  = (unsigned char) clipInt( left,  -127, 127 ) + CENTER_VALUE;
  LEFT_MOTOR   = (unsigned char) clipInt( right, -127, 127 ) + CENTER_VALUE;


#if RUN_MOTORS == 0
  LEFT_MOTOR   = CENTER_VALUE;
  RIGHT_MOTOR  = CENTER_VALUE;
#endif

}



int clipInt( int in, int lowLimit, int highLimit )
{
  if ( in > highLimit )
    return highLimit;
  else if ( in < lowLimit )
    return lowLimit; 
  else 
    return in;
}
Attached Files
File Type: zip trentonDrive.zip (2.3 KB, 114 views)
__________________
Trenton Tornadoes 381
2004 Philadelphia Regional Winners
2006 Xerox Creativity Award
---
My corner of the USPTO.
My favorite error message from gcc: main is usually a function
My favorite error message from Windows: There is not enough disk space available to delete this file.
 


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

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

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
heres the code. y this not working omega Programming 16 31-03-2004 15:18
What is wrong with this code???? It won't Compile and I don't know why? Please Help CrashZero Programming 23 26-03-2004 09:44
Changing 1 joystick code to 2 (rookie team) Brawler006 Programming 5 20-02-2004 17:00
TechnoKats Automated Test Drive Code Greg McCoy Programming 1 16-01-2003 17:45
"Motors and Drive train edition" of Fresh From the Forum Ken Leung CD Forum Support 6 29-01-2002 12:32


All times are GMT -5. The time now is 22:34.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi