Trying to wrangle serial data from an Arduino

Hello all,
I’ve been working on a project for the last few days. It’s a very simple LiDAR scanner turret. It scans from right to left, steps up, and then scans right to left again, repeating this for a set amount of scans. I actually completed the project, but my tiny Arduino-driven screen I was using appears to be defective and is no longer reliably outputting anything. So I decided to chuck the data over to Processing and see if I could get it to output the data in the same way I was outputting it to the screen.

So far, I’ve gotten the Arduino to spit out this data to serial:

23:15:16.634 -> 336	478	474	465	458	433	420	411	398	374	
23:15:16.634 -> 453	457	453	441	431	422	410	399	397	384	
23:15:16.634 -> 480	470	471	460	443	436	421	411	400	399	
23:15:16.634 -> 478	474	465	458	433	420	411	398	374	390	
23:15:16.634 -> End
23:15:26.740 -> 325	476	475	473	460	430	422	413	402	374	
23:15:26.740 -> 446	459	452	442	428	417	409	395	386	385	
23:15:26.740 -> 476	481	478	463	445	430	421	419	400	395	
23:15:26.740 -> 476	475	473	460	430	422	413	402	374	392	
23:15:26.740 -> End
23:15:36.836 -> 328	478	475	473	463	430	415	418	399	378	
23:15:36.836 -> 450	455	455	443	438	424	410	395	394	387	
23:15:36.836 -> 479	479	470	459	440	434	425	415	407	403	
23:15:36.836 -> 478	475	473	463	430	415	418	399	378	387	
23:15:36.836 -> End
23:15:46.896 -> 328	475	477	468	460	441	420	414	411	384	
23:15:46.896 -> 457	454	456	442	429	418	412	398	394	385	
23:15:46.896 -> 475	482	471	457	448	428	421	410	404	389	
23:15:46.896 -> 475	477	468	460	441	420	414	411	384	373	
23:15:46.896 -> End

The rows are tab-delimited per-value, and newlines are created with both \n and \r.

I’m stuck figuring out how to wrangle this into a 2d array in Processing. ← That’s my question, I don’t need any help writing the array to the screen.

Here’s my code so far:

import processing.serial.*;

Serial arduino; // Create object from Serial class
String serialData; // Data received from the serial port
int aziRange = 10;
int elevRange = 3;
int[][] LiDARdata = new int[aziRange][elevRange]; //Serial data formatted into an array

void setup() {
  String portName = Serial.list()[2]; // 2 = COM3 = Arduino
  arduino = new Serial(this, portName, 115200);
  
  size(320, 240);
}

void draw() {
  if(arduino.available() > 0) {
    serialData = arduino.readStringUntil('\r');
  }
  if(serialData != "End" && serialData != null) {
    println(serialData);
    String[] columnBreak = new String[elevRange];
    for(int i = 0; i < elevRange; i++) {
      columnBreak = splitTokens(serialData, "\n");
      print(columnBreak[i]);
    }
  }
}

Any ideas? Help would be very much appreciated, and I can share the Arduino code if necessary.

1 Like

Hello,

I spent a few moments on this to get you started…

Processing Code 1
import processing.serial.*;

Serial arduino; // Create object from Serial class
String serialData; // Data received from the serial port
int aziRange = 10;
int elevRange = 3;
int[][] LiDARdata = new int[aziRange][elevRange]; //Serial data formatted into an array

void setup() {

  printArray(Serial.list()); //glv
  String portName = Serial.list()[2]; // 2 = COM3 = Arduino
  arduino = new Serial(this, portName, 9600);

  size(320, 240);
}

void draw() {
  if (arduino.available() > 0) {
    serialData = arduino.readStringUntil('\r');
    //println(serialData); //glv
  }
  //if(serialData != "End" && serialData != null) {
  //  println(serialData);
  //  String[] columnBreak = new String[elevRange];
  //  for(int i = 0; i < elevRange; i++) {
  //    columnBreak = splitTokens(serialData, "\n");
  //    print(columnBreak[i]);
  //  }
  //}

  if (serialData != null) {
    println(serialData);
    serialData = trim(serialData);

    //String[] columnBreak = new String[elevRange];
    //columnBreak = splitTokens(serialData, " ");
    String[] columnBreak = splitTokens(serialData, " ");
    println(elevRange);
    for (int i = 0; i < elevRange; i++) {
      //columnBreak = splitTokens(serialData, " ");
      print(columnBreak[i]);
      print(" ! ");
    }
    println();
    println(columnBreak);
  }
}

