简体   繁体   中英

Jetson TX2, Arduino Uno Serial communication

I'm using a Jetson TX2, and a Arduino Uno to try and communicate over USB serial, the premise is I'm using a Arduino to communicate with some Laser ToF sensors, and a Thermopile.

The Jetson is running Ubuntu 16.04 for ros compatability as this will eventually tie into a ros node

Using just the Arduino IDE, serial monitor it the call and response works as intended, however once I try to get the call and response working using the Jetson that's where the data isn't get correctly written printed on the terminal.

The arduino prints a byte "9" to the Jetson when it's ready to receive, and the Jetson prints a "1" or a "2" over serial when it wants to receive the time of flight or thermal sensor data respectively.

The intended communication is for the Jetson to recieve 5 comma separated, float values from the ToF Sensors, followed by 64 comma separated float values from the thermal sensor, however I get the following:

Sending 1 for ToF Data

Reading data

1 bytes read, buffer contains:

Sending 2 for Thermal Data

Reading data

35 bytes read, buffer contains: Thermal/ToF sensor data

The code for the Arduino is as follows:

#include <Wire.h>
#include <VL53L1X.h>
#include <Adafruit_AMG88xx.h>



#define SensorNum 5 // Change number if you have less sensors, just be aware that the digital pins count down, so you may need to move the starting pin number up from pin 6
#define DEBUG 0 // Change to one if you want additional debugging information printed to the serial out.
#define SFX 0  // Set to 0 if you don't want to hear the set-up pips when the ToF sensors are being configured
#define Wait_For_Read 1 // Determines if the Arduino waits for a bit to be sent by Jetson before sending sensor data


VL53L1X sensors[SensorNum];

Adafruit_AMG88xx amg;

float pixels[AMG88xx_PIXEL_ARRAY_SIZE]; // Pixel array size is 64, as it is an 8x8 thermopile array
int M_pixels[8][8];

/* Change these values below to alter what the bands the temperature is classified as
 *  these values are output into a 8x8 array with numbers of 0 to 5, with temperatures below the lower threshold being 0
 *  this is done because its a lot easier to read at a glance a small array of numbers and it's easy to visualise where the heat is compared to the 8x8 of floating numbers
 *  the values are in degrees celsius
 */

float LowerThresh = 25.0; 
float LowerMidThresh = 27.5;
float MidThresh = 30.0; 
float UpperMidThresh = 32.5;
float UpperThresh = 35.0; 
int speakerpin = 10; // digital pin for the piezo to output small pips for user convinience, if SFX is diabled this pin is not used and can be reassigned.


void setup() {
  Serial.begin (115200);

  if (SFX){
  pinMode(speakerpin, OUTPUT);
  PlayTone(5, 2, 250); // Plays a small pip to let user know arduino is running, plays 5 rapid pips
  }

  Wire.begin();
  delay(500);
  Serial.println("Setting up sensors");
  Serial.println("Beginning VL53L1X ToF sensor set-up");
  ToF_Setup();
  Serial.println("Beginning AMG8833 Thermal sensor set-up");
  Thermal_Setup();
  Serial.println("Sensors initialised");

Serial.println ("Scanning I2C addresses"); // Outputs address to serial, addressess 0x28, 0x2A, 0x2C, 0x2E, 0x30, and 0x69 should be seen
  int count = 0;

  for (int i = 1; i < 120; i++)
  {

    Wire.beginTransmission (i);
    if (Wire.endTransmission () == 0)
    {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);
      Serial.println (")");
      count++;
      delay (1);
    }
  } 
  Serial.print ("Found ");
  Serial.print (count, DEC);
  Serial.println (" device(s).");
  byte rdy = 9;

  Serial.println(rdy);

}

void loop() {
  // put your main code here, to run repeatedly:


  byte output = 0;
  if (Wait_For_Read){

    if (Serial.available()){
      output = Serial.read();
    }

  }
  else output = 49;

 // Serial.println(output);
  if(output == 49){
    ToF_Read();


  }
  if(output == 50){

    Thermal_Read();

  }
  if (DEBUG) {

    ToF_Read_Debug();
    Thermal_Read_Debug();
    delay(1000); // delay to allow reading in arduino serial monitor

  }
  Serial.flush();
  delay(100);
}

