当前位置: 首页 > 知识库问答 >
问题:

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

司空实
2023-03-14

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

为了给Arduino提供关于哪些LED应该以何种颜色点亮的信息,我通过串行端口将数据从树莓Pi 3b发送到Arduinos。由于该表由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 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()开始)获得以下输出:

正如人们可以看到的,第一个RGB值被正确地传输,然而,在不到一个完整的发光二极管条之后,数据以错误的顺序到达,并且(正如你在图片的结尾所看到的)在某个时候完全停止显示,这可能表明不再读取任何数据。

我一直在尝试很多事情,比如更换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会立即打印正确的字符串,但它也会打印一个空的新行,并且不会响应任何类型的新数据。

共有1个答案

濮阳景天
2023-03-14

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

我还发现,在发送第一个JSON对象后,Arduino会将null打印到控制台,并且只在接收到第二个JSON对象后才向我发送第一个JSON对象。然而,这是我唯一一次从Arduino得到任何反馈,除了空

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

使用DynamicJsonDocumentStaticJsonDocument尝试不同的配置,我现在使用的是DynamicJsonDocument,但是StaticJsonDocument也可能在这里起作用。一个相当令人不快的问题是,在无效过程中的内部for循环中,我意外地将计数器变量与外部for循环的计数器变量进行了比较,尽管我能够在for循环之外的该点检索到正确的数据。

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

我将为这个新问题打开一个新问题,因为它在主题上不属于这个问题,但是一旦它被写出来,我将在这里添加一个参考。

更新

关于使用Adafruit的NeoPixel库处理7个以上LED条带的新问题可以在这里找到。

 类似资料:
  • 我有(1000、256、256)形状的3D阵列。我想从x维度中删除第100-200个条目(包含1000个条目)。写入[0:100101:1001]将从第二个维度(256个项目)进行剪切。 我如何索引它?

  • 一个表示3X3矩阵matrix.的类。 代码示例 const m = new Matrix3(); 注意行优先列优先的顺序。 set()方法参数采用行优先row-major, 而它们在内部是用列优先column-major顺序存储在数组当中。 这意味着 m.set( 11, 12, 13, 21, 22, 23, 31, 32, 33 );元素数组elements将存储

  • 给出了一系列成本。你可以向前跳两次,也可以向后跳一次。如果你在一个特定的指数上着陆,你必须把成本加到你的总数上。找到穿过数组或到达数组末端所需的最小成本。 输入: 输出: 说明:我们从指数1开始,跳到3然后跳出来,总成本为8 4=12。 我们如何为此构建DP解决方案?

  • 我有一个记录课程: 我创建了一个包含很多记录的大列表。只有第二个和第五个值,即i/10000和i,稍后分别由getter使用。 请注意,前10000条记录的类别2为0,接下来的10000条记录的类别1等,而值1按顺序为0-114999。 我创建了一个既并行又排序的流。 我有一个ForkJoinPool,它维护8个线程,这是我电脑上的内核数。 我使用这里描述的技巧将流处理任务提交给我自己的,而不是常

  • 我是编程新手,我有一个任务要求从一维数组创建二维数组。我想到了这一点(没有任何外部来源的帮助,因为这会剥夺学习经验)。它适用于我们教授的测试输入,我只是想知道这是一个丑陋/低效的解决方案。 测试输入:twoDArray([1,2,3,4,5],3)输出将是:[[1,2,3],[4,5]]

  • 我正在为一款新游戏编写关卡编辑器。问题是,我不确定用什么结构来存储数据。 它是一个基于平铺的地图引擎,使用x和y坐标以及该位置的平铺id。 我有多层,地图是可调整大小的,所以数组可能会给我带来一些麻烦,这就是为什么我选择了d::向量。为了防止大量过载,我只在有人放置瓷砖时添加一个瓷砖,所以如果没有瓷砖,矢量大小为零,并且放置的瓷砖越多,矢量大小就越大。 还有我的向量: 问题是,在添加新的磁贴之前,