We have an application where we need to print large amounts of data to a text file, but can’t figure out what we’re doing. We’re trying to save a log of the values sent to the motor controllers (I know 1500 may be a bit excessive, but it’s for a reason). First we made text files “RIGHT” and “LEFT” (and eventually tried “right” and “left”) and added them to our project (screenshot attached). We considered comma separated value data in one text file on two separate lines, but two separate text files seemed easier to use. This is the code we’re using:
//imported #include <fstream>
//leftdrive, rightdrive, and myrobot(leftdrive, rightdrive) are already initilized
int counter;
while (IsOperatorControl())
{
float driverLeftY = driverXbox->GetRawAxis(2);
float driverRightY = driverXbox->GetRawAxis(5);
myRobot->TankDrive(-driverLeftY, driverRightY);
ofstream left;
ofstream right;
left.open ("LEFT.txt");
right.open ("RIGHT.txt");
while (counter <= 1500) //while (samples <= 1500)
{
right << RightDrive->Get() << "," << endl;
left << LeftDrive->Get() << "," << endl;
counter++;
Wait(0.01);
}
left.close();
right.close();
}
When we check the text files, there is no change. Has anyone else tried utilizing text files in their code?
Reading and writing to the cRIO flash memory isn’t really well documented, but you can look in the WPILib source code at the Preferences class. It stores robot preferences in a text file. You can find the code in the Preferences.cpp and Preferences.h files.
The writing is done by a method called WriteTaskRun() that opens the file and writes a bunch of data to it then closes the file.
So we may or may not be able to print data into a text file, but if so, only into the cRIO flash memory? I thought it would be possible to save it to the computer because the data can be made present there as well. Could we still take that data back out of the text file and put it into an array (during autonomous), just as we could if we were programming a computer using fstream?
There’s a file system on the cRIO that uses flash memory storage. We’ve written files over 10 MB. I’m not sure what the available storage is, but it’s definitely enough for your purpose. When you open a file in robot code, you are opening a file on the cRIO file system. We use C stdio, but C++ streams should work too.
You must FTP to the cRIO to retrieve the file (or to delete it once you’re done). We use both the Windows FTP client and a web browser. The FTP URL is “ftp://10.te.am.2/”. If you use the FTP client, connect to the cRIO with “open 10.te.am.2” and then enter username “anonymous” password “anonymous”. (Others may work, but that’s just habit for me and I didn’t try anything else.)
If you want to stream data back to the driver station you just have to be careful about network bandwidth. Sending 2 numbers every 1/100th sec is very low impact, but keep track of these things and disable them unless you need them in a match. Paper cuts will kill you eventually.
Smart dashboard makes streaming data incredibly easy. Replace the stream IO statements in your loop with this:
If that number changes too fast to be understood, go into smart dashboard edit mode and change the number displays to be line plots. There’s no coding required.
Smart dashboard uses WPILib network tables. If you need something fancier you could write a custom network tables client that runs on the driver station. I think smart dashboard will solve your problem though. It also has the advantage of working during a competition match through the FMS. Other solutions may not work in competition and there’s no way I know of to test if something will work with the FMS.
If it utilizes the available ports listed in R59 I can’t imagine why it wouldn’t work. Have you had something designed to use one of those ports not work when connected to the FMS?
So we can write to a text file, but we can’t read it unless we FTP the file, and we need to use the Preferences class to create and access it (or does fstream work, but only writing to the flash memory)? If so, can we still do complex tasks with the data such as reading comma separated values into an array?
Don’t ignore smart dashboard though. I really think it will be better for you to try that first. Smart dashboard is useful for debugging, but can also be used during a competition match to show information on your driver station.
we can’t read it unless we FTP the file
Yes.
we need to use the Preferences class to create and access it
No. You can use standard file I/O routines to open and write to files. We use C stdio which looks like this:
#include <stdio.h>
...
FILE *output = fopen("/3322-output.txt", "w");
if (output) {
fprintf(output, "hello world
");
fclose(output);
}
C++ stream I/O routines should also work, but I haven’t tried. Can you post some working code if you get C++ streams working?
can we still do complex tasks with the data such as reading comma separated values into an array?
Yes.
The cRIO is an independent computer with its own files. The driver station is another independent computer. The cRIO and driver station use a limited network connection to communicate. If you want to share files between them you must copy them by FTP.
The only problem we’ve found using the cRIO file system with C is it will occasionally pause for up to 100ms to write data to permanent storage (flash storage). The C stdio routines I showed above buffer writes in memory. When the buffer fills up, it has to be written to permanent storage and that takes a long time.
Using ofstream is fine… but one thing. When you create or open ofstream objects, the file is cleared out. If you want to keep a running log, do this so that you only create the objects once.
//imported #include <fstream>
//leftdrive, rightdrive, and myrobot(leftdrive, rightdrive) are already initilized
int counter;
ofstream left;
ofstream right;
left.open ("LEFT.txt");
right.open ("RIGHT.txt");
while (IsOperatorControl())
{
float driverLeftY = driverXbox->GetRawAxis(2);
float driverRightY = driverXbox->GetRawAxis(5);
myRobot->TankDrive(-driverLeftY, driverRightY);
while (counter <= 1500) //while (samples <= 1500)
{
right << RightDrive->Get() << "," << endl;
left << LeftDrive->Get() << "," << endl;
counter++;
Wait(0.01);
}
}
left.close();
right.close();
Once you have this, use a FTP program like FileZilla to read off the cRIO flash at 10.xx.yy.2
Thanks everyone! Everything seems to be working perfectly now, and we’re on to the next problem. For some reason, when we try to read the data from the file using getline (which looks fine when we FTP it), we get the error
error: no matching function for call to `getline(std::ifstream&, int&)'
This is the actual code we’re using to read the lines:
if (counter <= 1500)
{
if (Timer::GetPPCTimestamp() >= waitTimeout) //State machine :D
{
//if ((!left.eof())&&(!right.eof()))
//{
rightval = std::getline(right, counter); //name of text file
driverStationLCD->PrintfLine((DriverStationLCD::Line) 0, "%f", rightval);
driverStationLCD->PrintfLine((DriverStationLCD::Line) 1, "%f", counter);
driverStationLCD->UpdateLCD();
counter++;
waitTimeout += 0.01;
//}
}
Is this just a cRIO compatibility problem? We can get very similar code to run properly on a computer.