|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
|
|
Thread Tools |
Rating:
|
Display Modes |
|
|
|
#1
|
|||||
|
|||||
|
Re: Programming tricks (and former trade secrets)
Quote:
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. ![]() |
|
#2
|
|||||
|
|||||
|
Re: Programming tricks (and former trade secrets)
Quote:
|
|
#3
|
|||||
|
|||||
|
Re: Programming tricks (and former trade secrets)
Quote:
).It is hard to go up against an open-source project, though... |
|
#4
|
|||
|
|||
|
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 |
|
#5
|
||||
|
||||
|
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
![]() |
|
#6
|
|||
|
|||
|
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 |
|
#7
|
||||
|
||||
|
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 Last edited by dpick1055 : 24-02-2007 at 01:22. |
|
#8
|
|||
|
|||
|
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 |
|
#9
|
||||
|
||||
|
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.
|
|
#10
|
||||
|
||||
|
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 It was used somewhat for debugging but the robots were never really done... Last edited by 6600gt : 24-02-2007 at 03:35. |
|
#11
|
||||
|
||||
|
Re: Programming tricks (and former trade secrets)
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.
|
|
#12
|
|||
|
|||
|
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 |
|
#13
|
||||
|
||||
|
Re: Programming tricks (and former trade secrets)
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;
}
}
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
|
|
#14
|
|||||
|
|||||
|
Re: Programming tricks (and former trade secrets)
Quote:
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. |
|
#15
|
||||
|
||||
|
Re: Programming tricks (and former trade secrets)
Quote:
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. |
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Former FIRST student and mentor dies in a tragic rocket attack in Iraq today. | Munkaboo | General Forum | 48 | 19-04-2005 12:21 |
| Off-season competetions and former teams | Venkatesh | Off-Season Events | 5 | 10-12-2004 17:23 |
| Harry Potter and the Chamber of Secrets | Ryan Dognaux | Chit-Chat | 33 | 01-12-2002 19:57 |
| scouting tips and tricks | Rick | Scouting | 1 | 08-01-2002 00:52 |