Print works, trouble with saveStrings

edited April 2015 in Library Questions

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

  • edited April 2015

    Perhaps splitTokens()? :-?? https://processing.org/reference/splitTokens_.html
    saveStrings(dataPath("data.txt"), splitTokens(dataOutput, " ,"));

  • This helped thanks. Reworked the code to:

    } else {
        command = "STOP";
        fill(255, 0, 0);
        String dataOutput = val + "," +  valTime + "," + mills;
        println(dataOutput);
        //saveStrings("data/data.txt", dataOutput);
        saveStrings(dataPath("data.txt"), splitTokens(dataOutput, " ")); //no errors
    

    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:

    String[] lines = { "One.", "Two.", "Three." };
    String result = "";
    for( int i= 0; i < lines.length; i++){
      println(lines[i]);
      result = result + lines[i] + "\n";
    }
    println("###");
    println(result);
    saveStrings("file.txt", result.split("\n"));
    
  • 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.

Sign In or Register to comment.