Трехмерный массив поступает в неправильном порядке через последовательный порт - PullRequest
1 голос
/ 27 мая 2019

Для университетского задания я пишу Java-приложение, которое будет запускать игровую логику для интерактивного светодиодного стола. Сам стол управляется либо 2 Arduino Duemilanove, либо 1 Arduino Mega 2560.

Чтобы предоставить Arduino информацию о том, какие светодиоды должны гореть, и какого цвета я отправляю данные через последовательный порт с Raspberry Pi 3b + на Arduinos. Поскольку таблица состоит из 14 светодиодных лент с 14 светодиодами на каждую светодиодную ленту, а каждый светодиод имеет 3 цветовых значения (RGB), я сохраняю данные о таблице в массиве int [14] [14] [3].

Перед отправкой массива в Arduino я создаю его JSON-объект (используя библиотеку Джексона), а затем отправляю массив в виде строки, используя jSerialComm. В зависимости от того, какую настройку Arduino я использую, я также либо передаю весь массив в JSON, либо разделяю его на два массива int [7] [14] [3] перед созданием объекта JSON.

Поскольку данные поступили в неправильном порядке на последовательный порт, когда я использовал 2 Arduinos и jSerialComm, я теперь получил новую Arduino Mega 2560 (так как другие вопросы SO предполагали, что неправильный порядок данных может возникнуть из-за устаревшего модуля PL2303) и попробовал еще раз с тем же результатом. После некоторых дальнейших исследований я теперь попытался использовать JSSC вместо jSerialComm, но все еще показывает тот же результат.

Java-класс, который я использую для отправки данных в arduino, выглядит следующим образом (кодом закомментированного кода является код, в котором я использовал 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 (s) обработка выглядит так:

#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 (начиная с Serial.println () в void loop):

enter image description here

Как видно, первые значения RGB передаются корректно, однако даже после менее чем одной полной светодиодной полосы данные поступают в неправильном порядке и (как видно в конце рисунка) в какой-то момент полностью перестают отображаться вверх, что, вероятно, означает, что данные больше не читаются.

Я очень старался заменить Arduino на случай, если PL2303 устарел или неисправен, а также пробовал разные библиотеки для последовательной связи, однако я не могу понять, что я делаю неправильно. Я потратил более 30 часов, пробуя разные подходы, но безрезультатно, поэтому все становится для меня очень неприятным.

UPDATE

Как предложено 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 Ответ

0 голосов
/ 30 мая 2019

Первым шагом для рабочего решения было удаление ненужного вызова Serial.print() каждый раз, когда читался новый символ. После удаления этой строки я смог подтвердить правильность полученных данных. Сдвинутая обратная связь, как упомянуто в моем втором обновлении к посту:

Я также выяснил, что после отправки первого объекта JSON Arduino выводит на консоль ноль и отправляет мне только первый объект JSON после получения второго объекта JSON. Однако, это единственный раз, когда я получаю какие-либо отзывы от Arduino, кроме null

произошло из-за того факта, что я недолго ждал на стороне приложения Java получения данных перед вызовом функции read(). После решения этой проблемы я всегда получал правильную строку.

Опробование различных конфигураций либо с DynamicJsonDocument, либо с StaticJsonDocument Теперь я в итоге использовал DynamicJsonDocument, но здесь также мог бы работать StaticJsonDocument. Довольно неприятная проблема заключалась в том, что во внутреннем цикле for в void process я случайно сравнил переменную счетчика с переменной внешнего цикла for, хотя мне удалось получить правильные данные в этой точке за пределами цикла for.

Проблема, заданная в этих вопросах, таким образом, решена, однако теперь возникла еще более серьезная проблема, поскольку я не могу получить какие-либо данные из полученного объекта JSON, как только я начинаю реализовывать код для управляйте светодиодами и звоните row[i].setPixelColor(j, row[i].Color(values[i][j][0], values[i][j][1], values[i][j][2])); в любой точке моего кода. Таким образом, чтобы подвести итог, этот конкретный вызов является реальной причиной того, что код не работает должным образом.

Я открою новый вопрос для этой новой проблемы, поскольку он не относится к этому вопросу тематически, однако я добавлю сюда ссылку, как только она будет написана.


UPDATE

Новый вопрос, касающийся адресации более 7 светодиодных лент с использованием библиотеки Adafruit NeoPixel, можно найти здесь .

...