Для университетского задания я пишу 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
):
Как видно, первые значения 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 мгновенно печатает правильную строку НО , она также печатает пустую новую строку и не реагирует на какие-либо новые данные в любом виде.