340 likes | 357 Views
Join us for an interactive workshop on software development, math concepts, timers, finite state machine, controls, and debugging techniques. Learn coding, testing, and debugging skills to enhance your programming knowledge.
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