340 likes | 354 Views
Intermediate Programming Workshop. November 11, 2006 Hauppauge High School SPBLI - FIRST. Simona Doboli Assistant Professor Computer Science Department Hosftra University Simona.Doboli@hofstra.edu. Mark McLeod Advisor Team 358 Hauppauge Northrop Grumman Corp. Mark.McLeod@ngc.com.
E N D
Intermediate Programming Workshop November 11, 2006 Hauppauge High School SPBLI - FIRST Simona Doboli Assistant Professor Computer Science Department Hosftra University Simona.Doboli@hofstra.edu Mark McLeod Advisor Team 358 Hauppauge Northrop Grumman Corp. Mark.McLeod@ngc.com
Agenda • Software Development • Integer or Fractional Math • Timers 101 • Finite State Machine • More Controls • Debugging Techniques • MPLAB Simulator • Wrap-up • References
Software Development • Decide on Features - What will it do? • Plan Controls for OI & Robot • joysticks, switches, sensors • Structured Programming • Design Control Algorithms • Code It • Test/Debug • Small modules before full operation • Try it on a robot up on blocks • Test on the final robot in game conditions
Integer or Fractional Math • Can Convert to use 0 as Neutral (normal math) • Speed of Computation (char, int, long, float) • Signed vs. Unsigned • Critical Order of Operation
Multiplication Operation Max Cycles 8 X 8 Unsigned 1 cycle 8 X 8 Signed 6 cycles 16 X 16 Unsigned 28 cycles 16 X 16 Signed 40 cycles 1 cycle = 40 MHz
Common Bugs • Variable Overflow & Typecasting Symptoms: motors suddenly go from full forward to full reverse • x = 255 * 2 / 4; // (incorrect) • x = (int) 255 * 2 / 4; // (correct) • Order of Operations - Better accuracy correct incorrect • x = 10 * 15/10 vs. x = 15/10 * 10 • x = x * 5/10 vs. x *= 5/10
Timers 101 • What is an “Interrupt”? What is Polling? • We have 5 timers • Each timer “tick” is 10-7 seconds (10 MHz) • Prescale/Postscale/Offset • time elapsed = 10-7 * prescale * postscale * # ticks • Sample Uses: • Measuring the time your code takes • Time-based Autonomous • Actions that require precise timing (e.g., gyro) • Where?: • user_routines.c in User_Initialization • user_routines_fast.c in InterruptHandlerLow
We Interrupt Your Regularly Scheduled Code User Initialization Setup Interrupt Radio packet ? NO YES Stop Everything Driver Routine Handle Timer Overflow Interrupt Auto Mode ? NO YES User Autonomous
Initialize the Timer #include <timers.h> // In user_routines.c in User_Initialization OpenTimer4(TIMER_INT_ON & T4_PS_1_16 & T4_POST_1_10); /* Preload timer to overflow after 4ms */ WriteTimer4(6);
Process the Timer Interrupt // In user_routines_fast.c in InterruptHandlerLow volatile unsigned long Clockms; // millisecond clock if (PIR3bits.TMR4IF) /* TIMER 4 INTERRUPT */ { PIR3bits.TMR4IF = 0; /* Clear Timer interrupt flag */ WriteTimer4(6); /* Reset Timer to overflow at 4ms */ Clockms += 4; /* milliseconds */ }
Timer ExampleLiquid Crystal Display (LCD) • Serial Communication • Digital output (not serial port) is used to transmits • Interrupt timer to send each bit • State machine for Start/Data/Stop sequence • Structure • High-Level: LCD_Samples.c (send Team #) • Mid-Level: write_utilities.c (send values) • Low-Level: Serial_Comm.c (send bit)
LCD – Code • Setup Timer for 240 characters/sec. (2400 baud) OpenTimer4(TIMER_INT_ON & T4_PS_1_16 & T4_POST_1_4 ); PR4 = 64; // Timer increments to this value then resets • Process Interrupt if (PIR3bits.TMR4IF) // timer 4 interrupt { PIR3bits.TMR4IF = 0; // clear the timer interrupt flag Write_Bit(); // To send the next bit of data & reset timer }
tf Forward No Action Collision Collision tr tb Rotate BackUp Finite State Machine (FSM) FSM for collision recovery
#define NOACTION = 0; #define BACKUP = 1; #define ROTATE = 2; #define FORWARD = 3; int state = 0; // global variables int tb = 10, tr = 5, tf = 7; void MoveAndRecover(void) { if (state == NOACTION) { if (collision()) { StartTimer(); state = BACKUP; } } else if (state == BACKUP) { move(-maxLeft, -maxRight); if (TimerIsPast(tb) ) { StartTimer(); state = ROTATE; } } else if (state = ROTATE) { move (maxLeft, -maxRight); if (TImerIsPast(tr)) { StartTimer(); state = FORWARD; } FSM Program
else if (state == FORWARD){ move(maxLeft, maxRight); if (collision()) { StartTimer(); state = BACKUP; } else if (TimerIsPast(tf)) { ResetTimer(); state = NOACTION; } } } // end MoveAndRecover(); void main(void) { state = NOACTION; move(maxLeft, maxRight); //forward while(1) { MoveAndRecover(); } } FSM Program
More Controls • Power Curves, e.g., • Deadbands • Software • Hardware (Victor Speed Controller ~ 117 to 137 ) • Joystick may have a limited range, e.g., 19 to 245 • Prevent instant full forward to full reverse
Joystick Lookup Table const rom unsigned char Joystick_Curve[129] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 127}; unsigned char Smooth_Joystick (unsigned char joy1) { unsigned char newvalue; if (joy1 >= 127) // Forward { newvalue = Joystick_Curve[joy1– 127]; // range is now 0-128 } else if (joy1 < 127) // Backward { newvalue = Joystick_Curve[127 - joy1]; // mirror curve for forward direction } return(newvalue+127); }
Potentiometer Position Control – Make Your Own Servo – // Map the joystick position (0-255) to a pot value (270-620) position = (long)620-270; // Get the range of pot motion position = ((position * PWM_in4) / 255) + 270; // Map pot to joystick #define DEADBAND 7 if (position < (potvalue - DEADBAND)) { pwm03 = 97; // Reverse } else if (position > (potvalue + DEADBAND)) { pwm03 = 157; // Forward } else { pwm03=127; // Stop }
Making a Button Toggle static char BallToggle=0; relay2_rev = 0; if ( !p1_sw_trig ) // Has the driver released the trigger? { BallToggle= 1; } if ( p1_sw_trig & BallToggle ) // Has driver pulled the trigger? { relay2_fwd = !relay2_fwd; // Pneumatic solenoid BallToggle= 0; }
Debugging Techniques • Printf, Printf, Printf • Look to be sure it’s really doing what you expect and not just happening to work • You must first debug your printf’s, e.g. Do the results look reasonable? • The Trouble with printf • Prints char and int fine (%d) • Prints unsigned char (%c) and unsigned int (%u) • DOES NOT print long or float directly • Must typecast
Special Printing • Printing Long Values long lx=123456; char buffer[80]; ultoa(lx, buffer); printf("ifi_printBufr=%s\r", buffer); • Printing Float Values #define ACCURACY 1000 // How many decimal places are important float f; int i, i2; // Might need to be longs if you have a lot of significant digits f = 245.56; /* Print float value */ i = (int) f; i2 = (int) ((f-i)*ACCURACY); printf("f = %d.%d \r", i, i2); //e.g., f = 245.559 Alternate code: printf(“%d.%d”, (x>>8), ((x) & 0x00ff) >> 8) );
Using MLAB Simulator • Select and set the simulator Debugger > Select Tool > MPLAB SIM Debugger > Settings > UART1 I/O: • Enable UART1 I/O • Rewind Input and Window
MPLAB Simulator • Watch Window: • to follow the value of a variable or a register. • View > Watch • Add a variable (after program builds successfully): • Select variable from program code and drag it to the Symbol Name field
MPLAB Simulator • Compute the time it takes for a part of the code to execute. • Select the correct frequency of the processor clock: • Debugger > Settings > OSC/Trace • Use Stopwatch: • Debugger > Stopwatch • Set breakpoints between the piece of code you want to measure
MPLAB Simulator • Add breakpoint: right click on the line of code you want to put the breakpoint and select: Set Breakpoint • Click Run: It will execute the program until the first breakpoint. • Click Run again: It will execute the program until the second breakpoint. • So on….
MPLAB Simulator – An Example • Define a function: void delay(unsigned int d) { unsigned int i = 0; for (; i < d; i++) ; } • Put two breakpoints around it.
MPLAB Simulator • Processor clock frequency: f = 20 MHZ • Duration of 1 Clock Cycle: CC= 1/f = 50 nsec • Before calling delay function: • Stop Watch shows: C1 = 35 cycles. • After calling delay function delay(10): • Stop Watch shows: C2 = 284 cycles. • Time passed: • delay(10) = (C2- C1) *4 *CC = 49.8 msec
Wrap Up • Suggested Projects • References • Online • Microchip C Compiler • Books
Suggested Projects • Autonomous program based on a Finite State Machine • Potentiometer to position an arm
References • Programming Quick Start http://team358.org/files/programming/2006ProgrammingQuickStart.pdf • FIRST RC Reference Guide http://www.ifirobotics.com/docs/rc-ref-guide-6-13-2006.pdf • FIRST OI Reference Guide http://www.ifirobotics.com/docs/oi-ref-guide-11-21-05.pdf • Programming forum www.chiefdelphi.com/forums
Microchip C Compiler Reference Documents • MPLAB C18 Libraries – printf, timers • MPLAB IDE User Guide – basic tutorial • MPLAB C18 Getting Started – directory structure, flow, installation options, how-to create a project
Reference Books • Practical C Programming by Steve Oualine • C For Dummies, Volume One & Two • C Programming - A Modern Approach - K N King • The C Programming Language (2nd Edition)-Kernighan & Ritchie • The C Answer Book - Kernighan & Ritchie • Mastering Algorithms with C by Kyle Loudon
Presentation Slides at: www.cs.hofstra.edu/~sdoboli or Team358.org Questions/Help please email us. Simona.Doboli@hofstra.edu Mark.McLeod@ngc.com