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)

Alan Anderson 20-02-2007 16:11

Programming tricks (and former trade secrets)
 
Now that the robots are on their way to their respective drayage, I'd like to hear about some of the innovative, clever, or just plain cute programming features that teams came up with this year. Did you implement a particularly elegant control system? Did you manage to make the driver's job trivial this year? I understand if you want to keep things mysterious for a few weeks, but please consider adding to the thread once you've demonstrated your robot in competition.

Here are a few novel things the TechnoKats did this year.
  • The programmers figured out how to be lazy and not have to physically reach into the robot and push the PROG button in order to load new software. With a single wire connected between a digital output and the external PROG pin, the robot can push its own button. We have it programmed to set the output low when the letter 'p' is received on the program serial port.
  • Since the team managed to build a second robot with a fully-functioning appendage, we needed to keep track of two separate sets of PID control constants. That was enough of a push to get us to adapt Kevin Watson's EEPROM-based configuration code for our use. With a special "tuning box" plugged in to one of the OI ports, we can adjust the constants on the fly, and then save them to EEPROM. No more recompiling just to accomodate a slightly lighter or heavier bit of hardware!
  • Since we already had the necessary EEPROM framework in place, we also gave the operators "presets" that they can store and recall at will.
Anyone else feel like sharing?

Rob2713g 20-02-2007 16:21

Re: Programming tricks (and former trade secrets)
 
Our programming team created a 2 joystick drive for mecanums, which provides much more control than the common single joystick drive.

Bharat Nain 20-02-2007 17:05

Re: Programming tricks (and former trade secrets)
 
We renamed and (re)defined everything in our program making everything VERY modular and easy to read. Some of these things can even be copied, pasted and tuned for many other robots.

meatmanek 20-02-2007 17:19

Re: Programming tricks (and former trade secrets)
 
Along the lines of renaming things...

Our team uses an 'abstraction layer' which consists of a bunch of global variables and two functions: abstractIn() and abstractOut().
The global variables are things like driveLeft, driveRight, joyL, joyR, etc.
Our abstraction code takes renaming it one step farther. Rather than using the 0-255 scale where 127 means stop, we shift it down 128 (signed char, rather than unsigned), and we also invert motors where it makes sense. (one side of the drivetrain, any appendages where the motor is 'backwards')

This helps make our code MUCH more readable and configurable, and makes algorithms a bit simpler.

Another trick we did this year was one big state machine for teleoperated mode. In the past, our robot has been nothing more than a glorified remote control car. This year, our robot knows what it's supposed to be doing, with a set of states for each objective, and so the drivers are freed to think more about the game, rather than the robot.

benhulett 20-02-2007 17:50

Re: Programming tricks (and former trade secrets)
 
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

Cuog 20-02-2007 18:01

Re: Programming tricks (and former trade secrets)
 
I made the robot fight gravity ;) actually it was a code w/ the accelerometer that would try and push back, but with no testing it made driving impossible because I got the direction that it corrects wrong, so it fights itself, oops

In the way of useful things I did this year, I got our omniwheel bot to drive mostly straight(still have to tune that) using a gyro chip that hopefully will self calibrate. The drive code also very nicely allows us to drive it FPS style with one joystick for translation and the x axis on the other for spin.

Robo_Coyote 20-02-2007 18:11

Re: Programming tricks (and former trade secrets)
 
Our programer made our lift motor a 20000 position servo with a program that state level 1 is between position 5000, and 7500 and so forth. He also got most of our operational programing done first time ever for that.

Kevin Watson 20-02-2007 20:03

Re: Programming tricks (and former trade secrets)
 
I've been working on a library that will work with version 3.0 of the C18 compiler. I'm almost there...

-Kevin

meatmanek 20-02-2007 20:23

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

Originally Posted by Cuog (Post 582694)
I made the robot fight gravity ;) actually it was a code w/ the accelerometer that would try and push back, but with no testing it made driving impossible because I got the direction that it corrects wrong, so it fights itself, oops

In the way of useful things I did this year, I got our omniwheel bot to drive mostly straight(still have to tune that) using a gyro chip that hopefully will self calibrate. The drive code also very nicely allows us to drive it FPS style with one joystick for translation and the x axis on the other for spin.

