title: Jetson TX2, Arduino Uno Serial communication
body: <p>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.</p>
  
  <p>The Jetson is running Ubuntu 16.04 for ros compatability as this will eventually tie into a ros node</p>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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:</p>
  
  <blockquote>
    <p>Sending 1 for ToF Data</p>
    
    <p>Reading data</p>
    
    <p>1 bytes read, buffer contains:</p>
    
    <p>Sending 2 for Thermal Data</p>
    
    <p>Reading data</p>
    
    <p>35 bytes read, buffer contains: <em>Thermal/ToF sensor data</em></p>
  </blockquote>
  
  <p>The code for the Arduino is as follows:</p>
  
  <pre><code>#include &lt;Wire.h&gt;
  #include &lt;VL53L1X.h&gt;
  #include &lt;Adafruit_AMG88xx.h&gt;
  
  
  
  #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 &lt; 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 &gt; 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 &lt; 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 &lt; 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 &lt;= AMG88xx_PIXEL_ARRAY_SIZE; i++) {
      if(i == (AMG88xx_PIXEL_ARRAY_SIZE)){
        Serial.println(pixels[i - 1]);
      }
      else{
        Serial.print(pixels[i - 1]);
      }
      if (i &lt; AMG88xx_PIXEL_ARRAY_SIZE) Serial.print(",");
    }
  
  }
  
  void PlayTone(int repetition, int duration, int hold){
    for (int j = 0; j &lt; repetition; j++){
      for (long i = 0; i &lt; 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 &lt; 8; j++) {
      for  (int h = 0; h &lt; 8; h++) {
        M_pixels[j][h] = 0;
      }
    }
    // if a pixel is above the temp threshold set to high
    for (int i = 0; i &lt; 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] &gt;= UpperThresh) {
        val = 5;
      }
      else if (pixels[i] &gt;= UpperMidThresh) {
        val = 4;
      }
      else if (pixels[i] &gt;= MidThresh) {
        val = 3;
      }
      else if (pixels[i] &gt;= LowerMidThresh) {
        val = 2;
      }
      else if (pixels[i] &gt;= 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 &lt; 8; i++) {
      for  (int j = 0; j &lt; 8; j++) {
        Serial.print(M_pixels[i][j]);
        Serial.print(',');
      }
      Serial.println(' ');
    }
  }
  
  void ToF_Read_Debug(){
  
    for (int i = 0; i &lt; 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 &lt;= 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();
  
  }
  </code></pre>
  
  <p>The code for the Jetson is:</p>
  
  <p>H file:</p>
  
  <pre><code> #include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;string.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;termios.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;stdbool.h&gt;
  
  #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);
  </code></pre>
  
  <p>C++ File:</p>
  
  <pre><code>    #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, &amp;toptions);
    /* set 9600 baud both ways */
    cfsetispeed(&amp;toptions, B115200);
    cfsetospeed(&amp;toptions, B115200);
    /* 8 bits, no parity, no stop bits */
    toptions.c_cflag &amp;= ~PARENB;
    toptions.c_cflag &amp;= ~CSTOPB;
    toptions.c_cflag &amp;= ~CSIZE;
    toptions.c_cflag |= CS8;
    /* Canonical mode */
    toptions.c_lflag |= ICANON;
    /* commit the serial port settings */
    tcsetattr(fd, TCSANOW, &amp;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 &lt; 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') &amp;&amp; (n == 2)) return 1;
  
  else return 0;
  
  
  }
  </code></pre>
  
  <p>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</p>