I have a Processing sketch that receives Serial and writes a csv file. It all worked fine on my old Macbook laptop. Maybe OSX 10.10 or something. I got a new laptop (with an Apple chip) and OSX 12.3 and Processing will not receive serial. The serial stream is coming from an arduino and the data shows up fine in the Arduino Serial monitor. (Yes I closed Arduino before trying it in Processing)
(Serial port also shows up in terminal in ls dev/tty*)
I have downloaded both varieties of Processing 4 beta, and Processing 3.5 and no joy with any installation. At one point I saw 3 entries in the “postln” monitor and then data just stops.
Here’s the whole sketch but I don’t think it’s going to really do any good without an Arduino for troubleshooting. It tried some serial port examples in Processing and no joy for any of them.
Anyone have a M1? I think they call it laptop (Apple chip) and used the Serial Library?
Any known recent problems with the Serial Library?
/*
Saving Values from Arduino to a .csv File Using Processing
*/
import processing.serial.*;
import controlP5.*;
ControlP5 cp5;
int numReadings = 10; // number of lines to be saved in file
int sampleDelay_S = 3; // seconds
int sampleDelay_mS = sampleDelay_S * 1000;
int lastTime = 0;
Serial myPort; //creates a software serial port on which you will listen to Arduino
Table dataTable; //table where we will read in and store values. You can name it something more creative!
int readingCounter = 0; // counts each reading to compare to numReadings.
String fileName;
float velocity = 0;
float windX = 0;
float windY = 0;
int iters = 0;
String temperatureC = "";
String UltraSonicSpeed = "";
String Angle = "";
int angle = 0;
boolean recording = false;
Toggle recordingButton;
// notes appear at the top of the table in the saved file
String notes = "";
StringList notesScript;
int notesIndex = 0;
String textValue = "";
String fullStr="";
void setup()
{
size(900, 700);
println(Serial.list());
myPort = new Serial(this, "/dev/tty.usbserial-AJ03LXML", 9600);
// myPort = new Serial(this, Serial.list()[0], 9600);
// CAUTION: your Arduino port number is probably different! Mine happened to be 1. Use a "handshake" sketch to figure out
// and test which port number your Arduino is talking on. A "handshake" establishes that Arduino and Processing are
// listening/talking on the same port.
// Here's a link to a basic handshake tutorial: https://processing.org/tutorials/overview/
//myPort = new Serial(this, portName, 57600); //set up your port to listen to the serial port
dataTable = new Table();
dataTable.addColumn("id"); //This column stores a unique identifier for each record. We will just count up from 0 - so your first reading will be ID 0, your second will be ID 1, etc.
//the following adds columns for time. You can also add milliseconds. See the Time/Date functions for Processing: https://www.processing.org/reference/
dataTable.addColumn("date");
dataTable.addColumn("time");
//the following are dummy columns for each data value. Add as many columns as you have data values. Customize the names as needed.
//Make sure they are in the same order as the order that Arduino is sending them!
dataTable.addColumn("Wind Vel");
dataTable.addColumn("X Dir");
dataTable.addColumn("Y Dir");
dataTable.addColumn("W_Angle");
dataTable.addColumn("WindSpdUS");
dataTable.addColumn("TempC");
/********* This is a row for adding notes - put notes in the "id" field, between quotes "like this" ********/
TableRow rowZero = dataTable.addRow();
rowZero.setString("id", "");
TableRow newRow = dataTable.addRow();
newRow.setString("id", "");
//record time stamp
newRow.setString("date", "");
newRow.setString("time", "");
//record sensor information. Customize the names so they match your sensor column names.
newRow.setString("Wind Vel", "");
newRow.setString("X Dir", "");//
newRow.setString("Y Dir", "");
newRow.setString("W_Angle", ""); // entered manually in Processing
newRow.setString("WindSpdUS", ""); // entered manually in Processing from ultrasonic data
newRow.setString("TempC", ""); // entered manually in Processing
/********************/
cp5 = new ControlP5(this);
PFont font = createFont("arial", 20);
notesScript = new StringList();
cp5.addTextfield("notesInput")
.setColor(color(255))
.setColorBackground(color(255, 255, 255, 29))
.setColorCursor(color(0))
.setPosition(10, 10)
.setSize(800, 30)
.setFont(createFont("arial", 16))
.setFocus(true)
.setAutoClear(false)
;
cp5.addTextfield("temperatureC")
.setPosition(20, 170)
.setSize(120, 40)
.setFont(createFont("arial", 20))
.setAutoClear(false)
;
cp5.addTextfield("UltraSonic_WindSpeed")
.setPosition(20, 90)
.setSize(120, 40)
.setFont(createFont("arial", 20))
.setAutoClear(false)
;
// parameters : name, default value (float), x, y, width, height
cp5.addSlider("WindAngle")
.setPosition(20, 250)
.setSize(40, 160)
.setRange(0.0, 360.0)
.setNumberOfTickMarks(17)
.setDecimalPrecision(1)
.setFont(createFont("arial", 20))
;
cp5.addBang("clear")
.setPosition(20, 500)
.setSize(80, 40)
.getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER)
;
cp5.addTextfield("Number_Samples") // number of samples to put in file
.setPosition(350, 90)
.setSize(120, 40)
.setFont(createFont("arial", 20))
.setAutoClear(false)
;
recordingButton = cp5.addToggle("recording") // create a toggle (on-off)
.setPosition(350, 250)
.setSize(80, 80)
.setColorForeground(color(50, 50, 50))
.setColorActive(color(255, 20, 0))
.setLabel("")
;
textFont(font);
lastTime = millis();
}
/* Read Serial Port from Arduino and write a file - adds settings from this sketch
only records when "Record" button is pushed in this sketch */
void serialEvent(Serial myPort) {
String val = myPort.readStringUntil('\n'); //The newline separator separates each Arduino loop. We will parse the data by each newline separator.
if (val!= null) { //We have a reading! Record it.
val = trim(val); //gets rid of any whitespace or Unicode nonbreakable space
println(val); //Optional, useful for debugging. If you see this, you know data is being sent. Delete if you like.
// parses the packet from Arduino and places the valeus into the sensorVals array. I am assuming floats.
// Change the data type to match the datatype coming from Arduino.
float sensorVals[] = float(split(val, ','));
velocity = velocity + sensorVals[0];
windX = windX + sensorVals[1];
windY = windY + sensorVals[2];
iters = iters + 1;
if (recording) {
if (millis() - lastTime > sampleDelay_mS) {
lastTime = millis();
velocity = velocity / iters ;
windX = windX / iters ;
windY = windY / iters ;
TableRow newRow = dataTable.addRow(); //add a row for this new reading
newRow.setInt("id", dataTable.lastRowIndex());//record a unique identifier (the row's index)
//record time stamp
newRow.setString("date", month() + "/" + day() + "/" + year());
newRow.setString("time", hour() + ":" + minute() + ":" + second());
//record sensor information. Customize the names so they match your sensor column names.
newRow.setString("Wind Vel", nf(velocity, 0, 3));
newRow.setString("X Dir", nf(windX, 0, 3)); //
newRow.setString("Y Dir", nf(windY, 0, 3));
newRow.setString("W_Angle", Angle);
newRow.setString("WindSpdUS", UltraSonicSpeed);
newRow.setString("TempC", temperatureC);
TableRow row = dataTable.getRow(dataTable.lastRowIndex());
String line = " Line " + row.getString("id") + " of " + str(numReadings) + ": " +
row.getString("Wind Vel") + " " + row.getString("X Dir") + " " + row.getString("Y Dir") + " " + row.getString("W_Angle")
+ " " + row.getString("WindSpdUS") + " " + row.getString("TempC");
println(line);
readingCounter++; //optional, use if you'd like to write your file every numReadings reading cycles
//saves the table as a csv in the same folder as the sketch every numReadings.
if ((readingCounter % numReadings == 0) ) //The % is a modulus, a math operator that signifies remainder after division.
{
fileName = "FlowSense_" + str(month()) + "_" + str(day())+ "_" + str(hour()) + ".csv";
//this filename is of the form year+month+day+readingCounter + str(day())
saveTable(dataTable, fileName);
// exit(); // Stop the program
// set recording button to off
recording = false;
recordingButton.setValue(false);
//Woo! save it to your computer. It is ready for all your spreadsheet dreams.
}
velocity = 0; // reset everything for averages
windX = 0;
windY = 0;
iters = 0;
}
}
}
}
void draw()
{
background(0);
fill(255);
text(UltraSonicSpeed, 190, 118);
text(temperatureC, 190, 198);
text(Angle, 150, 400);
text(numReadings, 480, 120);
text("Enter wind speed and temp C in fields from ultrasonic sensor", 10, 580);
text(" and hit return in each field", 10, 604);
pushMatrix();
if (recording==true) {
//fill(255, 25, 0);
text("Recording", 350, 350);
} else {
// fill(128, 128, 128);
text("Off", 350, 350);
}
popMatrix();
}
void WindAngle(float angleVal) {
Angle = str(angleVal);
text(Angle, 150, 400);
println("Setting angle to "+ Angle);
}
public void clear() {
cp5.get(Textfield.class, "temperatureC").clear();
cp5.get(Textfield.class, "UltraSonic_WindSpeed").clear();
UltraSonicSpeed = "";
temperatureC = "";
}
void controlEvent(ControlEvent theEvent) {
if (theEvent.isAssignableFrom(Textfield.class)) {
println("controlEvent: " + theEvent.getName()+"': "
+theEvent.getStringValue()
);
}
if (theEvent.getName() == "tempC") {
temperatureC = theEvent.getStringValue();
} else if (theEvent.getName() == "UltraSonic_WindSpeed") {
UltraSonicSpeed = theEvent.getStringValue();
} else if (theEvent.getController().getName()=="Angle") {
Angle = (theEvent.getController().getStringValue()) ;
} else if (theEvent.getController().getName()=="Number_Samples") {
numReadings = int(theEvent.getController().getStringValue());
readingCounter = 0; // reset reading counter when desired file size changes
} else if (theEvent.getController().getName()=="notesInput") {
notes = (theEvent.getController().getStringValue());
TableRow row = dataTable.getRow(0);
println(row.getString("id")); // Prints ""
row.setString("id", notes);
}
}
public void input(String theText) {
// automatically receives results from controller input
println("a textfield event for controller 'input' : "+theText);
}