java - 三维数组以错误的顺序到达串行端口

标签 java arrays json arduino serial-port

对于一项大学作业,我正在编写一个 Java 应用程序,它将为交互式 LED table 运行一些游戏逻辑。 table 本身由 2 个 Arduino Duemilanove 或 1 个 Arduino Mega 2560 控制。

为了向 Arduino 提供有关哪些 LED 应以哪种颜色点亮的信息,我通过串行端口将数据从 Raspberry Pi 3b+ 发送到 Arduino。由于该表由 14 个 LED 灯条组成,每个 LED 灯条有 14 个 LED,并且每个 LED 有 3 个颜色值 (RGB),因此我将有关该表的数据存储在 int[14][14][3] 数组中。

在将数组发送到 Arduino 之前,我创建了一个 JSON 对象(使用 Jackson 库),然后使用 jSerialComm 将数组作为字符串发送。根据我使用的 Arduino 设置,我还可以将整个数组传输为 JSON,或者在创建 JSON 对象之前将其拆分为两个 int[7][14][3] 数组。

当我使用 2 个 Arduino 和 jSerialComm 时,由于数据以错误的顺序到达串行端口,我现在得到了一个新的 Arduino Mega 2560(正如其他 SO 问题表明,由于过时的 PL2303 模块可能会出现错误的数据顺序),并再次尝试,得到相同的结果。经过进一步的研究,我现在尝试使用 JSSC 而不是 jSerialComm,但仍然出现相同的结果。

我用来将数据发送到arduino的java类如下所示(注释掉的代码是我使用jSerialComm/2 Arduinos的代码):

package de.pimatrix.backend;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fazecast.jSerialComm.SerialPort;

import jssc.SerialPortException;

public class SerialThread implements Runnable {

    public static SerialPort arduino1, arduino2;
    private int[][][] matrix = new int[14][14][3];

    private int[][][] matrixLeft = new int[7][14][3];
    private int[][][] matrixRight = new int[7][14][3];

    private Socket localHost;
    private Matrix matrixData;
    private ObjectInputStream in;