Arduino Code 1
void setup() 
  {
  Serial.begin(9600);
  Serial.flush();
  delay(2000);
  }

void loop() 
  {
  Serial.println("23:15:16.634 -> 336  478 474 465 458 433 420 411 398 374");
  delay(100); 
  Serial.println("23:15:16.634 -> 453 457 453 441 431 422 410 399 397 384");
  delay(100);  
  Serial.println("3:15:16.634 -> 480 470 471 460 443 436 421 411 400 399"); 
  delay(100); 
  Serial.println("23:15:16.634 -> 478 474 465 458 433 420 411 398 374 390"); 
  }

Start with a 1D array and then pack that into a 2D array.
That was my next step… but have laundry to do and this is as far as I got.

There are many posts in this forum on serial communications.

Have fun exploring!

Update…

Add the “End” to Arduino code to use with code below.

This code below will receive a nice clean data set of Strings from Arduino.
I left it as a 1D array of Strings that you can process further into useful data.

Processing Code 2
// Processing Serial Data
// GLV
// 2021-10-10

import processing.serial.*;

Serial arduino; // Create object from Serial class
String serialData; // Data received from the serial port

int data, count;
String [] sLidarData = new String [5];

boolean dataSetReady;

void setup() 
  {
  size(350, 100);
    
  printArray(Serial.list());
  String portName = Serial.list()[2]; // 2 = COM3 = Arduino
  println();

  // This will clear out the "leftovers" in the buffers
  arduino = new Serial(this, portName, 9600);
  arduino.stop();
  arduino = new Serial(this, portName, 9600);
  }

void draw()     
  {
  //background(0);
// Receive sLidarData data set  
  if (arduino.available() > 0) 
    {
    serialData = arduino.readStringUntil('\r');
    //println(serialData); //debug

    if (serialData != null) 
      {
      //println(serialData); // Try this before and after!
      serialData = trim(serialData);
      println(serialData);

      String[] dataIn = splitTokens(serialData, " ");
      
    
  // This saves the Lidar data as Strings in an 1D array
  // It can then be processed into a 2D array or otherwise.
  
      sLidarData [data++] = serialData;
      
      if (dataIn[2].equals("End")) 
        {
        println(); println("End"); println();
        data = 0;
        printArray(sLidarData); //debug
        if(sLidarData.length == 5) 
          {
          println(); println(count);   
          dataSetReady = true;
          }
        }  
      }  
    }
  } 
  

This still needs work! I leave that with you.

References:
https://processing.org/reference/split_.html This will be handy!
https://processing.org/reference/libraries/serial/index.html

:)

2 Likes

Thank you so much for the help.

The code runs fine for 6 scans, then it seems to overflow:

279	297	313	327	341	346	362	355	351	339	
285	301	320	338	341	346	344	335	328	315	
289	300	326	330	352	351	342	348	335	327	
297	313	327	341	346	362	355	351	339	327	
End
258	302	314	323	343	361	361	355	347	341	
289	298	325	338	343	348	337	332	324	319	
293	305	327	335	346	352	343	346	344	329	
302	314	323	343	361	361	355	347	341	330	
End
247	302	311	331	342	353	359	361	351	340	
288	303	321	338	348	350	341	333	323	321	
291	306	323	339	346	353	349	334	330	330	
302	311	331	342	353	359	361	351	340	326	
End
251	300	312	329	342	353	356	355	346	341	
289	302	325	340	348	345	341	333	331	320	
287	305	319	341	343	354	351	342	331	334	
300	312	329	342	353	356	355	346	341	333	
End
252	300	309	326	339	347	355	352	348	343	
280	303	319	343	351	347	337	331	329	320	
294	305	325	343	344	352	351	347	335	325	
300	309	326	339	347	355	352	348	343	331	
End
255	299	309	327	343	356	361	354	346	342	
284	305	323	336	344	350	349	335	323	319	
292	304	323	339	353	349	354	336	336	333	
299	309	327	343	356	361	354	346	342	327	
End
ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5

I don’t want to keep collecting all the data. What I want to do is each time a scan comes in, I write it to the screen, then wait for the next scan.

Hello,

I threw some code together based on what you were sending…

I adapted my Arduino code to send a random extra line and also got an expected ArrayIndexOutOfBoundsException.

