Трудно сказать, что происходит с массивом, но вы можете добавить параметры к drawAxes()
, которые уберут жесткую связь с dat
и сделают его многократно используемым для других эскизов:
void drawAxes(float x, float y, float z) {
//X - red
stroke(192, 0, 0);
line( 0, 0, 0, x, 0, 0);
//Y - green
stroke(0, 192, 0);
line(0, 0, 0, 0, y, 0);
//Z - blue
stroke(0, 0, 192);
line(0, 0, 0, 0, 0, z);
}
(например, drawAxes(dat[0] * 100, dat[1] * 100, dat[2] * 100);
)
Обновление Я понимаю, что вы имеете в виду: вы хотели бы построить график входящих данных и графика.
Проблема в том, что в данный момент вы храните только один образец, который постоянно обновляется.
Чтобы построить график с несколькими значениями, вам необходимо:
- создать массив для хранения нескольких выборок
- обновить массив (сдвигать старые значения по мере поступления новых)
- перебирать массив и отображать каждое значение
Шаг 1: создать массив [n-samples][3]
2D для хранения входящих данных. Для аргументации давайте сохраним историю из 30 сэмплов:
int sampleDimensions = 3;
// how many samples to record
int numSamples = 30;
// where to store the data
float[][] samples = new float[numSamples][sampleDimensions];
Шаг 2: Обновление сэмплов (смещение старых, добавление новых данных):
// read a new sample x,y,z entry and append it
void updateSamples(float x, float y, float z) {
// shift oldest samples by 1: count backwards from oldest sample to 2nd sample
for (int i = numSamples - 1; i > 0; i--) {
// copy previous sample data: offsetting old data by 1
samples[i][0] = samples[i-1][0];
samples[i][1] = samples[i-1][1];
samples[i][2] = samples[i-1][2];
}
// add newest entry as the first sample (replacing old data)
samples[0][0] = x;
samples[0][1] = y;
samples[0][2] = z;
}
Шаг 3 Итерация по данным и графику:
// render samples on screen with the option to scale the data
void drawSamples(float scale) {
for (int i = 0 ; i < numSamples; i++){
drawAxes(samples[i][0] * scale, samples[i][1] * scale, samples[i][2] * scale);
}
}
Имейте в виду, что это не очень эффективно с точки зрения рендеринга, однако для 30 сэмплов все должно быть хорошо. В конце концов важна разборчивость стиля визуализации.
Если вы хотите упростить визуализацию, вы можете просто визуализировать строку:
void drawSamples(float scale) {
beginShape();
for (int i = 0 ; i < numSamples; i++){
vertex(samples[i][0] * scale, samples[i][1] * scale, samples[i][2] * scale);
}
endShape();
}
Соединение всего этого вместе :
import processing.serial.*;
Serial myPort; //Serial Port
String dataLine; //Input from serial port
PVector a = new PVector(100, 50, 20);
int sampleDimensions = 3;
// how many samples to record
int numSamples = 30;
// where to store the data
float[][] samples = new float[numSamples][sampleDimensions];
// stores a single data sample from serial
float[] sample = new float[sampleDimensions];
// how much to scale data for visualisation
float sampleRenderScale = 100;
void setup() {
size(1024, 720, P3D);
strokeWeight(3);
noFill();
// try to open serial connection: display error otherwise (port missing, or busy (already open in Serial Monitor, etc.))
try {
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);
}catch(Exception e) {
println("error openin serial port: " + Serial.list()[0]);
e.printStackTrace();
}
}
void draw() {
if(myPort != null){
if (myPort.available() > 0){
dataLine = myPort.readStringUntil('\n');
if (dataLine != null) {
println(dataLine);
sample = float(split(dataLine, ",")); //parse comma-separated number string into numbers
println(sample);
if(sample == null || sample.length < 3){
println("parsed less than the expected 3 values:");
return;
}
println();
// add new sample to the list of recorded samples
updateSamples(sample[0], sample[1], sample[2]);
}
}
}
background(250);
drawAxes(sample[0] * sampleRenderScale, sample[1] * sampleRenderScale, sample[2] * sampleRenderScale); //draw original coordinate system
translate(width * 0.5, height * 0.5, 0);
rotateX(map(mouseY, 0, height, -PI, PI));
rotateY(map(mouseX, 0, width, -PI, PI));
drawAxes(sample[0] * sampleRenderScale, sample[1] * sampleRenderScale, sample[2] * sampleRenderScale);
// draw recorded samples
drawSamples(sampleRenderScale);
pushMatrix();
translate(a.x, a.y, a.z); //isolate coordinate system and draw translated A point
popMatrix();
}
// read a new sample x,y,z entry and append it
void updateSamples(float x, float y, float z) {
// shift oldest samples by 1: count backwards from oldest sample to 2nd sample
for (int i = numSamples - 1; i > 0; i--) {
// copy previous sample data: offsetting old data by 1
samples[i][0] = samples[i-1][0];
samples[i][1] = samples[i-1][1];
samples[i][2] = samples[i-1][2];
}
// add newest entry as the first sample (replacing old data)
samples[0][0] = x;
samples[0][1] = y;
samples[0][2] = z;
}
// render samples on screen with the option to scale the data
void drawSamples(float scale) {
beginShape();
for (int i = 0 ; i < numSamples; i++){
vertex(samples[i][0] * scale, samples[i][1] * scale, samples[i][2] * scale);
}
endShape();
}
void drawAxes(float x, float y, float z) {
//X - red
stroke(192, 0, 0);
line( 0, 0, 0, x, 0, 0);
//Y - green
stroke(0, 192, 0);
line(0, 0, 0, 0, y, 0);
//Z - blue
stroke(0, 0, 192);
line(0, 0, 0, 0, 0, z);
}
Обратите внимание на некоторые изменения:
DataLine
переименован в dataLine
(согласно Java Соглашения об именах ) - обычно переименовывают переменные, чтобы легко понять, что они / делают, и отформатировать код, чтобы было легче читать
- ошибка обработки последовательного порта. Вы уже сделали обработку ошибок для входящих данных, и это здорово.
Идея состоит в том, чтобы вырабатывать хорошие привычки по мере продвижения.
Если у вас есть время для изучения других языков, я рекомендую Python и несколько модулей, потенциально для того, чтобы начать кластеризацию / классификацию данных датчика, если это представляет интерес:
- pyserial для последовательной связи
- SciPy :
numpy
для быстрой обработки массива, matplotlib для построения графиков и sklearn для классификации / кластеризации / et c.