1
votes

I want to turn ON and OFF, three LEDS connected to arduino, using a python GUI, thus I use pyserial. The state of the LEDs is described by a tuple

RGB = (Red On/Off, Green On/Off, Blue On/Off), e.g. (1,0,1)

Since pyserial.write() works only with strings, let's say that RGB = "101"

I want to sent to arduino the RGB string, split it to three values 1, 0 and 1, and set LOW or HIGH three output pins, depending on the incoming values.

The python code works fine:

import serial
ser = serial.Serial('/dev/ttyACM4', 9600)
ser.write('101')

This is the arduino code:

void setup() {
Serial.begin(9600); 
Serial.println("Ready");
}

void loop() {
  char input_data = ' ';

  if(Serial.available()){ 
      char input_data = {Serial.read()}; 
      Serial.println(input_data); 
  }
delay(100); 
}

The print line is only for inspection purpose.

Can I somehow split the input_data string, and retrieve its values, like:

int R = input_data[0];   
int G = input_data[1];   
int B = input_data[2];   

Any suggestion would be appreciated.

1
Is your Serial.println printing the whole line, or just one character?gankoji
Looking at the Arduino documentation, you should only be getting a single int out of serial.read(). I don't have my arduino lying around to test, but I'd suspect it's the ASCII value of the characters you're getting, in which case you'd have to convert to numeric values before using them to drive pins.gankoji
I get 1 (new line), 0 (new line), 1 (new line). I suspect that the Serial.print line is executed three times, each for every value.user3060854

1 Answers

1
votes

OK, so one quick clarification here (as verified by your comment): input_data is not a string, it is a single char (one byte). Also, serial.read() returns a single byte (the next in the serial stream) and does so as an int, so you're implicitly casting int to char in your code. This is fine, just wanted to make that clear.

What you can do is make input_data an array of chars, and store each new byte in a new location in the array. Then you'll have all three numbers you're looking for. Then, all that's left is to turn input_data[i] into a LOW or HIGH value to be passed to each of your LED pins. What I would do is within your for loop, test each value read from the serial.read() function to see if it's value is '0' or '1' and then storing true or false in another array of bools. Finally, you can test that array and set the corresponding pin 'HIGH' or 'LOW' as necessary. Please keep in mind what I mentioned earlier in the comments, that you're going to want to test the received data as the characters 1 and 0 and not the numbers 1 and 0.

Here's a quick snippet as an example:

int[3] pins; //Initialize this to contain the numbers of the R, G, and B pins. 

void setup() {
    Serial.begin(9600); 
    Serial.println("Ready");


}

void loop() {
    char[3] input_data;
    bool[3] low_high;

    if(Serial.available() >= 3){
         for (int i=0; i<3; i++) {
             input_data[i] = Serial.read();

             if(input_data[i] == 48) //ASCII for 0
                 low_high[i] = false;

             if(input_data[i] == 49) //ASCII for 1
                 low_high[i] = true;

             //Serial.println(input_data);
         } 
    }

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

        if(low_high[j]) {
            digital_write(pins[j],'HIGH');
        } else {
            digital_write(pins[j], 'LOW');
        }
    }
    delay(100); 
}

That should get you up and running. Please keep in mind that this example has very limited input checking, so you'll need to beef it up a bit (i.e. checking for more than 3 bytes ready, making sure you're getting char's and not gibberish, etc.).