https://forum.processing.org/two/discussion/8070/why-do-i-get-an-arrayindexoutofboundsexception

This tested for it:

if (data > 4)
  println("Corrupt data!");
else
  sLidarData [data++] = serialData;

Often people are just using the “canned” Arduino examples and try to work with that.

I did not provide a complete working solution… just some code to get you started.

Adapt or rewrite your code as required and as errors show up.

Also search through the forum for some insights.

:)

Ok, well, thanks anyway. I’ll try to go on this and what you gave me.

If anyone else would like to help, here’s my current Arduino code in full. It’s adapted from the version which prints stuff to the attached screen, so there’s a lot of commented out code.

// setup the screen and stuff
/*#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#define TFT_DC 6
#define TFT_CS 7
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);*/

//setup motor shield
#include <Adafruit_MotorShield.h>

//setup motors
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *aziDrive = AFMS.getStepper(200, 1);

//setup servos
#include <Servo.h>
Servo elevDrive;

//setup the sensor
#include <Wire.h>
#include <VL53L0X.h>
VL53L0X sensor;

//changeable variables are here
const int aziRange = 10; //azimuth total sweep range (in motor steps * aziRes (200 per 360 degrees))
const int aziRes = 1; //azimuth resolution
const int elevRange = 3; //elevation total sweep steps
const int elevRes = 4; //elevation resolution (in degrees) (make sure (elevRange*elevRes) <= 170)
const int numReadings = 2; //number of samples per scan
const float maxDepth = 1000.0; //maximum displayed depth (must have .0 to work)
//const float minDepth = 300.0; //minimum displayed depth (must have .0 to work)

//non-changeable setup variables are here
int LiDARdata[aziRange][elevRange];
//const int Height = 240;
//const int Width = 320;



void setup() {
  Serial.begin(9600);
  Wire.begin();
  while (!Serial);
  
  //Serial.println("Mini-LiDAR Program Start!");
  /*tft.begin();
  tft.setRotation(3);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
  tft.fillScreen(ILI9341_BLACK);*/

  elevDrive.attach(10); //attach the elevation servo to pin 10
  elevDrive.write(10);

  if(!AFMS.begin()) {
    //Serial.println("Could not find Motor Shield.");
    while (1);
  }
  //Serial.println("Motor Shield found.");

  sensor.setTimeout(500);
  if (!sensor.init()) {
    //Serial.println("Failed to detect and initialize sensor.");
    while (1) {}
  }
  //Serial.println("Sensor found.");

  sensor.startContinuous();
  
  //Serial.println("Initialization complete. Waiting for positioning.");
  //tft.print("Initialization complete. \nWaiting for positioning.");
  
  delay(3000); //wait for user to position the stepper

  aziDrive->setSpeed(1);
  aziDrive->step(aziRange/2, BACKWARD, MICROSTEP); //move motor back by half length to starting position

  //tft.fillScreen(ILI9341_BLACK);
  //tft.setRotation(1);
}



void loop() {
  elevDrive.write(10);
  for(int elevStep = 0; elevStep <= elevRange; elevStep++) {
    //Serial.print("Starting elevation sweep ");
    //Serial.println(elevStep);
    elevDrive.write((elevStep * elevRes) + 10); //elevate by a step and add 10 deg for power usage reasons (duplicated step to fix the second sweep not elevating bug)
    for (int aziStep = 0; aziStep < aziRange; aziStep++) {
      //Serial.println(aziStep);
      
      int total = 0;
      
      for(int i = 0; i < numReadings; i++) {
        total = total + sensor.readRangeContinuousMillimeters();
      }
      
      float average = (total/1.0)/(numReadings/1.0);
      //Serial.println(average);
      LiDARdata[aziStep][elevStep] = average; //store LiDAR data
      
      aziDrive->step(aziRes, FORWARD, MICROSTEP); //step azimuth forward by 1
    }
    //Serial.println("Azimuth moving back to start...");
    elevDrive.write(((elevStep + 1) * elevRes) + 10); //elevate by a step and add 10 deg for power usage reasons (added 1 to move during azimuth reset)
    aziDrive->step(aziRange*aziRes, BACKWARD, MICROSTEP); //move azimuth back to starting position
  }
  //Serial.println("Elevation moving back to start...");
  int elevStep = 0;
  elevDrive.write(elevStep + 10); //move elevation back to starting position
  
  for(int j = 0; j <= elevRange; ++j) { // loop through array's rows
    for(int i = 0; i < aziRange; ++i) {// loop through columns of current row
    /*
    float grayScale = 1; //this sets the grayScale value to 0 if the sensor reading was outside of the set maxDepth instead of it being that weird yellow color
    if (LiDARdata[i][j] < maxDepth) {
      grayScale = 1 - (LiDARdata[i][j] / maxDepth);
    } else {
      grayScale = 0;
    }
    //float grayScale = 1 - (LiDARdata[i][j] / maxDepth);
    //float grayScale = 1 - (((LiDARdata[i][j] - 0.0) * (maxDepth - minDepth) / (1300.0 - 0.0) + minDepth) / maxDepth);
    unsigned int colorHex = ((unsigned int)(0x1F * grayScale) << 11) \
                          | ((unsigned int)(0x3F * grayScale) << 5) \
                          |  (unsigned int)(0x1F * grayScale);
    
    tft.fillRect((i*(Width/aziRange)), (j*(Height/elevRange)), (Width/aziRange), (Height/elevRange), colorHex); //print data to screen in blocks
    */
    Serial.print(LiDARdata[i][j]); //print data to serial
    Serial.print("\t"); // start new column of output
    }
  Serial.print("\n"); // start new line of output
  }
  Serial.println("End");
  delay(1000);
}

Here’s my current attempt to read the serial data from the Arduino in Processing:

//MiniLiDAR companion display app
//pl4sma2389
//Credits to: GLV

import processing.serial.*;

Serial arduino; // Create object from Serial class
String serialData; // Data received from the serial port
int aziRange = 10; // Must be the same as on Arduino
int elevRange = 3; // Must be the same as on Arduino
int[][] LiDARdata = new int[aziRange][elevRange]; //Serial data formatted into an array
int data, count;
boolean dataSetReady;
int Width = 320;
int Height = 240;

void setup() {
  String portName = Serial.list()[2]; // 2 = COM3 = Arduino
  println();
  
  arduino = new Serial(this, portName, 9600);
  arduino.stop();
  arduino = new Serial(this, portName, 9600);
  
  size(Width, Height);
}

void draw() {
  if(arduino.available() > 0) {
    serialData = arduino.readStringUntil('\r');
    if(serialData != null) {
      serialData = trim(serialData);
      println(serialData);
      
      String[] dataIn = splitTokens(serialData, "\t");
      
      if(dataIn[2].equals("End")) {
        println();
        println("End");
        println();
        data = 0;
      }
    }
  }
}

And here’s my code to write some hand-formatted data to the screen in Processing:

int[][] LiDARdata = { {335, 478, 483, 467, 463, 443, 404, 411, 410, 385}, 
                      {455, 450, 445, 440, 435, 422, 412, 397, 389, 389}, 
                      {477, 474, 472, 462, 446, 429, 416, 412, 398, 392}, 
                      {478, 483, 467, 463, 443, 404, 411, 410, 385, 357} };
int aziRange = LiDARdata[0].length;
int elevRange = LiDARdata.length;
int Width = 320;
int Height = 240;
int maxRangeDisplayed = 500;

void settings() {
  size(Width, Height);
}

void setup() {
  frameRate(2);
  println(aziRange);
  println(elevRange);
}

void draw() {
  colorMode(RGB, maxRangeDisplayed, maxRangeDisplayed, maxRangeDisplayed);
  background(1);
  for (int i = 0; i < elevRange; i++) {
    for (int j = 0; j < aziRange; j++) {
      fill(maxRangeDisplayed - LiDARdata[i][j]);
      stroke(maxRangeDisplayed - LiDARdata[i][j]);
      rect((j*(Width/aziRange)), (i*(Height/elevRange)), (Width/aziRange), (Height/elevRange)); //print data to screen in blocks
    }
  }
}
1 Like

With what, specifically? What is the latest error behavior or message that you are getting with your latest code, and what are you trying to fix the error that isn’t working?

1 Like

I guess if that is your definition of help, I don’t really want help; I want advice on how I take serial data that looks like this:

233 230 254 296 357 436 486 513 519 528
235 253 290 346 410 477 516 539 550 558
229 252 295 351 424 486 513 533 537 544
230 254 296 357 436 486 513 519 528 535
End

and put it into an array in Processing that looks like this:

