Why doesn't the port.write() work when placed inside the setup() function? Processing doesn't get serial data back from Arduino

I’m using processing with an Arduino UNO for my application. I’m making an adaptive traffic light system and for that, I’ve implemented a primitive graphic display in processing. In this, the processing code reads the number of cars in two lanes from a text file and send over this data to the Arduino, which then calculates the red light time for each lane and sends back the time to the processing program for displaying the timer.

Here is the processing code:

import processing.serial.*;
Serial port;
int lane1_on = 1;
float delay_light = 0;
int[] data_arr = {}; //no. of cars in lane 0 and lane 1 from text file
String data_str = "";
int index = 0;
PFont font;
int[] no_of_vehicles;
boolean flag = true;
String[] stuff = {};

void setup()
{
  size(1000,1000);

  font = loadFont("AgencyFB-Bold-200.vlw");
  textFont(font, 200);
  stuff = loadStrings("data.txt");
  data_arr = int(split(stuff[0], ','));
  port = new Serial(this, "COM4", 9600);
  port.bufferUntil('\n');
  port.write(data_arr[0]);
  port.write(data_arr[1]);
}

void draw()
{
  background(255,255,255);
  fill(0, 0, 0);
  text("lane 1", 50, 300);
  fill(0, 0, 0);
  text("lane 2", 600, 300);
  fill(0, 0, 0);
  text("timer", 325, 700);

  if(lane1_on==1){

  //lane1
  fill(0, 0, 0);
  text(".", 50, 40);
  fill(0, 255, 0);
  text(".", 50, 120);

  //lane2
  fill(255, 0, 0);
  text(".", 750, 40);
  fill(0, 0, 0);
  text(".", 750, 120);
  } else {


  //lane1
  fill(255, 0, 0);
  text(".", 50, 40);
  fill(0, 0, 0);
  text(".", 50, 120);

  //lane2
  fill(0, 0, 0);
  text(".", 750, 40);
  fill(0, 255, 0);
  text(".", 750, 120);
  }

  fill(0, 0, 0);
  text(delay_light, 150, 900);
  delay(1000);
  if(delay_light>0){
    delay_light--;
  }
}

void serialEvent (Serial port)
{
  if (port.available() > 0){
  data_str = port.readStringUntil('\n');
  println(data_str);
  data_str = data_str.substring(0, data_str.length() - 1);
  index = data_str.indexOf(",");
  lane1_on = int(data_str.substring(0, index));
  println(lane1_on);
  delay_light = float(data_str.substring(index+1, data_str.length()));

  stuff = loadStrings("data.txt");
  data_arr = int(split(stuff[0], ','));
  port.write(data_arr[0]);
  port.write(data_arr[1]);
  }
}

Here is the Arduino code:

int cars_in_lane1;
int cars_in_lane2;
int delays[] = {1,1}; //[lane1_delay, lane2_delay]
int lane1 = 1;
int lane2 = 2;

void setup() {
  Serial.begin(9600);
}

void loop() {
  while (Serial.available() == 0);
  cars_in_lane1 = Serial.parseInt();
  while (Serial.available() == 0);
  cars_in_lane2 = Serial.parseInt();

  delays[0] = timer_function(cars_in_lane1);

  Serial.print("1,");
  Serial.println(delays[0]);

  delay((delays[0])*1000);
  while(Serial.read() >= 0);
  delays[1] = timer_function(cars_in_lane2);

  Serial.print("0,");
  Serial.println(delays[1]);

  delay((delays[1])*1000);
}

float timer_function(int no_of_cars){
  if(no_of_cars <= 15){
    return 30;
  } else {
    return (2*(no_of_cars-15)) + 30;
  }
}

With this, my timer is stuck at 0 count and doesn’t even start as it doesn’t receive back anything from the Arduino, as I’ve checked from console logging in the processing code in the SerialEvent() function.

I don’t want to place the port.write() in the draw() function as it will send the data every time draw() loops and fill up the buffer with redundant data. But, I only seem to get back any data from the arduino when I use it this way, as I have checked by console logging a message in my serialEvent() function. I even tried using a flag as in this code, inside draw() :

if (flag){
  stuff = loadStrings("data.txt");
  data_arr = int(split(stuff[0], ','));
  port.write(data_arr[0]);
  port.write(data_arr[1]);
  flag = false;
  }