void ToF_Setup(){

int address = 0x28; // first address that the first sensor will be set to

for (int i = 6; i > 1; i--){ // sets up pins 6 to 2, for the XSHUT pin on VL53L1X to allow for address change

  pinMode(i, OUTPUT);
  digitalWrite(i, LOW);
  delay(100);

}

Wire.begin();

for (int j = 0; j < SensorNum; j++){

      if (DEBUG){
      Serial.print("Pin: ");
      Serial.println(6 - j);
      Serial.print("Current address: ");
      Serial.println(address, HEX);
      }
      if (SFX) PlayTone(j+1, 6, 500);  // plays pips according to which sensor is being set-up, 1 pip for sensor 1, 2 pips for sensor 2, etc..

      pinMode(6 - j, INPUT); 
      delay(150);
      sensors[j].init(true);
      delay(100);
      sensors[j].setAddress(address);
      Serial.print("Sensor: ");
      Serial.print(j+1);
      Serial.println(" address set.");

      address += 2;
      delay(200);

      sensors[j].setDistanceMode(VL53L1X::Long);
      sensors[j].setMeasurementTimingBudget(50000);
      sensors[j].startContinuous(50);
      sensors[j].setTimeout(100);
    }

  delay(150);
  Serial.println("ToF's initialised");

}

void Thermal_Setup(){

  Serial.println(F("AMG88xx pixels"));
  Serial.println(AMG88xx_PIXEL_ARRAY_SIZE);

  bool status;

    // default settings
    status = amg.begin();
    if (!status) {
        Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
        while (1);
    }

    Serial.println("Thermal sensor initialised");

    Serial.println();

    delay(100); // let sensor boot up


}

void ToF_Read(){

  for (int i = 0; i < SensorNum; i++){
    if(i == (SensorNum-1)){
      Serial.println(sensors[i].read()/1000.0, 4); // converts mm reading to meter, 4 signicant figures
    }
    else{
      Serial.print(sensors[i].read()/1000.0, 4); // converts mm reading to meter, 4 signicant figures
      Serial.print(",");
    }
    if (sensors[i].timeoutOccurred()) { 
      Serial.print("8000"); 
      Serial.print(",");
    }
  }

}

void Thermal_Read(){

  amg.readPixels(pixels);

  for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++) {
    if(i == (AMG88xx_PIXEL_ARRAY_SIZE)){
      Serial.println(pixels[i - 1]);
    }
    else{
      Serial.print(pixels[i - 1]);
    }
    if (i < AMG88xx_PIXEL_ARRAY_SIZE) Serial.print(",");
  }

}

void PlayTone(int repetition, int duration, int hold){
  for (int j = 0; j < repetition; j++){
    for (long i = 0; i < duration * 1000 ; i += 600){
     digitalWrite(speakerpin, HIGH);
     delayMicroseconds(1915);
     digitalWrite(speakerpin, LOW);
     delayMicroseconds(1915);
    }
    delay(hold);
   }
}

void check_pixels() {
  int row;
  int col;
  int val;
  // clear all previous pixels for next refresh
  for (int j = 0; j < 8; j++) {
    for  (int h = 0; h < 8; h++) {
      M_pixels[j][h] = 0;
    }
  }
  // if a pixel is above the temp threshold set to high
  for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) {

    row = round(i / 8);
    if (i % 8 == 0) {
      col = 0;
    }
    else
    {
      col = i % 8;
    }
    if (DEBUG) {
//    Serial.print(row);
//     Serial.print(',');
//    Serial.println(col);
    }
    if (pixels[i] >= UpperThresh) {
      val = 5;
    }
    else if (pixels[i] >= UpperMidThresh) {
      val = 4;
    }
    else if (pixels[i] >= MidThresh) {
      val = 3;
    }
    else if (pixels[i] >= LowerMidThresh) {
      val = 2;
    }
    else if (pixels[i] >= LowerThresh) {
      val = 1;
    }
    else {
      val = 0;
    }
    if (DEBUG) {
     Serial.print(i);
     Serial.print(',');
     Serial.print(pixels[i]);
     Serial.print(',');
     Serial.println(val);

    }
    M_pixels[row][col] = val;
  }
  if (DEBUG) { pixels_debug();}

  //This will print out all the pixels that should be turned on to
  //movesensor();
}


void pixels_debug() {

  for (int i = 0; i < 8; i++) {
    for  (int j = 0; j < 8; j++) {
      Serial.print(M_pixels[i][j]);
      Serial.print(',');
    }
    Serial.println(' ');
  }
}

