Today we will look at my favorite module, Debug. Of course, setting breakpoints and debugging in Robot C is amazing. Sometimes, however, it is helpful to look at how the program is running using something less intrusive than Robot C debug and more friendly than a print statement. This debug program runs in the background. Results can be viewed in tabular format and as a time-history plot when the robot is reconnected to the PC and Robot C.
#pragma DebuggerWindows("debugstream") // Story - As a software debugger, I want to see a descriptive string and a variable so that I can understand // what my software is doing. // Usage - To use this software, // 1. DebugSkip(4); Print out every 5th value. Use any number you want. The default is 0 (no skips). // 2. Use DebugInt, DebugFloat, or DebugBool to collect the debug information. // 3. Place the DebugPrint(); after all the debugInt calls. (Takes 10ms or less to run). // // The data is output to the debug stream and to a file called "debug.txt" // The data going to the file is limited to 10000 characters. This is about 151 rows with 10 columns. // // Written by David Lempia // #define DBG_MAX_COL 10 string debugColName[10]; string debugValue[10]; int debugI=0; int debugSkip=0; int debugSkipI=0; int iFrameCntDebug=0; short DebugFile; TFileIOResult isOk; int nFileSize=10000; string debugFileName="debug.txt"; // ---------------- Capture integer debug information ---------------------// void DebugInt(const string name, int value){ string tmp; if (debugI < DBG_MAX_COL){ if (iFrameCntDebug==0){ strncat(tmp,name,5); sprintf(debugColName[debugI],"%5s",tmp); } sprintf(debugValue[debugI++],"%5d",value); } return; } // ---------------- Capture float debug information ---------------------// void DebugFloat(const string name, float value){ string tmp; if (debugI < DBG_MAX_COL){ if (iFrameCntDebug==0){ strncat(tmp,name,5); sprintf(debugColName[debugI],"%5s",tmp); } sprintf(debugValue[debugI++],"% 2.2f",value); } return; } // ---------------- Capture boolean debug information ---------------------// void DebugBool(const string name, bool value){ string tmp; if (debugI < DBG_MAX_COL){ if (iFrameCntDebug==0){ strncat(tmp,name,5); sprintf(debugColName[debugI],"%5s",tmp); } if (value==true) debugValue[debugI++]=" T"; else debugValue[debugI++]=" F"; } return; } // Set the number of times the printout is skipped (Default is to print every time) void DebugSkip(int skip){ debugSkip=skip; } // Send the print data to the debug window and the debug file "debug.txt" void DebugPrint(){ char str[70]; string tmp1,tmp2; int i=0; if (debugI>0){// Do not send out Debug info if not needed if (iFrameCntDebug==0){ //writeDebugStream("col size %d", debugI); Delete(debugFileName, isOk); OpenWrite(DebugFile, isOk, debugFileName, nFileSize); strcpy(str,"Frame,"); for (i=0; i < (debugI-1); ++i){ strcat(str,debugColName[i]); strcat(str,","); } strcat(str,debugColName[i]); strcat(str, "\n"); writeDebugStream(str); WriteString(DebugFile, isOk, str); } if (debugSkip < debugSkipI++){ strcpy(str,""); sprintf(str,"%5d,",iFrameCntDebug); for (i=0; i < (debugI-1); ++i){ strcat(str,debugValue[i]); strcat(str,","); } strcat(str,debugValue[i]); strcat(str,"\n"); writeDebugStream(str); WriteString(DebugFile, isOk, str); debugSkipI=0; } iFrameCntDebug++; debugI=0; //Clear the debug buffer } } //#define TEST_DEBUG //------------------------------------------------- #ifdef TEST_DEBUG // Unit Test // [x] Normal test // [x] To many debugInt(3) calls // [x] No calls to debugInt() - No output should happen. // [x] Skip number is right // [x] The name is longer than 5 characters. Should be limited to 5. // [x] Output to file and debug stream match // [x] Test max file size (File output ends without issue when the max file is hit) // [x] Test worst case time. It takes between 3 and 10 ms to output all 10 columns of data. task main(){ int tmp=0; //DebugSkip(2); // ClearTimer(T2); for (int i=0; i < 10; i++){ DebugInt("r1",time1[T2]); DebugInt("r2",time1[T2]); DebugInt("r3",time1[T2]); DebugInt("r4",time1[T2]); DebugInt("r5",time1[T2]); DebugInt("r6",time1[T2]); DebugInt("r7",time1[T2]); DebugInt("r8",time1[T2]); DebugInt("r9",time1[T2]); DebugInt("r10",time1[T2]); DebugInt("r11",time1[T2]); /*DebugInt("1234567",tmp++); DebugFloat("r2",2.5); DebugBool("r3",false);*/ //-----------------Print the debug statements out------------------// DebugPrint(); } } #endif
Correct usage of the debug software requires a minimum of two function calls, a DebugInt(), DebugFloat(), or DebugBool() (i.e. watch functions) to capture the watch information, and a DebugPrint() to send the print information out to the debug window and the debug file. Up to 10 watch variables can be watched at a time.
Use DebugInt, DebugFloat, or DebugBool function calls to watch variables in the software. Be careful to place the function calls in a place where they will be called on every itteration. If the calls are inside an if-then-else and are not called on an itteration, the past value will be printed out.
Place DebugPrint() in a location that is called after all of the watch functions are called. That is all there is to it. Here is the watch window (tabular format) for the tests I ran on a RiseEdge function:
Here is the plot version for the tests I ran on a RiseEdge function:
To plot this file, I copied the file off of the NXT using Robot C the main menu-> Robot -> NXT Brick -> File Management Utility. I then opened the file in MS Excel and used a line plot.
Let me know if you find this function useful.
No comments:
Post a Comment