so that the port.write() sends data only once to the Arduino. But this gives the same result of Arduino not sending anything back. It seems to not write to the port every time it is run, even inside the draw() function.

I tried running the Arduino code alone and sending it the same data through the serial monitor and it works correctly.

I think my problem may be similar to this thread - Write and read to Serial port at the same time

What can be done to solve this and why is processing behaving like this?

Btw, I’ve also posted this on StackOverflow, you can check that thread here - https://stackoverflow.com/questions/62411094/why-doesnt-the-port-write-work-when-placed-inside-the-setup-function-proce

1 Like

I don’t think I will be able to pin point your issue. I will suggest by starting with the following revision of your code:

void serialEvent (Serial port)
{
  data_str = port.readStringUntil('\n');
  String[] tokens = split(data_str,',');
  lane1_on =tokens[0];
  delay_light=float(tokens[1]);

   //SEE note 3
  stuff = loadStrings("data.txt");
  data_arr = int(split(stuff[0], ','));
  port.write(data_arr[0]);
  port.write(data_arr[1]);  
}

Note:

  1. Serial Event fires when there is some data. No need to check if there is data available in the port. Check the reference: Serial Event
  2. Use split() as it makes your code more readable
  3. It is not clear what you are doing here by loading the file in this function. Can you share the content of this file, or a snipet to show its structure? I think you are better to load the file only once in setup and then you manage the data here in the serial event. There is no information about the logic of your program, so it will help if you briefly exaplain what these few lines suppose to do.

Finally, it is not recommend it to have a delay() inside the draw() function. You can slow down your sketch using frameRate() or control the execution of each frame using noLoop()/redraw() functions. You can call 'redraw()inside theserialEvent()` if that suits your use case.

Kf

1 Like

Hi @wasd808

Welcome to the community! :slight_smile:

I have not tested your code, but check https://learn.sparkfun.com/tutorials/connecting-arduino-to-processing/all
Maybe something like a handshake protocol will be useful for you. That way, you can send the data for processing and establish a contact between Arduino and Processing.

Also, like @kfrajer I am not understanding why are you loading a file. Maybe if you share it we can test and try to help you :slight_smile:

1 Like

My bad, I didn’t write the logic of my code, here it is:
The Arduino first sets up and waits for any serial data to come in. Processing is supposed to read the number of cars in two lanes which are stored in the data.txt file as just two comma-separated integers in the setup(). It then parses it and sends it to Arduino through serial. Arduino gets these values and calculates the green light time for lane 1 based on number of cars in it using timer_function() and sends two comma-separated integers to processing in this format:

(is lane 1 light to be turned green? integer 1 for yes, 0 for no),(countdown duration)

and then waits to read another input from processing after that amount of delay. Processing parses the lane 1 and delay comma-separated string in serialEvent() and then updates the number of cars from the data.txt file and writes it back to Arduino for it to do the same thing all over, for turning lane 1 light red.
In draw(), I’ve shown the red and green lights using full stops, and there is a countdown timer according to the delay received, for lights to switch again.

The first read of data.txt in setup() was to start a communication with Arduino so that I can catch the reply in the serialEvent() and then send the new values from data.txt in it. Another program is updating that file.

Here is what the processing app is supposed to look like:

I’ll try the handshake protocol thing and these changes that you recommend, and reply again.

1 Like

I do not understand what is the role of the arduino here. Would it do something else beside returning those values?

  • I recommend you move all your logic to Processing. It simplifies your program by allowing it to run without depending on an arduino unit. This makes it easier to debug and even to reproduce by community members here.
  • You are using your arduino as a worker meaning you are giving it a task to complete and report back. If you need an arduino in your use case, use it as a slave then. For example, if you need to use an arduino to control an external process using IO logic, then command your arduino to do something from Processing. Processing would be doing all the logic calculation and commands the arduino whenever it is required.
  • Do not use delay() inside your draw loop as this is blocking draw. Using your “flag” approach is the way to go here. Make sure you name the flag something meaningful as flag is a generic term.
  • I would also drop the text file in your code. You can manage the data in memory and set the initial values in setup(). From what I understand, you are only reading the first line of the text file.

Kf

1 Like

I used the frameRate() function instead of the delay, and moved all of my code to processing. Thanks! this worked. I had decided to use Arduino because I was thinking to do this with LEDs and a LCD too, but I don’t need that anymore in my application. Will try the handshake protocol too, if I need to hook-up any hardware I/O to it. Thanks!

1 Like