We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi. I'm trying to use record serial data from Piezo sensors on arduino. I have good communication over serial port. The processing code is lifted and modified slightly from the excellent "poor mans's oscilloscope" by John Porter (http://www.instructables.com/id/Arduino-Improved-Poor-Mans-Oscilloscope/).
I tried to add a "record button" to write select data to disk, only when the button is pushed. This works great as far a printing in the console, and I guess I could copy and paste from there, but I'd much rather have it work properly. Somewhere I'm messed up with my variable formatting.
The current error is "The method of saveStrings(Strring,String[]) in the type PApplet is not applicable for the arguments (String, String)"
Thanks for any tips.
/*
* Oscilloscope
* Gives a visual rendering of analog pin in realtime.
*
* ---------------- IMPROVEMENTS ------------------
* Updates by John Porter, 2/7/2014
* Added ability to move waveform left or right.
* Added gridlines (bounds and minor).
* Added ability to pause/resume.
* Added ability to measure time.
* General usability improvements.
*
* --------------- ORIGINAL PROJECT ---------------
* This project is part of Accrochages
* See http://accrochages.drone.ws
* (c) 2008 Sofian Audry (info@sofianaudry.com)
* ------------------------------------------------
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// * ------------------ HOT KEYS ------------------
final char T_UP = 'w'; // Translate waveform up
final char T_DOWN = 's'; // down
final char T_LEFT = 'a'; // left
final char T_RIGHT = 'd'; // right
final char Z_IN = 'c'; // Horizontal zoom in
final char Z_OUT = 'z'; // out
final char S_IN = 'e'; // Vertical scale in
final char S_OUT = 'q'; // out
final char MGL_UP = 'r'; // Minor grid lines increase
final char MGL_DOWN = 'f'; // decrease
final char TOG_PAUSE = 'p'; // Toggle pause (unpause resets waveform)
final char RESET_AXIS = ' '; // Reset axis settings
final char MEAS_TIME = 'x'; // Adds and/or highlights vertical bars (time measurement)
final char BAR_LEFT = ','; // Move highlighted vertical bar left (can also mouse click)
final char BAR_RIGHT = '.'; // right
// * ----------------------------------------------
// * --------------- STARTING STATE ---------------
float zoom = 1.0;
float scale = 0.5;
int centerV = 0;
int centerH = 0;
int gridLines = 0;
int com_port = 1; // Index number in Serial.list
// * ----------------------------------------------
// Global vars
import processing.serial.*;
Serial port; // Create object from Serial class
int val; // Data received from the serial port
long valTime;
int mills; // Time data was received
int[] values;
long[] times;
float voltage;
float measTime = 0;
int timeMode = 0;
int[] timeBars = {0, 0};
PFont f;
boolean pause;
boolean canStart = true;
//GUI stuff
int rectX = 50;
int rectY = 400;
int rectW = 100;
int rectH = 50;
String command = "";
String dataReading = "";
String [] dataOutput = {};
StringList test;
//String dataOutput;
// Setup
void setup() {
size(1500, 480);
println(Serial.list());
port = new Serial(this, Serial.list()[2], 9600);
//port = new Serial(this, Serial.list()[com_port], 9600); // Com port specified here
values = new int[width];
times = new long[width];
timeBars[0] = width/3;
timeBars[1] = 2*width/3;
pause = false;
smooth();
f = createFont("Arial", 16, true);
}
// Read value from serial stream
int getValue() {
int value = -1;
while (port.available () >= 3) {
if (port.read() == 0xff) {
value = (port.read() << 8) | (port.read());
}
}
return value;
}
// Get a y-value for the datapoint, varies based on axis settings
int getY(int val) {
return (int)(height/2 -(val-512+centerV)*scale /1023f * (height - 1));
}
/// 1023.0f
// Push the values in the data array
void pushValue(int value) {
for (int i=0; i<width-1; i++)
values[i] = values[i+1];
values[width-1] = value;
}
// Push the timestamps in the time array
void pushTime(long time) {
for (int i=0; i<width-1; i++)
times[i] = times[i+1];
times[width-1] = time;
}
// Draw waveform
void drawLines() {
int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
stroke(255,255,0);
for (int i=0; i<width; i++) {
x1 = round(width - ((width-i) * zoom) + centerH);
y1 = getY(values[i]/10);
if(i > 1)
line(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
}
}
// Draw gridlines (bounds, minor)
void drawGrid() {
// Get scaled values for bounds
int pFive = getY(1023);//1023
int zero = getY(0);
// Draw voltage bounds
stroke(255, 0, 0);
line(0, pFive-1, width, pFive-1);
line(0, zero+1, width, zero+1);
// Add voltage bound text
textFont(f, 10);
fill(255, 0, 0);
text("+5V", 5, pFive+12);
text(" 0V", 5, zero-4);
// Draw minor grid lines
int gridVal = 0;
stroke(75, 75, 75);
for (int i = 0; i < gridLines; i++) {
gridVal = getY(round((i+1.0)*(1023.0 / (gridLines+1.0))));
line(0, gridVal, width, gridVal);
}
// Add minor grid line text
if (gridLines > 0) {
textFont(f, 16);
fill(204, 102, 0);
float scaleVal = truncate(5.0f / (gridLines+1), 3);
text("Grid: " + scaleVal + "V", 1350, height-12);
}
// Print difference between vertical 'time' bars
if (timeMode > 0) {
textFont(f, 16);
fill(204, 102, 0);
int idx0 = round(width + (timeBars[0] - width - centerH)/zoom);
int idx1 = round(width + (timeBars[1] - width - centerH)/zoom);
// Ensure time bars are over a recorded portion of the waveform
if(idx1 < 0 || idx0 < 0 || idx1 > (width-1) || idx0 > (width-1) || times[idx1] == 0 || times[idx0] == 0)
text("Time: N/A", 30, height-12);
else{
float timeDiff = truncate((times[idx1] - times[idx0])/2000000.0,2);
text("Time: " + timeDiff + "ms", 30, height-12);
}
}
}
// Draw vertical 'time bars' (seperate from above for better layering)
void drawVertLines(){
stroke(75, 75, 75);
if (timeMode == 1) {
line(timeBars[1], 0, timeBars[1], height);
stroke(100, 100, 255);
line(timeBars[0], 0, timeBars[0], height);
}
else if (timeMode == 2) {
line(timeBars[0], 0, timeBars[0], height);
stroke(100, 255, 100);
line(timeBars[1], 0, timeBars[1], height);
}
}
// Truncate a floating point number
float truncate(float x, int digits) {
float temp = pow(10.00, digits);
return round( x * temp ) / temp;
}
// When a key is pressed down or held...
void keyPressed() {
switch (key) {
case T_UP: centerV += 10/scale; break; // Move waveform up
case T_DOWN: centerV -= 10/scale; break; // Move waveform down
case T_RIGHT: centerH += 10/scale; break; // Move waveform right
case T_LEFT: centerH -= 10/scale; break; // Move waveform left
case MGL_UP: // Increase minor grid lines
if (gridLines < 49)
gridLines += 1;
break;
case MGL_DOWN: // Decrease minor grid lines
if (gridLines > 0)
gridLines -= 1;
break;
case BAR_LEFT: // Move the time bar left (also mouse click)
if (timeMode == 1 && timeBars[0] > 0)
timeBars[0] -= 1;
else if (timeMode == 2 && timeBars[1] > 0)
timeBars[1] -= 1;
break;
case BAR_RIGHT: // Move the time bar right (also mouse click)
if (timeMode == 1 && timeBars[0] < width-1)
timeBars[0] += 1;
else if (timeMode == 2 && timeBars[1] < width-1)
timeBars[1] += 1;
break;
}
}
// When a key is released...
void keyReleased() {
println(key+": "+(int)key);
switch (key) {
case Z_IN: // Zoom horizontal
zoom *= 2.0f;
if ( (int) (width / zoom) <= 1 )
zoom /= 2.0f;
break;
case Z_OUT: // Zoom horizontal
zoom /= 2.0f;
if (zoom < 1.0f)
zoom *= 2.0f;
break;
case S_IN: scale*=2; break; // Scale vertical
case S_OUT: scale /= 2; break; // Scale vertical
case RESET_AXIS: // Reset all scaling
centerV = 0; centerH = 0;
scale = 0.5; zoom = 1; gridLines = 0;
break;
case MEAS_TIME: timeMode = (timeMode + 1) % 3; break; // Change the vertical bars (off, left bar, right bar)
case TOG_PAUSE: // Toggle waveform pausing
if (pause) {
centerH = 0;
for (int i=0; i<width; i++){
values[i] = 0; // Clear data on resume
times[i] = 0;
}
}
pause = !pause;
}
}
// Use mouse clicks to quickly move vertical bars (if highlighted)
void mousePressed() {
if(timeMode == 1)
timeBars[0] = mouseX;
else if(timeMode == 2)
timeBars[1] = mouseX;
if(buttonOver()){
if(canStart){
port.write("start");
port.write('\n');
} else {
port.write("stop");
port.write('\n');
}
canStart = !canStart;
}
}
// Primary drawing function
void draw()
{
background(0);
drawGrid();
// Get current voltage, time of reading
val = getValue();
valTime = System.nanoTime();
mills= millis();
// If not paused
if (!pause && val != -1) {
// Push value/time onto array
pushValue(val);
pushTime(valTime);
// Print current voltage reading
textFont(f, 16);
fill(204, 102, 0);
//voltage = truncate(val * 0.01 / 1023, 1);
voltage = truncate(val/1023*0.5, 1);
text("Voltage: " + voltage + "V", 1350, 30);
if (canStart) {
command = "REC";
fill(0, 255, 0);
} else {
command = "STOP";
fill(255, 0, 0);
String dataOutput = " "+ val/5 + "," + " "+ valTime + "," + mills;
//dataOutput= str(val), "," , str(valTime);
println(dataOutput);
saveStrings("data/data.txt", dataOutput);
}
noStroke();
rect(rectX, rectY, rectW, rectH);
fill(255);
text(command, rectX + 30, rectY + 30);
}
drawLines();
drawVertLines();
}
boolean buttonOver() {
if (mouseX >= rectX && mouseX <= rectX+rectW &&
mouseY >= rectY && mouseY <= rectY+rectH) {
return true;
} else {
return false;
}
}
Answers
Perhaps splitTokens()? :-?? https://processing.org/reference/splitTokens_.html
saveStrings(dataPath("data.txt"), splitTokens(dataOutput, " ,"));
This helped thanks. Reworked the code to:
It writes the data in csv format, but only one line that is constantly overwritten. Why doesn't it add the data to the file line by line like println?
Function saveStrings() takes two parameters. The first is the name of the file to write to. The second is an Array of Strings to write to that file.
If you write to a file that already exists, the old file is replaced with the new one!
What you could do instead is add all the Strings you want to save together, separated by \n's, then save the Array of Strings created by split()ing that string:
I see what you mean, but I must have this in the wrong place. I implement this code I get the same result, constantly overwriting the data, which consists of just one string.
I'm currently looking at PrintWriter, but still not successful.
How about using timestamps in order to have separate files organized by time?:
http://forum.processing.org/two/discussion/9963/how-to-save-keyboard-input-as-multiple-txt-files-using-timestamp-in-naming-convention