What is your favorite software tool? This post describes some of the tried and true software tools that I have found useful. I would love to hear from you about tools you find useful. Please put a comment at the bottom of this post with a description or a pointer to tools you find useful.
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.