void ToF_Read_Debug(){

  for (int i = 0; i < SensorNum; i++){
  Serial.print("Sensor ");
  Serial.print(i+1);
  Serial.print(": ");
  Serial.print(sensors[i].read());
  if (sensors[i].timeoutOccurred()) { Serial.print(" TIMEOUT"); }
  Serial.println();
  }

}

void Thermal_Read_Debug(){

  amg.readPixels(pixels);

  Serial.print("[");
  for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++) { 
    Serial.print(pixels[i - 1]);
    Serial.print(", ");
    if ( i % 8 == 0 ) Serial.println();
  }
  Serial.println("]");
  Serial.println();

  if (DEBUG) check_pixels();

}

The code for the Jetson is:

H file:

 #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdbool.h>

#define BUFFER_SIZE 1024
#define DEBUG 1

// Adapted from Canonical Arduino read by Chris Heydrick - 
// https://github.com/cheydrick/Canonical-Arduino-Read/blob/master/canonicalarduinoread.c



int init();
bool get_tof(int fd);
bool get_thermal(int fd);
bool read_data(int fd);
bool chk_rdy(int fd);

C++ File:

    #include "SensorSuite.h"



int main(int argc, char *argv[]){

int fd;
bool rdy = 0;




fd = init();

while (!rdy) {
    rdy = chk_rdy(fd);
}


rdy = get_tof(fd);

while (!rdy) {
    rdy = read_data(fd);
}

rdy = get_thermal(fd);

while (!rdy) {
    rdy = read_data(fd);
}

close(fd);

}

int init(){

  int fd;
  struct termios toptions;

  /* open serial port */
  fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
  printf("fd opened as %i\n", fd);

  /* wait for the Arduino to reboot */
  usleep(3500000);

  /* get current serial port settings */
  tcgetattr(fd, &toptions);
  /* set 9600 baud both ways */
  cfsetispeed(&toptions, B115200);
  cfsetospeed(&toptions, B115200);
  /* 8 bits, no parity, no stop bits */
  toptions.c_cflag &= ~PARENB;
  toptions.c_cflag &= ~CSTOPB;
  toptions.c_cflag &= ~CSIZE;
  toptions.c_cflag |= CS8;
  /* Canonical mode */
  toptions.c_lflag |= ICANON;
  /* commit the serial port settings */
  tcsetattr(fd, TCSANOW, &toptions);

  return fd;

}

bool get_tof(int fd){

    if(DEBUG) printf("\nSending 1 for ToF Data\n");

    write(fd, "1", 1);
    tcdrain(fd);
    usleep(2000000);

    return 0;

}

bool get_thermal(int fd){

    if(DEBUG) printf("\nSending 2 for Thermal Data\n");


    write(fd, "2", 1);
    tcdrain(fd);
    usleep(2000000);

    return 0;

}

bool read_data(int fd){

    int n;
    char buf[BUFFER_SIZE] = "temp text";

    if(DEBUG) printf("\nReading data\n");
    n = read(fd, buf, BUFFER_SIZE);
    buf[n] = 0;
    // if(n!=1)


    if (n < 35) return 0;
    else {
    if (DEBUG) printf("%i bytes read, buffer contains: %s\n", n, buf);
    return 1;
    }
}

bool chk_rdy(int fd){

    int n;
    char buf[BUFFER_SIZE] = "temp text";

    n = read(fd, buf, BUFFER_SIZE);
    buf[n] = 0;

if ((buf[0] == '9') && (n == 2)) return 1;

else return 0;


}

I've managed to solve the empty return message on Jetson by adding in a if statement (c++ code amended) to not print anything until the expected number of bytes is returned but this is hit and miss as now sometimes I get the thermal data when I should get the tof data and vice versa or I'll just get two of one

In read_data() , you cannot expect that you get all the data with one n = read(fd, buf, BUFFER_SIZE) call. Apparently the first read call yields only the first data byte, so you have to continue reading and appending data into buf until all data arrived. (Of course for this you either have to know how many bytes are sent or how the end can be identified.)

Following on from Armali,

I managed to get it working by working out how many bytes I was was sending, luckily they were constant throughout, I then simply kept the the Jetson reading until the correct amount of bytes had arrived, using the serial output I recognized that the Jetson actually went through a few cycles before the Arduino had sent all the data, I believe this was due to using serial prints in the Arduino code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM