三维阵列以错误的顺序到达串行端口

时间:2019-05-27 18:57:39

标签: java arrays json arduino serial-port

对于大学作业,我正在编写一个Java应用程序,它将为交互式LED表格运行一些游戏逻辑。桌子本身受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个Arduinos和jSerialComm时,由于数据以错误的顺序到达串行端口,所以我现在得到了一个新的Arduino Mega 2560(因为其他SO问题表明,由于PL2303模块过时,可能会出现错误的数据顺序),并且再次尝试,结果相同。经过一些进一步的研究,我现在尝试使用JSSC代替jSerialComm,但是仍然显示出相同的结果。

我用来将数据发送到arduino的java类看起来像这样(注释过的代码是我使用jSerialComm / 2 Arduino的代码):

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灯条之后,数据以错误的顺序到达,并且(如您在图片末尾所见)在某些时候完全停止显示向上,这可能表示不再读取任何数据。

我一直在尝试诸如PL2303过时或损坏的情况下更改Arduino之类的事情,以及尝试用于串行通信的不同库,但是我无法弄清楚自己在做什么错。我已经花了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立即打印正确的字符串 BUT ,它还会打印一个空的新行,并且不响应任何形式的任何新数据

1 个答案:

答案 0 :(得分:0)

解决方案的第一步是每次读取新字符时都删除不必要的Serial.print()调用。删除此行后,我可以确认数据正确到达。 正如我在第二篇更新中提到的,反馈已转移:

  

我还发现,在发送第一个JSON对象后,Arduino将null打印到控制台,并且仅在收到第二个JSON对象后才向我发送第一个JSON对象。但是,这是我唯一一次从Arduino获得任何反馈的情况,除了null

发生这种情况是由于在调用read()函数之前,我在Java应用程序端没有等待足够长的时间来等待数据到达。解决此问题后,我始终会收到正确的字符串。

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

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

我将为该新问题打开一个新问题,因为它在主题上不属于该问题,但是一旦编写,我将在此处添加引用。


更新

有关使用Adafruit的NeoPixel库解决7个以上LED灯条的新问题,可以找到here