Last year, we used mecanum wheels to drive our robot. I played with some code using the YRG to make the joystick always be relative to the driver, rather than the robot. Push forward on the joystick, and it goes down the field, push right on the joystick, and it goes right on the field, twist the joystick and the robot will turn. Unfortunately, our drivetrain was too fast, capable of turning about one revolution per second (without the rest of the robot, I don't know what it was with all of that). The YRG was limited to 80 degrees per second. I wanted to get another gyro, but we never followed through on that.

If you're using a DAA to control an arm, you might consider using a quadrature encoder. DAAs are prone to drift, and aren't very accurate when you integrate them twice to get position.

Cuog 20-02-2007 20:27

Re: Programming tricks (and former trade secrets)
 
I had to slow down the speed of our spin because at full speed the spin is roughly 2 rev/sec, not drivable at all, the YRG is on there to adjust the spin so that we spin reliably and dont over spin.

the DAA was intended to push back against another robot when they bump us, sadly it ended up fighting itself so thats something I'm going to try and fix on thursday otherwise it will just be scrapped.

kitscuzz 20-02-2007 20:50

Re: Programming tricks (and former trade secrets)
 
We were just proud to get so many systems to work together:

The adc is now working in conjunction with the gyro code to integrate 400 times a second (which needs a long long, but we made it reset every 360 degrees to prevent overflow).

I'm soon to add in the Dual Axis Accelerometer to account for tilt so that I can kill the gyro integration if the tilt exceeds a certain angle.

We used the eeprom and trig funtions in order to make field-oriented holonomic (which I almost had working perfectly when they tore it out of my hands to ship it... hardware team didn't get the robot done until yesterday... sadness). 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.

The encoder (a banner IR sensor) counts the number of times a wheel turns in order to keep track of the height of the arm.

And we were going to do the camera, but the autonomous ended up being so enormous, that we had to abandon it. We made the whole thing with multiple light tracking, and we had a plan, but it was just too difficult to get it running straight without a working Dual Axis Accelerometer and perfect camera code that we had to give up. 15 seconds is not very much time.

Although it's not particularly useful code, anyone who wants it can PM me for the accelerometer and gyro code we made. It's a little too processor intensive if your planning on doing the camera, but it can integrate up to 6200 times a second to keep really close track of the gyro angle or velocity. For whatever reason, we couldn't seem to make it keep track of the velocity very well, but we cut the error on the angle down to .5 degrees for a full spin on the bot.

JBotAlan 20-02-2007 21:16

Re: Programming tricks (and former trade secrets)
 
I wrote a two-shot arm control module--if the arm's potentiometer value is more than a certain amount, it will send full speed out to that joint, otherwise, it will send a slower value until it is within a "deadband". Unfortunately, I didn't get as much testing in as I wanted to because the gear that meshes with the worm-tooth kept losing teeth and the robot dentist got more and more agitated as the night went on...I nicknamed our 'bot "gear muncher" because I broke 3 gears yesterday and 2 the day before. Little brass teeth are littering the floor. Not Good. We have some hardened steel gears coming, though.

I also have an EEPROM solution in place--you move the arm to where you want it, then hold a button combo on the handheld and the robot saves that position to the EEPROM and will recall it when that button is pressed.

Of course, our code still isn't done. It's...functional...which is an improvement over last year.

JBot

kitscuzz 20-02-2007 21:24

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

Originally Posted by JBotAlan (Post 582884)
I also have an EEPROM solution in place--you move the arm to where you want it, then hold a button combo on the handheld and the robot saves that position to the EEPROM and will recall it when that button is pressed.

JBot

Hey, that's an excellent idea! :D Well now I have a solution for resetting the arm position before each match. The banner IR encoder solution I talked about is arbitrary, this will keep it in place.

kaszeta 20-02-2007 21:29

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 and two functions: abstractIn() and abstractOut().
The global variables are things like driveLeft, driveRight, joyL, joyR, etc.
Our abstraction code takes renaming it one step farther. Rather than using the 0-255 scale where 127 means stop, we shift it down 128 (signed char, rather than unsigned), and we also invert motors where it makes sense. (one side of the drivetrain, any appendages where the motor is 'backwards')

We've done this for several years. We have one set of functions that maps user inputs into various abstract state variables (speed and heading, for example, arm angle, etc), and a second set of functions that maps these state variables into pwms and relay settings. This is nice, since it means that the autonomous modes are programmed the same way.

I also got the students to use a rigorously defined finite state machine for the autonomous mode this year, and it really paid off. We gained a lot of autonomous functionality without a lot of extra effort, and it's a lot more debuggable.

Otherwise, the other neat innovation was using large numbers of infrared sensors to do a lot of our work (especially in autonomous). They also give us a "virtual bumper" that can keep us from hitting things we don't want to.

kaszeta 20-02-2007 21:31

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

Originally Posted by meatmanek (Post 582821)
Last year, we used mecanum wheels to drive our robot. I played with some code using the YRG to make the joystick always be relative to the driver, rather than the robot. Push forward on the joystick, and it goes down the field, push right on the joystick, and it goes right on the field, twist the joystick and the robot will turn. Unfortunately, our drivetrain was too fast, capable of turning about one revolution per second (without the rest of the robot, I don't know what it was with all of that). The YRG was limited to 80 degrees per second. I wanted to get another gyro, but we never followed through on that.

Get the ADXRS300EB gyro (or the Sparkfun breakout board equivalent, which is easier to wire), and you won't regret it. Last year we made a prototype holonomic drive, and it was way fun to drive, and user-centric coordinates allow you to easily do things like spin while driving.

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)

meatmanek 22-02-2007 22:00

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

Originally Posted by buddy.smith (Post 583489)
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

Amen to that.

efoote868 22-02-2007 22:00

Re: Programming tricks (and former trade secrets)
 
this year we used 2 SVN servers to keep track of all of our code, and changes. One was for the inexperienced programmers, so that they could learn, and the other was for the final versions of the code (code that would always compile, instead of having to track down all the convention mistakes and what not). Helped so that more than 1 person could work on the code at once, and allowed for much faster programming.
Also, for 868's state machine, we had multiple people write their own version, so that we could easily take the best of them. (points to meatmanek for winning out)

meatmanek 22-02-2007 22:08

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

Originally Posted by efoote868 (Post 584677)
(points to meatmanek for winning out)

It's amazing how excessively commenting your code (read: Just about every line that isn't a duplicate of a previous line) can bring about the appearance of quality.

JimGRobot 23-02-2007 20:43

Re: Programming tricks (and former trade secrets)
 
Great thread, there are many good ideas out there.

We talked about the remote PROG button ourselves, but never implemented it.

One thing we did for the drivers was create an "Auto Trim" button for the joysticks. You use the regular trim adjust to get them close, then push the button. This saves the current joystick positions and subtracts those values from all future readings. This is built into a joystick "class" that is part of a code library that will be released to the world this spring.

We have an automatic scoring button, as others have mentioned, and separate buttons for all of the arm preset positions. We used a potentiometer for arm position feedback, and it works well.

One other cool thing is a micro-switch on the tube gripper to automatically close the jaws with a tube is present. This makes tube pickup very quick and easy.

We wired a bunch of momentary switches across a string of resistors connected to a single joystick input on the OI, instead of using 10 digital input bits. I will be making some PC boards over summer so others can do this very easily. The code does a little math to convert the input value into a switch number; this is built into another library class.

I guess that's all for now...
Jim

dpick1055 23-02-2007 22:02

Re: Programming tricks (and former trade secrets)
 
Do you think you could talk more about the auto-trim button. We're having a lot of trouble keeping our joysticks in the right trim position. Or is it a closely guarded secret :)

JimGRobot 24-02-2007 00:56

Re: Programming tricks (and former trade secrets)
 
Thanks for the note, no, this one is a loosely guarded secret...

We do some strange things with the scaling of our joysticks, but the principle is the same regardless of how you do it.

Start by creating a static global variable for each joystick axis, like:

char p1_x_offset = 0;
char p1_y_offset = 0;

Any place that you normally use the raw joystick value, use the joystick value minus the offset value, like:

pwm01 = (p1_y - p1_y_offset); //used to be p1_y only

Set the offset value to the joystick value when a button is pressed:

if ( button_pressed )
p1_y_offset = p1_y;

I think you get the idea. You are better off working with integer variables to avoid overflows, and handle limit checking, then converting back to char for writing to the pwm output.

Another thing to consider is adding a button to clear the offset. If you use this method to remove a large error, remember that the offset correction will not be present when the robot is reset, and the thing might take off.

In our implementation we limit the offset value to about 6 counts...

Let me know if you have other questions.

Jim

dpick1055 24-02-2007 01:18

Re: Programming tricks (and former trade secrets)
 
I'm still having a little trouble understanding this. Say when your joystick is centered it gives a value of 130. If you set that to your offset and then move your joystick to 200. Wouldn't that only send you forward at a speed of 70? And then when your joystick is somewhere near 127 you would be going in reverse?

Thanks
-David

JimGRobot 24-02-2007 01:31

Re: Programming tricks (and former trade secrets)
 
Sorry for the confusion, what I posted earlier only works if you scale your joysticks around zero by subtracting 127 from the joystick reading, and adding 127 back in before writing to the pwm.

So, here is a tweak to my earlier post. Instead of setting the offset to the joystick value, set it to the joystick value minus 127:

p1_y_offset = p1_y - 127;

If the joystick value is 130, and you press the auto trim button, the offset will be 3. When this value is subtracted from 130, you get the null value of 127. When the joystick value is 200, you get 197, and 100 you get 97.

If the offset value is too big, it will limit the range of the joystick value. Suppose you auto trim when the joystick value is 77, the offset is -50. When the raw value of the joystick is 254, the corrected value would only be 204, and if the raw value was less than 50, the corrected value would already be limited at zero.

Play around with this a little. The principle involved is to capture the difference between the joystick's actual value when trimmed, and what you want it to be when trimmed, and apply that difference to future readings.

Jim

dpick1055 24-02-2007 01:35

Re: Programming tricks (and former trade secrets)
 
Oh haha now I get it. I actually scaled our joystick values too so I could use a squaring function for driving. Thanks for the help, this is definitely something our drivers will appreciate.

6600gt 24-02-2007 03:32

Re: Programming tricks (and former trade secrets)
 
I started in the summer but I got in working during the build season. When I started I didn't even know the difference between C and C++. Through extensive research I was able to create a kind of "master" dashboard using Visual C++ 2005. It was designed to decrease the debugging time. I also had to develop the support code on the RC to work with this application through the program port.

You can watch any 10 int values simultaneously in a list form. Just choose form two drop down lists, one picks the type of variable(pwms, analogs, D In, D out, joysticks axes, etc.) and the other one is for choosing the number, ex. pwm05, and one can watch any preprogrammed value in real time. No need to reflash just to watch a different pwm!

It also has 16 extras that can be assigned to any variable like this, e_01 = variable(reprogramming is required but its much faster that modifying multiple printfs). Call up E1 from the GUI drop down list and you get a real time stream. The RC only sends 21 bytes over the serial port every loop, yet it provides the GUI with 10 int values.

The GUI can also graph the first 2 columns, allowing one to watch the relationship between the joystick input and the pwm output as it run through his/her algorithms, for example.

Also contains a camera simulator that shows the green tracking box and red cross hair target based on the camera T packet.

Though I haven't gotten around to it yet, I am working on an "fake" OI simulator that will allow me to control the robot from the computer:D

It was used somewhat for debugging but the robots were never really done...

Bomberofdoom 24-02-2007 06:50

Re: Programming tricks (and former trade secrets)
 
Things not implemented in team 2230's robot code:
We wanted to make a very simplified control system with the gyro in order to make the robot move from the drivers prespective. I.E: You need your robot to go left from your position. You turn the joystick to the left, the robot will turn left untill it reaches it's angle and will continue in that direction as long as the joystick is held in that direction. New joystick direction? The robot will stop and turn to the new direction and continue.
Of course, that was not implemented, because we lost our gyro a single day after we received it(about 2 weeks before the shipping of the robot instead of 4).

Things implemented

- Automated arm levels. Every push of the joystick's wheel in the certian direction will raise the arm of the robot to the direction and certain level we defined(1st level, the chute, 2nd level etc...).
- Automated platform lowering and manual raising. The platforms for the robots are automaticly lowered. With a special saftey press-code on the joystick, only after the driver is sure he wants to lower his platforms in the place he is he will lower it. At the end of the game, after the saftey inspectors go over the robot making sure the raising of the platforms won't damage anything, the platforms are raised slowly and manualy.
-Automatic jack system. With the help of the trusty acclerometer, we've been able to make sure all jacks attempt to level eachother while progressing to the height while trying to keep all motors at thier max speed in order to maintain stabilty.

Things hoping to be implmented
- A complete autonomous mode. In the "practice" day, we'll try to get values from the arena and define the certain values we need to make an autonomous mode that will use the values of the position the robot starts, the number of lights it should look for and which way to go in order to set the robot in the direction of the defined number of lights.

That's pretty much it. :cool:

Jake M 24-02-2007 15:48

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

Originally Posted by JimGRobot (Post 585198)
Great thread, there are many good ideas out there.

We talked about the remote PROG button ourselves, but never implemented it.

One thing we did for the drivers was create an "Auto Trim" button for the joysticks. You use the regular trim adjust to get them close, then push the button. This saves the current joystick positions and subtracts those values from all future readings. This is built into a joystick "class" that is part of a code library that will be released to the world this spring.

We have an automatic scoring button, as others have mentioned, and separate buttons for all of the arm preset positions. We used a potentiometer for arm position feedback, and it works well.

One other cool thing is a micro-switch on the tube gripper to automatically close the jaws with a tube is present. This makes tube pickup very quick and easy.

We wired a bunch of momentary switches across a string of resistors connected to a single joystick input on the OI, instead of using 10 digital input bits. I will be making some PC boards over summer so others can do this very easily. The code does a little math to convert the input value into a switch number; this is built into another library class.

I guess that's all for now...
Jim

Speaking of trim, I was considering how to make a circuit that would give some kind of feedback (LED perhaps) when the voltage off of the joystick pots themselves corresponds to about 127 (about 1.82 volts, if I remember correctly) That way you could know how good your trim is, without even needing to use dashboard, or printfs. I was going to use the two weeks before competiton, and after shipping to do this. Then we learned that we had to ship the OI Board along with the robot, and all of our other joysticks are faulty in some way or another.

Cuog 24-02-2007 16:12

Re: Programming tricks (and former trade secrets)
 
You can use the LEDs on the OI and have them turn on when the joystick input is where you want it.(for info on this look at the bottom of default_routine() in the default code

Dave Flowerday 24-02-2007 16:26

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

Originally Posted by JimGRobot (Post 585374)
If the joystick value is 130, and you press the auto trim button, the offset will be 3. When this value is subtracted from 130, you get the null value of 127. When the joystick value is 200, you get 197, and 100 you get 97.

Be very careful with this. By doing this you're effectively overriding a safety feature built into the OI by IFI. That feature sets the OI outputs to 127 when the joystick is unplugged. If you have your "auto trim" set to subtract 10 (or whatever), then when a stick gets unplugged your robot will start driving.

Jake M 24-02-2007 17:07

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

Originally Posted by Cuog (Post 585663)
You can use the LEDs on the OI and have them turn on when the joystick input is where you want it.(for info on this look at the bottom of default_routine() in the default code

Very true, but my whole reasoning for making such a circuit is not simply to let us see when the joysticks are trimmed or aren't, it's to let us do so without using up other OI features (such as the LEDs) which we could use for other feedback, concerning the actual driving of the robot. We can only acesss 8 of them, through the joystick ports and we could easily find 8 other uses for an LED.

The Lucas 24-02-2007 17:08

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

Originally Posted by Cuog (Post 585663)
You can use the LEDs on the OI and have them turn on when the joystick input is where you want it.(for info on this look at the bottom of default_routine() in the default code

Quote:

Originally Posted by Jake M (Post 585701)
Very true, but my whole reasoning for making such a circuit is not simply to let us see when the joysticks are trimmed or aren't, it's to let us do so without using up other OI features (such as the LEDs) which we could use for other feedback, concerning the actual driving of the robot. We can only acesss 8 of them, through the joystick ports and we could easily find 8 other uses for an LED.

I wrote a routine like this years ago and it goes into the code for both my teams every year. Here is what I use: ( I just added some defines for portability)

Code:

#define CALAXIS1        p1_y
#define CALAXIS2        p1_x
#define CALAXIS3        p3_y
#define CALAXIS4        p3_x


if (disabled_mode)
{
        //when joysticks are calibrated
        //all 8 LEDs will be on
        Pwm1_green = (CALAXIS1 >= 127);
        Pwm1_red = (CALAXIS1 <= 127);
        Pwm2_green = (CALAXIS2 >= 127);
        Pwm2_red = (CALAXIS2 <= 127);
        Relay1_green = (CALAXIS3 >= 127);
        Relay1_red = (CALAXIS3 <= 127);
        Relay2_green = (CALAXIS4 >= 127);
        Relay2_red = (CALAXIS4 <= 127);
}
else
{
        //whatever you normally do with the LEDs
}

It only uses the LEDs while the bot is disabled, since it should be calibrated before enabling. You are free to use the LEDs as you would during the match, just put that code in the else statement. Just make sure your LEDs are set every loop to avoid confusing the drivers with stray lights.

Basically you just have to play with the calibration trimmers until both red and green LEDs are ON for that axis. Might be tough at first but you will get the touch. All 8 LEDs ON = "Calibrated and ready to go". :)

JimGRobot 24-02-2007 21:23

Re: Programming tricks (and former trade secrets)
 
Thanks for the note, this is a very good point...

We see the same behavior whenever we reset the RC.

Fortunately, our offsets are small, so the bot doesn't go nuts.

Thanks,
Jim

Dave K. 26-02-2007 01:34

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

Originally Posted by Alan Anderson (Post 582591)
Anyone else feel like sharing?

Streamlined, non-directional Encoder Tach code and added a ring buffer. This is used with 100 counts per revolution encoders on each wheel and provides good low speed resolution while still allowing the PID loop to compute new values every 26ms.

Some will recognize Kevin's interrupt framework, but everything else is different.

Here's the relevant portion of the interrupt routine:

Code:


volatile unsigned int Tach_Count[NUM_TACH];
unsigned char Old_Port_B = 0xFF;

void InterruptHandlerLow () {

        unsigned char Port_B;
        unsigned char Port_B_Delta;

  // other interrupt handler code removed for clarity.

        else if (INTCON3bits.INT2IF && INTCON3bits.INT2IE) { // encoder 1 interrupt?
                INTCON3bits.INT2IF = 0; // clear the interrupt flag
                Tach_Count[0]++;
        }
        else if (INTCON3bits.INT3IF && INTCON3bits.INT3IE) { // encoder 2 interrupt?
                INTCON3bits.INT3IF = 0; // clear the interrupt flag
                Tach_Count[1]++;
        }
        else if (INTCONbits.RBIF && INTCONbits.RBIE) { // encoder 3-6 interrupt?
                Port_B = PORTB; // remove the "mismatch condition" by reading port b           
                INTCONbits.RBIF = 0; // clear the interrupt flag
                Port_B_Delta = Port_B ^ Old_Port_B; // determine which bits have changed
                Old_Port_B = Port_B; // save a copy of port b for next time around
       
                if(Port_B_Delta & 0x10) { // did external interrupt 3 change state?
                        if (Port_B & 0x10) {
                                Tach_Count[2]++;
                        }
                }
                if(Port_B_Delta & 0x20) { // did external interrupt 4 change state?
                        if (Port_B & 0x20) {
                                Tach_Count[3]++;
                        }
                }
        }
}


Initialization:

Code:

unsigned char i, j;

        for(i=0;i<NUM_TACH;i++) {
                TachHead[i] = 0;
                for(j=0;j<TACHBUFSIZE;j++) {
                        TachBuf[i][j] = 0;
                }       
        }

And here's the foreground tach code that runs in the 26ms loop:

Code:

#define NUM_TACH 4
#define TACHBUFSIZE 4

extern unsigned int Tach_Count[];  // interrupt routine edge counter
unsigned char i, j;
unsigned int TachBuf[NUM_TACH][TACHBUFSIZE];  // ring buffer
unsigned char TachHead[NUM_TACH];  // TachBuf head pointer
unsigned int Tach[NUM_TACH];  // Tach result register.


                        // disable tach interrupts, grab current count, and reset counter

                        INTCON3bits.INT2IE = 0;                // Disable INT2 for tach 1
                        INTCON3bits.INT3IE = 0;                // Disable INT3 for tach 2
                        INTCONbits.RBIE = 0;                // Disable Port B change interrupt for tach 3&4

                        // get current tach values into local var, then reset the counter
                        for (i=0;i<NUM_TACH;i++) {
                                TachBuf[i][TachHead[i]] = Tach_Count[i];        // place current tach count into ring buffer & inc buffer
                                Tach_Count[i] = 0;
                        }

                        INTCON3bits.INT2IE = 1;                // INT2 on
                        INTCON3bits.INT3IE = 1;                // INT3 on
                        INTCONbits.RBIE = 1;                // Port B change interrupt on


                        // sum up the tach counts in ring buffer into Tach[]
                        for (i=0;i<NUM_TACH;i++) {
                                Tach[i] = 0;
                                for(j=0;j<TACHBUFSIZE;j++) {
                                        Tach[i] += TachBuf[i][j];
                                }
                                if (++TachHead[i] >= TACHBUFSIZE) {
                                        TachHead[i] = 0;
                                }
                        }

                        // Tach[] now contains the unsigned wheel speeds


Alan Anderson 26-02-2007 06:55

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

Originally Posted by Dave K. (Post 586460)
Streamlined, non-directional Encoder Tach code and added a ring buffer. This is used with 100 counts per revolution encoders on each wheel and provides good low speed resolution while still allowing the PID loop to compute new values every 26ms.

We did that for the shooter wheel last year, but with a twist. Recognizing that the buffer is essentially a filter that slows down the measurement response, we added the newest value from the buffer multiple times. The resolution stays high, but the sum more quickly represents a change in velocity.

I also came up with an interesting result when I figured how long it took to maintain the ring buffer. With as many as ten entries, it turned out to be faster to move all of the values every time than to index through an array. Array operations are convenient and make for easier coding in many cases, but they can be remarkably slow.

Joohoo 26-02-2007 08:24

Re: Programming tricks (and former trade secrets)
 
we worked on writing a new scripting language for autonomous mode.

so easy to write new logic I had mechanical people writing some stuff.

Dave K. 26-02-2007 13:37

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

Originally Posted by Alan Anderson (Post 586484)
We did that for the shooter wheel last year, but with a twist. Recognizing that the buffer is essentially a filter that slows down the measurement response, we added the newest value from the buffer multiple times. The resolution stays high, but the sum more quickly represents a change in velocity.

I also came up with an interesting result when I figured how long it took to maintain the ring buffer. With as many as ten entries, it turned out to be faster to move all of the values every time than to index through an array. Array operations are convenient and make for easier coding in many cases, but they can be remarkably slow.

I agree that a weighted average approach can help. In this case, to get the resolution we needed, a sample window of about 4*26 (100ms) worked out about right, but only performing the PID calculations at that rate, made the loop somewhat hard to optimize and user response more sluggish.

I don't doubt that individual moves would be faster as it avoids one or more multiply operations to compute the array index.

Although the interrupt routines use an arrayed variable to store the tach counts, the use of an absolute index allows the compiler and linker to resolve this to a fixed memory location at build time.

The overall simplification of Kevin's code by reworking the logic to remove direction sensing as well as the overhead of function calls helps reduce the CPU loading where the impact is the greatest.

My primary point in sharing the idea was to provide a simpler example of how a velocity only interrupt could work, and to introduce the idea of using a sliding window for data values to improve resolution.


I chose to use arrayed variables in the 26ms loop for the tach code as well as all of the remaining PID code just to help with readability and to make it easy to change the size of the ring buffer, or add/delete motors.

Certainly if the CPU didn't have any idle time left, the arrays are one of the first things I'd go after.

Jake M 26-02-2007 23:43

Re: Programming tricks (and former trade secrets)
 
[quote=The Lucas;585702]It only uses the LEDs while the bot is disabled, since it should be calibrated before enabling. You are free to use the LEDs as you would during the match, just put that code in the else statement. Just make sure your LEDs are set every loop to avoid confusing the drivers with stray lights.[quote]

Now, why didn't I think of that? Thanks for the tip.

PhilBot 27-02-2007 10:32

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

Originally Posted by WesleyC (Post 583888)
The code goes something like this:

output = (input * input / 127) * (input > 0) ? 1 : -1;

This is a great piece of math, but when I tried it, it didn't work...
It only served to reinforce my motto "when in doubt, add parenthesis".

It appears that the compiler gives greater precedence to * than it does to ?

So what the code was doing was this:

output = ((input * input / 127) * (input > 0)) ? 1 : -1;

not this:

output = (input * input / 127) * ((input > 0) ? 1 : -1);


As written, the code only returned +/- 1. With parenthesis added as in the second example, the code did what was intended.

The other cool by-product of this code is that it adds in a small dead-band to the joystick. Any offset less than 13 returns a zero after interger math truncation.

Dave K. 27-02-2007 14:02

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

Originally Posted by PhilBot (Post 587085)
This is a great piece of math, but when I tried it, it didn't work...
It only served to reinforce my motto "when in doubt, add parenthesis".

It appears that the compiler gives greater precedence to * than it does to ?

So what the code was doing was this:

output = ((input * input / 127) * (input > 0)) ? 1 : -1;

not this:

output = (input * input / 127) * ((input > 0) ? 1 : -1);

Operator precedence for Multiplicative and Additive instructions is relatively high, whereas the ternary operator is quite low, however the '?' forms a 'sequence point' and considers anything to the left, within the sequence, to be used as the scalar value.

Parenthesis is, of course, the correct way to create the desired association, and when using the ternary operator is a good habit to adopt.

WesleyC 01-03-2007 11:25

Re: Programming tricks (and former trade secrets)
 
Thanks for the notes!

I'm coming from a PHP background--all math is given equal precedence in PHP; you use parenthesis to emphasize certain points to be performed first--also, all expressions are evaluated before math is performed.

Also, one thing you must be careful of when using this particular phrase is that the input variable must either be an int or typecast to an int before performing math. If "input" is a char, the math will overflow the size of the type, creating... shall we say, "undesirable" results. :P

Dave K. 01-03-2007 15:22

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

Originally Posted by WesleyC (Post 588212)
Thanks for the notes!

I'm coming from a PHP background--all math is given equal precedence in PHP; you use parenthesis to emphasize certain points to be performed first--also, all expressions are evaluated before math is performed.

Also, one thing you must be careful of when using this particular phrase is that the input variable must either be an int or typecast to an int before performing math. If "input" is a char, the math will overflow the size of the type, creating... shall we say, "undesirable" results. :P

Without disagreeing with the comment about type casting...

If the compiler is really standards compliant, objects or expressions of rank less than int (such as unsigned char) are converted to int (if int can represent all values of the original type) or unsigned int (otherwise); this is known as integer promotion.

In the case of multiplying two unsigned chars, the the product of two values of unsigned type will be reduced according to the range of values for that type.

This is an area where compiler's behavior will sometimes vary, especially those targeted towards 8 bit native platforms (such as the PIC18) where math with 8 bit variables is not always evaluated as an integer (which in this case is 16 bits).

Not all compilers correctly perform integer promotion, and I've only run across one that did not behave any better when type casts were applied.

In the case of the PIC18 compiler it does understand integer promotions, however the default behavior is to not do it. The C compiler documentation covers this in section 2.7 (ISO DIVERGENCES).

Snappel328 02-03-2007 23:40

Re: Programming tricks (and former trade secrets)
 
Well, we've got some good things going on. I guess everyone else was either hurrying or something with their programming, because we managed to play quite a lot of Counter-Strike and still have a perfectly functional robot heh.

Qbranch 03-03-2007 12:36

Re: Programming tricks (and former trade secrets)
 
*to the tune of California Dreamin'*

CCPs make me happy... when the skys are grey... when i have the pwm blues... on a winter's day... update rate ga-lore... when the skys are grey-hey.... :cool:

keep on dreamin... and good luck in Rack N' Roll!

(by the way, low freq SDAR, team 1024's pet project, autonomous mode? we'll find out... *hint hint*)

-q

JohnC 09-03-2007 01:07

Re: Programming tricks (and former trade secrets)
 
Our drive code was such that 3/54 teams approached us specifically asking how we get such fine control of our robot.

I know this is a lot of code, and it's not very advanced, but man does it work well.

Code:

int driveScaleFactor = 3;

void Left(int speed) {
  pwm03 = Safe_Values(speed);
}

void Right(int speed) {
  pwm04 = Safe_Values(254-speed);
}

int Safe_Values(int roughValue) {
  int toReturn = roughValue;

  if(toReturn> 254) {
    toReturn = 254;
  } else if(toReturn < 1) {
    toReturn = 1;
  }

  return toReturn;
}

int Scale_Offset(int roughValue, int scaleFactor) {
  int toReturn = roughValue;

  toReturn = ((toReturn-127)/scaleFactor) + 127;

  return toReturn;
}

//// later, in Process_Data_From_Master_uP()

if(p1_sw_trig && p2_sw_trig) {
  Left(p1_y);
  Right(p2_y);
} else {
  Left(Scale_Offset(p1_y,driveScaleFactor));
  Right(Scale_Offset(p2_y,driveScaleFactor));
}

The advantage of having a function to assign pwm values instead of assigning them inline, is, obviously, you can add other functions like the one I did. Let me know if you use this!

I will eventually post code that uses PD control with encoders to drive in a straight line autonomously.

AustinSchuh 09-03-2007 01:38

Re: Programming tricks (and former trade secrets)
 
We wrote our own sin() function.
It takes a degree measure in in "funnys", where there are 40 "funnys" per circle. We then directly map that angle to the table after correcting the sign of the number. We are using this to implement a feed forward controller with our PID controller. We will be adding in a function on Thursday that will take 2 angles and some other various data in from our double jointed arm, and output the torque that is being experienced on the "shoulder" joint and implement that into the PID controller for the shoulder.

I also wrote our drive code so that the steering wheel we use specifies the difference in motor power between the left and the right wheels. This even works when the throttle is full forward. The code calculates it out so that even though it would like to run one motor at over full power, it lowers the other motor's power further instead to retain this difference in power.

I like the reduced sensitivity code that I saw earlier. I think that I am going to implement a version of that using one of the buttons on our steering wheel to turn the mode on or off.

Our sin(x) function:
Code:

static const int8 sin_table[] = {0, 20, 39, 58, 75, 90, 103, 113, 121, 125, 127};
int sin(int x) {
        char negate = 0;
        int result;

        // sin(-x) = -sin(x)
        if (x < 0) {
                x = -x;
                negate = 1;
        }

        // sin(x) = sin(x - 360 degrees)
        while (x >= 40) x -= 40;

        if (x > 30) {
                x = 40 - x;
                negate = !negate;
        } else if (x > 20) {
                x = x - 20;
                negate = !negate;
        } else if (x > 10) {
                x = 20 - x;
        }
        result = (int) sin_table[x];
        if (negate) result = -result;
        return result;
}


JonA 09-03-2007 10:40

Re: Programming tricks (and former trade secrets)
 
Pro-Tip: Don't use 255 as a full forward value.
With stop at 127, there are 127 effective negative numbers (0-126) and 128 effective positive numbers (128-255). Enforcing 254 as the maximum forward value allows you to easily change the sign of the number (254-n) by using the 8 bit number circle.

Pro-Tip: Use object oriented design. (And implement it that way)
Objects allow you to divide up your code based on things in real life instead of what the processor can do. It also is the easiest way to do abstraction, encapsulation and modularity in C. Even though the language (C) does not natively support objects, there are many ways to implement objects. My preferred way is to define a typedef structure with all of the members/attributes in the class and then implement functions that are prefixed with the class name that take in a pointer to the class structure. To get encapsulation put public function definitions in the header file and private function definitions in the c file.

Snappel328 09-03-2007 13:39

Re: Programming tricks (and former trade secrets)
 
Well, this year we made whole different .c and .h files for every part on our robot.
Arm.c
Grabber.c
Lifter.c
Drive.c

I don't know how obvious this is to anyone else, but it got quite confusing last year when we kept typing all our code in userroutines.c

JJG13 09-03-2007 16:14

Re: Programming tricks (and former trade secrets)
 
Blame it on hardware.

Redneck 12-03-2007 00:04

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

Originally Posted by JJG13 (Post 593891)
Blame it on hardware.

Quite the tempting idea when, on my team at least, anyone who's not involved with programming immediately says "Blame the programmers" when something doesn't work...;)


One of the cool things my team did this year was use VNC when teaching the rookie programmers. As one of the experienced programmers worked on the code, the rookies could follow along by connecting to the computer remotely.

Roger 14-03-2007 07:37

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

Quite the tempting idea when, on my team at least, anyone who's not involved with programming immediately says "Blame the programmers" when something doesn't work...
The shop was riding us pretty hard, even on stuff that was obviously their problem. I think they slowed down (but not totally stopped) when I started replying "I'll get right on it."....

"Aw gee, the arm broke again -- must be a programming error."
"I'll get right on it!"
"Pneumatics tube popped out -- programming error!"
"I'll get right on it!"

They do not want me touching anything but a keyboard....

They also slowed down when I got their #@$$^% robot to actually work :cool:

♥♣♠♪ 20-03-2007 17:27

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 and two functions: abstractIn() and abstractOut().
The global variables are things like driveLeft, driveRight, joyL, joyR, etc.
Our abstraction code takes renaming it one step farther. Rather than using the 0-255 scale where 127 means stop, we shift it down 128 (signed char, rather than unsigned), and we also invert motors where it makes sense. (one side of the drivetrain, any appendages where the motor is 'backwards')

This helps make our code MUCH more readable and configurable, and makes algorithms a bit simpler.

Another trick we did this year was one big state machine for teleoperated mode. In the past, our robot has been nothing more than a glorified remote control car. This year, our robot knows what it's supposed to be doing, with a set of states for each objective, and so the drivers are freed to think more about the game, rather than the robot.

Our code did the abstractions, but to the point where we had #define unsign(x) ((x)-127-((x)==255))
We #defined all the pwms to things like pwmL, pwmR, pwmA, etc.
The worst was when we needed to use two motors to control the wheels on the left and right. pwmL is #defined as (pwm05=pwm06)

Adamskiy 20-03-2007 22:11

Re: Programming tricks (and former trade secrets)
 
We did similar to the above quote of meatmanek, but scaled it from -100 to +100....lost some resolution, but it made calculations much more simple. And although we had a tank drive, we set the left thumbstick on our Xbox controller to the throttle, and the right thumbstick controlled steering. We did that after picking drivers, as one of them loves Halo and figured it would be more easy for him to control.

For our elevator, the motor that acted as the winch was a small CIM with a BaneBots gearhead/encoder on it, so we used the encoder to have set rack positions (high/med/low) that would be assigned to a single button on the Guitar Hero controller. We then had a limit switch at the bottom (load position) that would reset the encoder count to 0 to account for slight variations that would occur....obviously not the best method, but it was accurate to about an inch, so good enough since we lower the tube onto the rack to score.

meatmanek 20-03-2007 22:31

Re: Programming tricks (and former trade secrets)
 
I also wrote sscanf but haven't gotten a chance to use it yet. My stupid state machine based input code works well enough, so I haven't bothered to change the code to use sscanf yet.

It compiles, and it works when I test it on my linux box. Only has %c, %u, and %d at the moment, but it should be pretty easy for someone to add other stuff to it.

http://meatmanek.net/scanf.c

Eldarion 20-03-2007 22:33

Re: Programming tricks (and former trade secrets)
 
I created this: http://www.falconir.com/products.php

After calibrating once at our home practice field, it was literally "set it and forget it". We did not have to recalibrate once at either of the two regionals! It even handled a dim target light on the practice field.

Then we changed our arms out and autonomous broke permanently :(

JBotAlan 20-03-2007 23:07

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

Originally Posted by Eldarion (Post 602106)
After calibrating once at our home practice field, it was literally "set it and forget it". We did not have to recalibrate once at either of the two regionals! It even handled a dim target light on the practice field.

Whoaa, cool! I do wish that this was open-source, or at least a few more details were included on the website...but good job! I did consider briefly a PC with a webcam onboard--that would be much easier to deal with than a CMUcam...but I'm also starting to lose confidence in the camera module. The lens seems to distort the image horribly, and it's not a defect because it does it on 2 cameras. I don't know as if I'll ever use the CMUcam. Too complicated...

My little bit: stay SIMPLE! And make sure the basics are done first! Autonomous mode does no good if the arm control module doesn't work...I should know, I just got it done yesterday during our last build window before Waterloo. I know I can do much better next year.

JBot

Mike 20-03-2007 23:13

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

Originally Posted by Eldarion (Post 602106)
I created this: http://www.falconir.com/products.php

After calibrating once at our home practice field, it was literally "set it and forget it". We did not have to recalibrate once at either of the two regionals! It even handled a dim target light on the practice field.

Then we changed our arms out and autonomous broke permanently :(

Looks cool, but have you checked out your main open-source competition: the avrcam

Eldarion 20-03-2007 23:15

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

Originally Posted by JBotAlan (Post 602134)
Whoaa, cool! I do wish that this was open-source, or at least a few more details were included on the website...but good job!

If you want to, you can download the manual from the website. It offers some insight into the basic algorithms involved (adaptive image segmentation is the main one). Another featue is that the system natively uses 320x240 images, and scales the centroids down by two for output purposes. I will probably put a little more detail on the main products page; thanks for the suggestion! :)

I did not make this open source as I have been working on the algorithms for the past 2 1/2 years, and would like to make a little bit of profit so that I can fund my other vision systems research. It is hard to continue researching with no funds available to test ideas with! :) Besides, it is written for an FPGA, an FPGA which is pretty much filled up by the code. (1 million logic cells, all in use! :ahh: )

The OV7620 camera module itself is not a bad module for this kind of work. I have yet to see this distortion you speak of, and I have had the oppertunity to work with 6 different OV7620 modules. Out of curiosity, did you plug both of them (one at a time, of course :) ) into the same CMUCam board or different CMUCam boards when you noticed the distortion?

Eldarion 20-03-2007 23:20

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

Originally Posted by Mike (Post 602141)
Looks cool, but have you checked out your main open-source competition: the avrcam

That's interesting, but I think it will be hard to beat the raw processing power of a dedicated FPGA. The FPGA allows me to use 320x240 resolution, over 6 times the resolution of the CMUCam or the avrcam. It does sacrifice speed a little bit, runnig at a little over 6 FPS, but I have found that to be more than adequate. The increased resolution allowed me to stably track the lights from the home zone, (and far beyond it, actually :) ).

It is hard to go up against an open-source project, though...

Matt Krass 20-03-2007 23:35

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

Originally Posted by Eldarion (Post 602146)
If you want to, you can download the manual from the website. It offers some insight into the basic algorithms involved (adaptive image segmentation is the main one). Another featue is that the system natively uses 320x240 images, and scales the centroids down by two for output purposes. I will probably put a little more detail on the main products page; thanks for the suggestion! :)

I did not make this open source as I have been working on the algorithms for the past 2 1/2 years, and would like to make a little bit of profit so that I can fund my other vision systems research. It is hard to continue researching with no funds available to test ideas with! :) Besides, it is written for an FPGA, an FPGA which is pretty much filled up by the code. (1 million logic cells, all in use! :ahh: )

The OV7620 camera module itself is not a bad module for this kind of work. I have yet to see this distortion you speak of, and I have had the oppertunity to work with 6 different OV7620 modules. Out of curiosity, did you plug both of them (one at a time, of course :) ) into the same CMUCam board or different CMUCam boards when you noticed the distortion?

I don't mean to be rude, but I took a look at the code you provide and I must say, it's terribly disorganized and disheveled. I find it hard to navigate and poorly commented, it took me and a friend several minutes to figure out what is apparently a timeout reset of the cameras. Your project looks promising, but I think you should polish it up quite a bit more before charging such a hefty sum for it. And I'm not certain but is that full blown development board depicted in your picture actually entirely necessary? Seems like you could design your own hardware to house the device and save some money in removal of unnecessary parts.

Again I don't mean to be rude, and if I'd made a mistake in my conclusions, please forgive me, your site is somewhat sparse on details, I'll happily stand corrected if I am wrong.

Vashts6583 20-03-2007 23:50

Re: Programming tricks (and former trade secrets)
 
We have an accerlerating, exponentiating drive code, which means, if you slam the joysticks from center to full forward, the robot, accelerates at an increasing speed.

For controls, we have our "conditional limit" system. operator moves arm, then holds a button, which corresponds to a spider, then stops at that limit and can't move. It can go past all the other limits (except top and bottom of course), but its very convenient. Also, our limit switches were velcro-ed on, to allow for mobility and last-minute-changability.

What else did I do this year? OH YEAH! Those LEDs on the OI....I made them all have a purpose. switch 1/2 - drive forward/back for each side. switch 3/4 - arm up/down and max limit/min limit. relay 1->3 - 3 levels of spiders. Fun times.

Eldarion 20-03-2007 23:55

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

Originally Posted by Matt Krass (Post 602161)
I don't mean to be rude, but I took a look at the code you provide and I must say, it's terribly disorganized and disheveled. I find it hard to navigate and poorly commented, it took me and a friend several minutes to figure out what is apparently a timeout reset of the cameras. Your project looks promising, but I think you should polish it up quite a bit more before charging such a hefty sum for it. And I'm not certain but is that full blown development board depicted in your picture actually entirely necessary? Seems like you could design your own hardware to house the device and save some money in removal of unnecessary parts.

Again I don't mean to be rude, and if I'd made a mistake in my conclusions, please forgive me, your site is somewhat sparse on details, I'll happily stand corrected if I am wrong.

Very good points. I did just throw together the example code for a temporary example, as I do not have an RC with me right now and so I could not clean up and test the code. I will pull it until I can clean it up and test it.

Would someone be able to direct me to a place that can handle the manufacturing and assembly of circuit boards that can handle BGA devices in small runs? At this point, I have almost zero capital, so I cannot invest in a run of 2000 boards and hope to sell them later.

I kind of rushed this product out here to "test the waters" and see if there would be any interest in a system like this. The actual system itself is very mature and stable, I am having some difficulty with the peripheral stuff, like sample IFI drivers. If you click on the "Add to Cart" link, you will see that I am not actually offering this for sale to the general public yet. (I should probably make that more clear.) What I would like is for one or two teams to be willing to test this, make sure that the manual is clear and such, that I am not overpromising, etc. before making this generally available and investing in a new board design.

You were not rude; this is my first time attempting to bring something to market and as such it is a learning experience for me. I appreciate your criticism and feel free to poke as many holes in my logic above as necessary.

Maybe we could discuss this further via the PM system so as not to tie up this thread?

Thanks again. :)


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