int[][] LiDARdata = { {179, 169, 172, 183, 201, 220, 251, 297, 359, 432}, 
                      {174, 177, 192, 207, 224, 248, 289, 343, 408, 484}, 
                      {167, 175, 187, 203, 224, 256, 298, 355, 431, 490}, 
                      {169, 172, 183, 201, 220, 251, 297, 359, 432, 484} };

I don’t really want someone to write my code for me, just give me some advice, clues, tips or whatever it is that I’m not picking up on from reading the official documentation for the past couple of days.

Wasn’t trying to be rude, I was just uncertain whether the ArrayIndexOutOfBoundsException you mentioned earlier in the thread was still the problem, or if it was something else.

Unfortunately I can’t load your code into a PI right now, but I can give specific advice on the Processing / Java side if that is where your problem is.

For example, if you are dropping values or getting extra values – or if an End is getting dropped, causing one block to have too many lines – then you could add error checking and/or you could make the Processing receiving end an ArrayList instead of an array so that it doesn’t care how many rows you add. Seeing how much you are receiving might also help with debugging.

1 Like

That’s the problem that I’m having with the code that @glv sent me, but I’m not sure that he’s thinking what I’m thinking about how I want to process the data.
I should have taken a video of the device while it was working.

I already stated:

I won’t write it for you; not my style.

I have been providing you hints and tips along the way.

I wrote test code to generate 10x10 grid data; it could just have easily been Lidar data.
I started with your Arduino code but don’t have the hardware so improvised.

Arduino Grid
void setup() 
  {
  Serial.begin(115200);
  delay(500);
  }

float offset;
float angle;

void loop() 
  {
  offset += 1;
   
  Serial.println("Start");
  for(int x = 0; x < 11; x++) 
    {     
    for(int y = 0; y < 11; y++) 
      {
      float xval = 64+64*sin((x+offset)*PI/10);
      float yval = 64+64*sin((y+offset)*PI/10);  

      float val = xval + yval;  // This will be used as color
      Serial.print(int(val));
      if (y < 10) Serial.print(','); 
      }
    Serial.print('\n');
    }
  Serial.println("End");
  delay(10);
}

I was able to write some Processing code to generate this:

loop

I followed my own suggestions and generated a 2D array from the 1D array that was received:

I did provide a reference to split() the data into integers… one of the tips I provided and necessary later.

I made a 2D array from the 1D array of Strings converted to integers with split() and int().
See the reference for examples.

This is your journey… take it one step at a time.

There are resources here:

:)

Hi @pl4sma2389 ,

Is the amount of lines and number per line fixed everytime the scan sends? I will assume that you always send 4 lines and 10 columns per line, followed by an “End”
If so, I would do something like, get the string, parse it and assign it.

Check the code below. Hope it helps!

import processing.serial.*;

Serial arduino; // Create object from Serial class

String serialData; // Data received from the serial port
int aziRange = 10; // Must be the same as on Arduino
int elevRange = 3; // Must be the same as on Arduino
int[][] LiDARdata; //Serial data formatted into an array
int data, count;
boolean dataSetReady;
int Width = 320;
int Height = 240;

int currentLine = 0;
void setup() {
  String portName = Serial.list()[2]; // 2 = COM3 = Arduino
  println();
  
  arduino = new Serial(this, portName, 9600);
  arduino.bufferUntil(13);
  
  LiDARdata = new int[elevRange][aziRange]; //4 lines by 10 columns 
  
  size(Width, Height);
}

void draw() {
 
}

void serialEvent(){
  String oneLine = arduino.readString();
  if(!oneLine.contains("End")){
    String parseLine[] = split(oneLine.trim(),'\t');
    if(parseLine.length == 10){
     for(int i = 0; i < aziRange; i++){
       LiDARdata[currentLine][i] = parseInt(parseLine[i]);
     }
     //DEBUG
     printArray(LiDARdata);
     
     currentLine++;
    }
  }
  else{
    currentLine = 0;
  }
}

EDIT: I did not test this code

1 Like

Hello @jeremydouglass,

You most certainly were not rude.
You asked for clarity on what he needed help with.

This was not a polite response:

It could have been more appropriately just an answer to your question without the vitriol:

@pl4sma2389,

https://dictionary.cambridge.org/dictionary/english/bite-the-hand-that-feeds-you

We are volunteers here and offer help where we can and if we choose to.
Communication in a forum can be a challenge at times.
Please be respectful to others.

:)

1 Like

Hello,

It is often helpful to write short snippets of test code for better understanding.
Then integrate these in to a larger project.
I do this often.

