Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   Programming tricks (and former trade secrets) (http://www.chiefdelphi.com/forums/showthread.php?t=54668)

Dave Flowerday 20-02-2007 23:17

Re: Programming tricks (and former trade secrets)
 
Quote:

Originally Posted by kitscuzz (Post 582852)
And we're working on sticking the gyro bias into the eeprom as well in order to prevent recalculation every time you turn on the robot.

I'd recommend against doing this. The gyro bias can vary quite a bit based on a number of factors like temperature, voltage, etc. It's completely possible for it to be different every time you turn the machine on.

tdlrali 21-02-2007 00:05

Re: Programming tricks (and former trade secrets)
 
We wrote some code that eliminates the need for a programmer...
More on this later :D

htwiz2002 21-02-2007 00:39

Re: Programming tricks (and former trade secrets)
 
5 Attachment(s)
Well, This year I was set on programming autonomous, but I am hardly sure we will have a robot that needs it :(. It is 19% complete, and still in alpha stage, but I had promised myself that I would continue even though the robot is shipped (having problems trying to get the Controller to work without an OI, but I believe that that is default), and what I have now may interest some.

As I said, it is VERY incomplete, and not altogether working. It is a terminal interface to the controller (mainly for debugging purposes) that eventually will replace most programming that a team would need to do (as far as autonomous and some others, PWM mappings and others will still need to be modified every now and then :D).

I have already integrated Kevin's Camera Processing routines, Serial IO routines, and EEPROM (still unverified, sigh) routines, and the interface is kinda cool. If you want some more info, check out the attachment.

The main features are (/will be):
- Easy autonomous programming by the end-user (a.k.a. the non-programmers) using the terminal interface
- Easy Drive controls altering/setting using the terminal interface
- QuickView info on various IO's (like pwms, DigIO, AnaIO, Battery voltage) through the terminal
- On-the-fly Calculation of field placement using camera, accelerometers, gyros, IR, yada yada...
- Easy autonomous programming... (wait, did I already say that?) using a (slightly) intuitive terminal interface
Did I mention that all of this is through the terminal interface?
Unfortunately, I haven't coded the IFI loader's interface menu yet, but HyperTerminal works absolutely fantastic for now, with auto-updating information on the fly and a much more user-friendly menu (I tried implementing a line-by-line menu; didn't work out at all, updated information tended to cause the menu to disappear rather quickly, yada yada.)

Still in Beta! If anyone could assist writing autonomous action code (read about it in the documentation) please PM me!
BTW, does anyone have a memory free count for the default code? I would like to post how much memory my "add-on" will take, and I forgot :ahh:.
Also, I would like to add code for things like Gyros and Accelerometers, but since We do not have such things (working or not) I cannot possibly program for it. At the current time almost none of my program uses timers (forgot how, :stupidme:) and If I cannot use data from sensors, the code would be blind. anyways...
Like I said, 19% complete, still need LOTS of code, see attachment for more info.

Catch you all later!:p

Astronouth7303 21-02-2007 00:53

Re: Programming tricks (and former trade secrets)
 
In addition to debuting the scripting system I wrote in the pre-season 2006 (that we ended up not needing -- it was a very strange robot), I tried a few structural things.

The scripting is based on preprocessing direct calls to functions, instead of Kevin Watson's structure-based navigation code. (The preprocessing is so that the script will abort when autonomous ends.) It follows the idea of a lot of little loops: every command calls HEARTBEAT at least once, and that handles getdata() and putdata() calls. This all makes C-like syntax:
Code:

SCRIPT drive_half_field()
{
    CMD_UNFURL(NO_WAIT);
    CMD_DRIVE(FEET(20));
    CMD_TURN(DEGREES(90), RIGHT);
    CMD_WAIT(SECONDS(2));
    CMD_HOME_IN(); // Drives towards the light
    CMD_DROP(); // Drop that keeper!
    CMD_DRIVE(INCHES(-18));
    CMD_TURN(DEGREES(90), LEFT);
    CMD_DRIVE(FEET(20)); // And maybe crash into someone!
}

You can also stick in loops, ifs, or any other constructs, calls, or whatever you want. Just call HEARTBEAT if you go too long.
One of the big ones this year was that every mechanism followed a standard interface. Every mechanism had the following macros or functions:
  • NAME_Init() -- Initialize state
  • NAME_UserMode() -- Perform operator mode controlls
  • NAME_Sensor() -- Take sensor readings at the begining of the slow loop (autonomous or user mode)
  • NAME_Process() -- Handle control loops at the end of the slow loop
  • NAME_IsDone() -- For mechanisms that moved to a position, had it reached its position?
  • NAME_*(...) -- Any control functions (eg, Arm_GoTo(ANALOG val), Drive_1stick(UCHAR drive, UCHAR turn), etc)
This was facilitated by wrappers around getdata() and putdata() which handled this. Note that these functions are used in both autonomous and operator mode.

I also had my usually tools, namely pinouts.h (a configuration file of all the hardware I/O aliases and tweaking constants), Eclipse, and old code.

Also, I'm the operator this year, so I can make it as complex as I want. (Because I know how it all goes!) Ok, not really. There is a backup driver that I have to keep up-to-date.

Amongst the things I may do between now and our competitions:
  • Write a generic python script to generate lookup tables
  • Write another LCARS Dashboard for this year's robot (likely in python, so that I can develop on my Linux desktop)
  • Adding a real-time clock using one of the timers

Quote:

Originally Posted by benhulett (Post 582685)
Designed a "level code" to make the arm operator's job 10x easier :D
Ex: you push this button, the arm moves to level 2 and sets the motor to neutral (until you push another button)

We have that, too. We just used a pot, though.

Quote:

Originally Posted by tdlrali (Post 583083)
We wrote some code that eliminates the need for a programmer...
More on this later :D

Isn't that ironic? Writing code to keep you from writing code?

Japper 21-02-2007 01:41

Re: Programming tricks (and former trade secrets)
 
Me being the main programmer on a rookie team and not knowing what to expect, and not programming in over 10 years, I incorporated the following "different" features:

1. Neutral control/Panic button: Before we knew about the v14 fix for the run on condition, I was concerned about the robot running out of control as we had encountered this problem, so I added some code that puts both motors in Neutral by pressing either joystick trigger button. (we have a 2 wheel drive CIM motor system). I left this feature in the code in case in the heat of the moment, the operator needs to stop.

Quote:

if (p1_sw_trig || p2_sw_trig)
{
pwm01 = pwm02 = 127;
}
2. Scaling factor/ Turbo Mode: I found that our Cim motors run a little faster than we wanted for manueverability at full PWM output levels (0 & 255) so I used a scaling factor that is applied to the each drive wheel joystick Y position and then mapped each joystick wheel to act as a turbo button which would give us burst speed if we needed it. Consequently, we added raised casters in the back of our chassis to keep it from tipping as hitting the turbo button gave it a wicked (but cool looking) lurch like you see in funny cars on the 1/4 mile track...

Incidently, because the turbo mode is set for each drive wheel independently with the thumbwheel on its joystick, some pretty quick and possibly uncontrolled turns can be made.

Also, testing confirmed that if the operator holds down the triggers (neutral and puts both joysticks forward with both the turbo buttons on and then releases the trigger buttons that we could do a "hole shot" and a "wheelie"... well it looks cool anyhow...:)

The Y axis code (p1_y = (p1_y /speed) + plus_speed; & p1_y = (p2_y /speed) + plus_speed; ) is in there as we originally set this up for single joystick control and it works for that as well so I left the code in there. Here is what my crude code for that looks like:


Quote:

/******************************** Slower mode **********************************************
* The following code sets all PWMs to default lower speed (dictated by scaling factor *
* (speed) and then to full output level of each joystick when its wheel button is pressed *
* and held *
************************************************** *****************************************/

static int speed = 3; /* speed control scaling factor = PWM divided by this number */

static int plus_speed = 80; /* this value is added after speed control scaling factor to center and normalize
the PWM value (if speed = 2 use 64, if speed = 3 use 80, if speed = 4 use 96) */

if (p1_wheel < 60)
{
p1_x = (p1_x /speed) + plus_speed; /* adjust PWM by a factor of speed and add plus_speed to compensate */
p1_y = (p1_y /speed) + plus_speed; /* adjust PWM by a factor of speed and add plus_speed to compensate */
}

if (p2_wheel < 60)
{
p2_x = (p2_x /speed) + plus_speed; /* adjust PWM by a factor of speed and add plus_speed to compensate */
p2_y = (p2_y /speed) + plus_speed; /* adjust PWM by a factor of speed and add plus_speed to compensate */
}
3. Backlash Prevention: I put a simple normailizing feature on the drive wheel joysticks to center these and to prevent backlash on the motors due to a released joystick. I noticed that when the joystick was released from the forward position that it would kick the motor in reverse momentarily and I was concerned about blowing a fuse from the excessive current draw on this condition. So I added the following code:
Quote:

/**************************Backlash Adjust ************************************
* This section sets the joystick X & Y zero points if PWM is between 124 & *
* 130 to avoid backlash near zero crossings *
************************************************** ****************************/

if (p1_x < 130 && p1_x > 124)
{
p1_x = 127; /* normalize X neutral on Joystick */
}

if (p1_y < 130 && p1_y > 124)
{
p1_y = 127; /* normalize Y neutral on Joystick */
}

if (p2_x < 130 && p2_x > 124)
{
p2_x = 127; /* normalize X neutral on Joystick */
}

if (p2_y < 130 && p2_y > 124)
{
p2_y = 127; /* normalize Y neutral on Joystick */
}


4. Acceleration ramp up/down: We found that the acceleration was too quick so we added the following simple ramp up code:


Quote:

/************************** Ramp up Routines ************************************
* This section ramps the joystick X & Y PWM levels for smooth transistions of *
* acceleration or deceleration *
************************************************** ******************************/

#define ramp_speed 3

if(pwm01 > (p1_y+ramp_speed))
{
pwm01 += ramp_speed;
}
else if (pwm01 < (p1_y-ramp_speed))
{
pwm01 -= ramp_speed;
}
else
{
pwm01 = p1_y;
}
if(pwm02 > (p2_y+ramp_speed))
{
pwm02 += ramp_speed;
}
else if (pwm02 < (p2_y-ramp_speed))
{
pwm02 -= ramp_speed;
}
else
{
pwm02 = p2_y;
}
5. Motor Bias Adjustment: Also, I found that the motor bias was different with the two CIM motors especially since one was turned 180 degrees from the other wheel that the robot would track to one side with both drive wheel joysticks in the same position. I added corrections to these but as the motors heat up I couldn't count on this being a constant value so I incorporated a dummy plug to add a correction only if the dummy plug is installed. The code looks like this:

Quote:

/* ------------ correct for motor speed if rc_04 is low */

if ((p1_y < 255) && (rc_dig_in03 == 0))
{
pwm01 = pwm01 + 2;
}

if ((p1_y > 2) && (rc_dig_in03 == 0))
{
pwm01 = pwm01 - 2;
}
6. Troubleshooting aid: When trouble shooting my robot's motors and controls, I had a hard time seeing some of the joystick values in dashboard viewer so I mapped these to un0used PWM outputs so I could see what was going on which made it easier to figure this out...

Quote:

pwm11 = p3_wheel; /* show us the value of p3_wheel on dash board viewer as pwm11 */
pwm09 = rc_dig_in02; /* show us the value of rc_dig_in02 on dash board viewer as pwm09 */
pwm08 = rc_dig_in01; /* show us the value of rc_dig_in01 on dash board viewer as pwm08 */
Sorry to be so long winded but being a rookie and not programming in quite a while I am sure that my code looks a little crude to most of you professionals out there but it does work for what it was intended.

Some of these ideas that I used, I am sure you pros have figured out better methods for or used something similar and I am hoping that you share those ideas with me...

I just wanted to share a few of my ideas with you all...

Good luck to all in your competition!

buddy.smith 21-02-2007 16:13

Re: Programming tricks (and former trade secrets)
 
Hm... We used mecanum wheels. We coded the usual translation routines, then used a third axis on the joystick (twist) for rotation.

We didn't design it this way, but what emerged was that driving in circular arcs was VERY easy, which the drivers love because of the design of the rack.

Other features...the arm's motion is limited by a pot, but if the pot fails (becomes disconnected), the arm will still be usable. I wish I could say we thought of this BEFORE the pot failed (wiring problem)....

I'd love to restructure the First code...I really don't like their coding style, but 6 weeks isn't enough time for that, so making the robot work was priority #1

--buddy

Guy Davidson 21-02-2007 17:44

Re: Programming tricks (and former trade secrets)
 
One of the neater things we did this year has to do with our arm. We use a pot to get position feedback about the location of the arm. Out of the 0-1023 range the pot can give us, we only use about 250. On every activation of the robot, the contoller reads the initial pot value, and makes it the temporary zero for the match. Hence, even if the pot slips between matches, or moves, or we have to change it, it still works.

Jake M 21-02-2007 18:57

Re: Programming tricks (and former trade secrets)
 
I implemented a globals.h file to handle all variables that need to be accessed across multiple .c files, and a handy macro that can make all these declarations in a single statement, which makes things easy if you need to add more variables, or change the name of an existing one.

Code:

/********************************************************************************
* FILE NAME: globals.h
*
* DESCRIPTION:
*  This file contains the definitions of global variables, used by multiple
*  modules in the robot program. A macro is used to resolve the separate
*  definition of each variable, in each module. Simply include this file in
*  all of your C Source files, but also make sure to insert the line
*    #define MAIN_C
*  in your main.c file.

********************************************************************************/

/* GLOBAL_VAR(Type, Name, Initial Value); */
#ifdef MAIN_C
#define GLOBAL_VAR(t, n, v) t n = v
#else
#define GLOBAL_VAR(t, n, v) extern t n
#endif

/* example */
GLOBAL_VAR(unsigned char, test, 0);

In addition, I came up with a similar macro to deal with the relays.

Code:

#define drt_hand_piston_fwd  relay2_fwd
#define drt_hand_piston_rev  relay2_rev

...

#define RELAY_FWD  1
#define RELAY_OFF  0
#define RELAY_REV  -1

#define Generate_Relay(r)\
        {\
          r##_fwd = 0;\
          r##_rev = 0;\
          if(r == 1)\
            r##_fwd = 1;\
          else if(r == -1)\
            r##_rev = 1;\
        }

...

GLOBAL_VAR(char, drt_hand_piston, 0);

...

Generate_Relay(drt_hand_piston);

I also tried to use the EEPROM to make the arm_position self-calibrating, but seeing how I only got the robot for programming late on Monday, I didn't have enough time to make it work.

Alan Anderson 21-02-2007 20:17

Re: Programming tricks (and former trade secrets)
 
Quote:

Originally Posted by meatmanek (Post 582659)
Our team uses an 'abstraction layer' which consists of a bunch of global variables...

We do much the same thing, but our abstraction layer is only two global variables. One is a structure full of commands like desired position or turn rate, and the other is a structure full of feedback like manipulator position or current heading. Keeping things together like that helps keep the code more understandable, I think.

Stvn 21-02-2007 22:41

Re: Programming tricks (and former trade secrets)
 
Our biggest difference this year is using the USB chicklet with an XBox controller to control our arm. The little chicklet lets us use 12 buttons by using two analog ports along with digital.

Other than that, we have switches that we set before each match and read so that we can choose between up to sixteen different autonomous modes.

It's really too bad that the only one programmed is "Do Nothing"...

Andrew Schreiber 21-02-2007 23:07

Re: Programming tricks (and former trade secrets)
 
This year we have decided to give every motor on our robot its own structure. This allows each motor to have the several constants it needs for our two PID functions. Every motor is going to be controlled by the position PID and the drive motors will be controlled with the velocity and position PIDs. All the PIDs are designed to work with any of the motors.

To help us figure out the constants we are working on a terminal program (similar to kev watson's that was used with the camear) and a nice interface for it. This is mostly just for fun though.

Oh, and using the PID functions in the arm we have written code to allow us to specify the (x,y) position (in front of our arm's current rotation) and have the arm calculate the angles it needs to reach that position. I think its called Inverse Kinematics.

Tom Bottiglieri 21-02-2007 23:10

Re: Programming tricks (and former trade secrets)
 
-Modular PID Driver
-Modular "Drive" Driver
-EEPROM based gains and controls
-Command based autonomous mode
-self generating autonomous scripts from serial port (stored in EEPROM)
-GUI script creator
-LCD screen on robot

Pretty much all the stuff we did last year on 195, with a few new goodies.

WesleyC 21-02-2007 23:20

Re: Programming tricks (and former trade secrets)
 
I'm something of a rookie to the programming field, particularly robotics programming. Heck, I didn't really know C until the beginning of the season, and I had no CLUE what a PD or PID loop was until a mentor showed me the ins and outs of it...

However, one of our team rules being that only the students may produce the final product, I was drafted into the job--especially since I was the only guy on the team that knew a #define from an int.

Thankfully, I had an older robot to practice on, and I'm fairly well up on my higher math algorithms, so it wasn't all that bad...

Our robot is a 2-wheel drive, caster steering lightweight--not designed for pushing matches, but fast enough to get out of the way should one begin. Given that information, I quickly realized that even though our team used NO gearbox except the KOP transmission, we needed to have both very high speed and enough precision to control the 'bot at low speed. To combat this discrepancy, I eventually resorted to a math trick I'd learned long ago... Exponential control.

The code goes something like this:

Quote:

//Convert input from 0 - 255 range to -127 - 127 range
input -= 127;

//Square input and divide by 127, giving us the expected range--since
// squaring a variable loses its sign, multiply by 1 or -1 depending on the
// input sign
output = (input * input / 127) * (input > 0) ? 1 : -1;

//Send out the modified output; add 127 to put it back into 0 - 255 range
motor_speed = output + 127;
This control algorithm seems to work quite nicely for our drivers. They're able to control the machine with a high degree of precision when the input is small, but as they push the stick farther, the robot gains in speed... well, exponentially. :D

Of course, this is a little different than the code we used, as it's not mixed for multiple drive motors or anything.


A couple other cool things we did:

-Position-based arm: Position is controlled by a shaft encoder; if the arm is knocked off position it will automatically try to return to that position
-Simple drive system--the robot can be controlled completely using only two joystick axis, the top hat, and a trigger
-Automated function for "return to home"--resets the robot, brings the arm and wrist back into folded positions and readies it for another round
-Automated function for "drop ringer"--we determined a precise sequence of motions that are very efficient for hanging a ringer on a post once positioned properly, then assigned a button to perform all these motions simultaneously. The result is rather cool--the robot drops the ringer on the rack in one smooth (though rather noisy--it's running 3-4 elements simultaneously!) motion, much faster than any of our drivers could perform the task, and gets the arm out of the way of the ringer entirely.

We tinkered around with autonomous code, and with the use of 2 PD positioning algorithms got the robot to drop a ringer successfully. However, we'll need a couple things tweaked before competition--the building team crated the robot before I could manage to get the code to raise the arm to the proper scoring position in! :yikes:

kaszeta 22-02-2007 09:15

Re: Programming tricks (and former trade secrets)
 
Quote:

Originally Posted by Alan Anderson (Post 583659)
We do much the same thing, but our abstraction layer is only two global variables. One is a structure full of commands like desired position or turn rate, and the other is a structure full of feedback like manipulator position or current heading. Keeping things together like that helps keep the code more understandable, I think.

Now that's an idea I like.

MARS-CJ 22-02-2007 21:55

Re: Programming tricks (and former trade secrets)
 
Quote:

Originally Posted by benhulett (Post 582685)
Designed a "level code" to make the arm operator's job 10x easier :D
Ex: you push this button, the arm moves to level 2 and sets the motor to neutral (until you push another button)
We can have it working with and without an encoder

:ahh:

That's exactly what we were thinking of doing! But we never got around to actually putting the code in.

Pretty much the only "trick" we put in there was an acceleration code, which would only let the motor value go up by 5 every loop. I believe there was a thread about that sorta thing... (http://www.chiefdelphi.com/forums/sh...520#post572520)


All times are GMT -5. The time now is 18:06.

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