    @Override
    public void run() {

        SerialJSONWriter writer = new SerialJSONWriter();

        ServerSocket ss = null;
        localHost = null;
        matrixData = new Matrix(matrix);
        try {
            ss = new ServerSocket(62000); // erstellen eines lokalen Sockets auf Port 62000, um die zu übertragende
                                            // Matrix vom ClientThread
        } catch (IOException e) {
        }

        while (true) {
            try {
                localHost = ss.accept();
            } catch (Exception e) {
                e.printStackTrace();
            }
            initializeInputStream();
            waitForMatrix();
            splitMatrix();

            try {
                writer.tryWrite(matrixRight, matrixLeft);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void splitMatrix() {
        for (int i = 0; i < 14; i++) {
            for (int j = 0; j < 14; j++) {
                if (i <= 6) {
                    matrixRight[i][j][0] = matrix[i][j][0];
                    matrixRight[i][j][1] = matrix[i][j][1];
                    matrixRight[i][j][2] = matrix[i][j][2];
                } else {
                    matrixLeft[i - 7][j][0] = matrix[i][j][0];
                    matrixLeft[i - 7][j][1] = matrix[i][j][1];
                    matrixLeft[i - 7][j][2] = matrix[i][j][2];
                }
            }
        }
    }

    private void initializeInputStream() {
        try {
            InputStream input = localHost.getInputStream();
            in = new ObjectInputStream(input);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void waitForMatrix() {
        System.out.println("Waiting for Matrix");
        try {
            matrixData = (Matrix) in.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        this.matrix = matrixData.matrix;
    }

    class SerialJSONWriter implements AutoCloseable {

        // Zuweisen der seriellen Ports
//      private final SerialPort /*arduino1, arduino2,*/ arduinoMega;
        private jssc.SerialPort arduinoMega;

        public SerialJSONWriter() {
//          arduino1 = SerialPort.getCommPort("COM5");
//          arduino2 = SerialPort.getCommPort("COM6");
//          arduinoMega = SerialPort.getCommPort("COM7");
            arduinoMega = new jssc.SerialPort("COM7");
            try {
                arduinoMega.openPort();
                arduinoMega.setParams(115200, 8, 1, jssc.SerialPort.PARITY_EVEN);
            } catch (SerialPortException e) {
                e.printStackTrace();
            }
//          arduinoMega.setBaudRate(115200);
//          arduinoMega.setNumDataBits(8);
//          arduinoMega.setNumStopBits(1);
//          arduinoMega.setParity(0);


            // setzen der Timeouts für die Kommunikation mit den Arduinos
//          arduino1.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
//          arduino2.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
//          arduinoMega.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
//          arduino1.setBaudRate(115200);
//          arduino2.setBaudRate(115200);
//          arduinoMega.setBaudRate(115200);
//          arduino1.openPort();
//          arduino2.openPort();
//          arduinoMega.openPort();
//          arduino1.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 0,
//                  0);
//          arduino2.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 0,
//                  0);

//          arduinoMega.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 0,
//                  0);
        }

        public void write() {

        }

        private void tryWrite(Object dataRight, Object dataLeft) throws IOException {
            String dataAsJSONRight = new ObjectMapper().writeValueAsString(dataRight) + "\n";
            String dataAsJSONLeft = new ObjectMapper().writeValueAsString(dataLeft) + "\n";
            try {
                arduinoMega.writeString(dataAsJSONRight);
            } catch (SerialPortException e) {
                e.printStackTrace();
            }
//          for (int i = 0; i < dataAsJSONRight.length(); i++) {
////                arduino1.getOutputStream().write(dataAsJSONRight.getBytes()[i]);
//              System.out.println(dataAsJSONRight);
//              arduinoMega.getOutputStream().write(dataAsJSONRight.getBytes()[i]);
//          }
//          for (int i = 0; i < dataAsJSONLeft.length(); i++) {
////                arduino2.getOutputStream().write(dataAsJSONLeft.getBytes()[i]);
//              arduinoMega.getOutputStream().write(dataAsJSONLeft.getBytes()[i]);
//          }
        }

        @Override
        public void close() throws Exception {
//          arduino1.closePort();
//          arduino2.closePort();
            arduinoMega.closePort();
        }
    }
}

在 Arduino 上,处理过程如下所示:

#include <ArduinoJson.h>
#include <Adafruit_NeoPixel.h>

#define PINROW0 2
#define PINROW1 3
#define PINROW2 4
#define PINROW3 5
#define PINROW4 6
#define PINROW5 7
#define PINROW6 8

#define NUMPIXELS 14 //Amount of pixels per row

Adafruit_NeoPixel row[] = { //Intitialize the array, that contains the addressable LED strips in the Adafruit format
  Adafruit_NeoPixel(NUMPIXELS, PINROW0, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUMPIXELS, PINROW1, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUMPIXELS, PINROW2, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUMPIXELS, PINROW3, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUMPIXELS, PINROW4, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUMPIXELS, PINROW5, NEO_GRB + NEO_KHZ800),
  Adafruit_NeoPixel(NUMPIXELS, PINROW6, NEO_GRB + NEO_KHZ800)
};

#define DELAY 1000 //set refresh cycle to 10 milliseconds
#define NUMSTRIPS 7/*(sizeof(row)/sizeof(row[0]))*/ //Amount of connected LED strips


int values[7][14][3];
int c = 0;
String matrixAsString = "";

void setup() {

  /*Setup serial port on which the Pi connects to the Arduino*/
  Serial.begin(115200); //set baudrate to 115200 Bit per second
  Serial.setTimeout(1000);

  Serial.println(100);

  /*initialize NeoPixel Library*/
  for (int i = 0; i < NUMSTRIPS; i++) {
    row[i].begin();
    row[i].show();
  }
}

void process(String matrixAsString) {
  StaticJsonDocument<4372> doc;
  Serial.println(matrixAsString);
  deserializeJson(doc, matrixAsString);

  for (int i = 0; i < 7; i++) {
    for (int j = 0; i < 14; j++) {
      values[i][j][0] = values[i][j][1] = values[i][j][2] = (int) (doc[i][j][0]);
    }
  }
}

//infinite loop refreshing the matrix
void loop() {

  while (Serial.available()) {
    char c = Serial.read();
    Serial.println(matrixAsString);
    matrixAsString += c;
    if (c == '\n') {
      process(matrixAsString);
      matrixAsString = "";
    }

  }

}

发送半矩阵数据时(例如 int[7][14][3]):

[[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[255,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]]

通过 Arduino IDE 中的串行监视器,我从 Arduino 获得以下输出(从 void Loop 中的 Serial.println() 开始):

enter image description here

正如人们所看到的,第一个 RGB 值已正确传输,但是,即使在不到一个完整的 LED 灯条之后,数据也会以错误的顺序到达,并且(正如您在图片末尾看到的那样)在某个时刻完全停止显示,这可能表明不再读取任何数据。

我一直在尝试很多事情,比如更换 Arduino,以防 PL2303 过时或有缺陷,以及尝试不同的串行通信库,但我无法弄清楚我做错了什么。我花了 30 多个小时尝试不同的方法,但没有成功,所以事情让我感到非常沮丧。

更新

根据B.Letz的建议我正确设置了数据、停止位和奇偶校验位(现在为 8 个数据、1 个停止位且无奇偶校验位)。通过阅读 arduino 反馈,我仍然得到相同的结果,但经过一番调整后,我意识到问题可能是我的 Serial.print 显然导致了 Arduino 的巨大滞后,因此它无法正确及时地处理所有数据。在进行处理之前删除第一个 Serial.print 调用后,我现在看到 Arduino 正确打印了正在传输的第一个矩阵。然而,出于某种原因,对于所有进一步传输的数据,Arduino 都会打印 null。我将尝试延长超时,以防由于 Arduino 端超时而出现空指针。

更新2

与我的假设相反,重新配置超时并没有解决问题。我还发现,在发送第一个 JSON 对象后,Arduino 将 null 打印到控制台,并且在收到第二个 JSON 对象后才向我发送第一个 JSON 对象。然而,这是我唯一一次从 Arduino 得到任何反馈,除了 null 之外。我还注意到,当我通过串行监视器发送 JSON 字符串时,Arduino 会立即打印正确的字符串但是,它还会打印一个空的新行,并且不会响应任何类型的任何新数据。

最佳答案

工作解决方案的第一步是删除不必要的 Serial.print()每次读取新字符时调用。删除这条线后,我可以确认数据正确到达。 正如我对帖子的第二次更新中提到的转变的反馈:

I also figured out that after the first JSON Object is sent the Arduino prints null to the console and only sends me the first JSON object after receiving the second JSON object. However this is the only time I get any feedback from the Arduino except null

发生的原因是我在调用 read() 之前没有在 java 应用程序端等待足够长的时间来接收数据。功能。解决这个问题后,我总是收到正确的字符串。

使用 DynamicJsonDocument 尝试不同的配置和StaticJsonDocument我现在最终使用 DynamicJsonDocument但也有一个 StaticJsonDocument可能在这里工作过。 一个相当令人不快的问题是 void process 中的内部 for 循环。我不小心将计数器变量与外部 for 循环的变量进行了比较,尽管我能够在 for 循环之外检索到正确的数据。

这个问题中提出的问题因此得到解决,但是现在出现了一个更大的问题,因为一旦我开始实现控制 LED 的代码并调用 row[i].setPixelColor(j, row[i].Color(values[i][j][0], values[i][j][1], values[i][j][2]));,我就无法从收到的 JSON 对象中检索任何数据。在我的代码中的任何一点。因此,总而言之,这个特定的调用是代码无法正常工作的实际原因。

我将针对该新问题提出一个新问题,因为它在主题上不属于该问题,但是一旦编写完毕,我将在此处添加对其的引用。

<小时/>

更新

有关使用 Adafruit 的 NeoPixel 库解决 7 个以上 LED 灯带问题的新问题可以在 here 中找到。 .

关于java - 三维数组以错误的顺序到达串行端口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56331204/

相关文章:

java - sqljdbc4.jar - 无法连接到 MSSQL 服务器实例 - SSL 错误?

java - 仅将集合的一部分放入数组中

javascript - 拒绝执行来自 'file_name.php' 的脚本,因为它的 MIME 类型 ('text/html' ) 不可执行,并且启用了严格的 MIME 类型检查

java - 如何初始化一个二维数组?

c# - 有谁知道我在哪里可以找到通用 Windows 专用网络(客户端和服务器)代码示例?

php - 如何使用 PHP 在 JSON 中添加数据

java - Spring 批处理 : FlatFileItem Writer

java - 如何读取以 json 形式发送的 google 登录 api 的响应

java - 如何在 find-sec-bugs 中仅运行定义的检测器

c - 比较 int 数组的程序不起作用