For example:

// Processing Array Study
// GLV
// 2021-10-10

String [] testData = new String [2];

int [][] test = new int[4][10];

void setup() 
  {
  testData [0] = "233 230 254 296 357 436 486 513 519 528"; // A single String of data
  testData [1] = "000 111 222 333 444 555 666 777 888 999"; // A single String of data
  printArray(testData);
  println();
  
  String[] strData = splitTokens(testData[0], " ");
  printArray(strData);
  println();
  
  String[] strData2 = split(testData[1], " ");
  printArray(strData2);
  println();
  
  int[] intData = int(split(testData[0], " "));
  printArray(intData);
  println();
  
  int[] intData2 = int(splitTokens(testData[1], " "));
  printArray(intData2);
  println();  
  
  test[0] = intData;
  printArray(test[0]);
  println();
  
  test[1] = intData2;
  printArray(test[1]);
  println();
  
  for(int i = 0; i<2; i++)
    { 
    for(int j = 0; j<10; j++)
      {
      print(test[i][j], " ");  
      }
    println();  
    }
  println();   
    
    
  for(int i = 0; i<4; i++)
    { 
    for(int j = 0; j<10; j++)
      {
      test[i][j] = j + i*4;   
      }
    }
  println();     

  for(int i = 0; i<4; i++)
    { 
    for(int j = 0; j<10; j++)
      {
      print(test[i][j], " ");  
      }
    println();  
    }   
    
for(int i = 0; i<4; i++)
    { 
    for(int j = 0; j<10; j++)
      {
      print("["+i+"]"+"["+j+"]", test[i][j], "" );  
      }
    println();  
    }       
  }
Results
[0] "233 230 254 296 357 436 486 513 519 528"
[1] "000 111 222 333 444 555 666 777 888 999"

[0] "233"
[1] "230"
[2] "254"
[3] "296"
[4] "357"
[5] "436"
[6] "486"
[7] "513"
[8] "519"
[9] "528"

[0] "000"
[1] "111"
[2] "222"
[3] "333"
[4] "444"
[5] "555"
[6] "666"
[7] "777"
[8] "888"
[9] "999"

[0] 233
[1] 230
[2] 254
[3] 296
[4] 357
[5] 436
[6] 486
[7] 513
[8] 519
[9] 528

[0] 0
[1] 111
[2] 222
[3] 333
[4] 444
[5] 555
[6] 666
[7] 777
[8] 888
[9] 999

[0] 233
[1] 230
[2] 254
[3] 296
[4] 357
[5] 436
[6] 486
[7] 513
[8] 519
[9] 528

[0] 0
[1] 111
[2] 222
[3] 333
[4] 444
[5] 555
[6] 666
[7] 777
[8] 888
[9] 999

233  230  254  296  357  436  486  513  519  528  
0  111  222  333  444  555  666  777  888  999  

0  1  2  3  4  5  6  7  8  9  
4  5  6  7  8  9  10  11  12  13  
8  9  10  11  12  13  14  15  16  17  
12  13  14  15  16  17  18  19  20  21  

[0][0] 0 [0][1] 1 [0][2] 2 [0][3] 3 [0][4] 4 [0][5] 5 [0][6] 6 [0][7] 7 [0][8] 8 [0][9] 9 
[1][0] 4 [1][1] 5 [1][2] 6 [1][3] 7 [1][4] 8 [1][5] 9 [1][6] 10 [1][7] 11 [1][8] 12 [1][9] 13 
[2][0] 8 [2][1] 9 [2][2] 10 [2][3] 11 [2][4] 12 [2][5] 13 [2][6] 14 [2][7] 15 [2][8] 16 [2][9] 17 
[3][0] 12 [3][1] 13 [3][2] 14 [3][3] 15 [3][4] 16 [3][5] 17 [3][6] 18 [3][7] 19 [3][8] 20 [3][9] 21 

:)

Thank you all very much for your suggestions. I think I’ve found a way to do it myself. I already had a way to print the data to the screen as long as I preformatted it— I was just looking for a way for the screen printing program to read the data directly from the Arduino. I’ll post my solution once I have it done.

Ideally, I would want the program to sense the width and height of the scan array automatically, as it can be configured by the user. Thanks anyway for the suggestion, it helps a lot.

Hi @pl4sma2389 ,

I guess that can be done since it is a user configuration. So, as long as it is passed to a variable you should be able to modify them.