Project can run on Tinkercad but not Arduino IDE

Hi all.

I have an issue with my project.
I'm trying to make an RGB LED come out with a color typed in on the monitor by a user.

It's a project from toptechboy, that I'm following because I want to learn the programming of Arduino.
http://www.toptechboy.com/uncategorized/lesson-14-if-statements-and-conditionals-in-arduino/

When the color typed in by the user is sended from the monitor, the project is running past all if statements, exept the last one, which is for when a color is typed in, but not yet defined in the project.

The weird thing about this, is that the code is runnig as intended on Tinkercad, but I can't make it work from Arduino IDE or Arduino Web Creator.

I have tried on 2 different Arduino Uno boards(clones), 2 different computers and with 2 different USB cables. All with the same results.
Even if I copy/paste in the code from toptechboy, I get a similar result.

Can it be an issue related to the boards because they are clones? Or am i missing something?

Thanks in advance

Lesson14.ino (2.16 KB)

What have you got the Line ending set to in the Serial monitor ?

Anything except "No line ending" will add extra characters to the characters entered which may be interpreted as invalid user input

1 Like

(deleted)

What does the program print on Serial? It should echo what you sent to it.

UKHeliBob:
What have you got the Line ending set to in the Serial monitor ?

Anything except "No line ending" will add extra characters to the characters entered which may be interpreted as invalid user input

The program uses Serial.readString(), which reads characters until a timeout expires. Not a good choice, but then the program is a crock anyway...

UKHeliBob:
What have you got the Line ending set to in the Serial monitor ?

Anything except "No line ending" will add extra characters to the characters entered which may be interpreted as invalid user input

I made a while loop where I'm awaiting input from the serial monitor.

aarg:
What does the program print on Serial? It should echo what you sent to it.

Yes I also have set up the serial to echo what I'm typing in for color, and it gives the text I type in the monitor, so that part seems to be okay. Unless there is coming some invisible characters with the input

spycatcher2k:
Is your RGB led wored correctly, with current limiting resistors, and in the correct wiring for type - common Anode or common Cathode?

All is wired up correctly. My RGB has build in resistors.
And I can easily set up the different colours if I made a code with out the if statements

Did you try changing the line ending in the serial monitor, as suggested in reply #1?

When it echos input strings, does it double space (put an additional line between output lines)?

By the way, the code is garbage. It's supposed to teach conditionals, and uses them very amateurishly.

Bak81, I have to agree with aarg.
The problem is the Serial.readString(). I tested the sketch in Tinkercad and it worked. Somehow the Serial input of Tinkercad works better together with the Serial.readString().

We don't use the Serial.readString(), readBytesUntil() and so on, because it is not well defined if the result is a zero-terminated string and how it behaves when the buffer is full.

When you send a command, it can be "red", but there can be a linefeed and/or carriage return after it. For example "red\r\n".
When only sending "red" as three bytes 'r', 'e', 'd', then you have to rely on a timeout to detect that nothing else will follow.
A good sketch should detect the linefeed and/or carriage return and also have a timeout.

When you set the baudrate in the sketch to 9600, then you should also set the serial monitor to 9600 baud.

Can you test this ?
I have only tested it in Tinkercad :confused:

const int redLed = 6;     // set pin 6 to red LED
const int greenLed = 10;  // set pin 10 to green LED
const int blueLed = 11;   // set pin 11 to blue LED
String colorChoice;       // variable for holding user input
unsigned long previousMillis; // for timeout

void setup() 
{
  Serial.begin(9600);   //Open serial port to 9600baud

  //setup outputs
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);

  Serial.println("Please choose your color. (red, green, blue, cyan, purple, magenta or yellow )");   //Prombt user for color
}


void loop() 
{
  bool processColor = false;
  
  if( Serial.available() > 0)
  {
    int inChar = Serial.read();
    previousMillis = millis();   // timestamp the last received character
    if( inChar == '\n' || inChar == '\r' || inChar == '\0' || inChar == -1)
    {
      // Ignore the received character.
      // If something valid was received before, then start processing it.
      if( colorChoice.length() > 0)
      {
        processColor = true;
      }
    }
    else
    {
      // The received byte is probably good data, add it to the others.
      colorChoice += (char) inChar;
    }
  }

  if( colorChoice.length() > 0)  // busy with receiving data ?
  {
    if( millis() - previousMillis >= 200)  // nothing for 200 ms ?
    {
      processColor = true;  // start processing the data that was received up to now
    }
  }
  
  if( processColor)
  {
    Serial.println(colorChoice); // for checking the input

    if (colorChoice=="red")
    {
      analogWrite(redLed, 255);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 0);
    }
    else if (colorChoice =="green")
    {
      analogWrite(redLed, 0);
      analogWrite(greenLed, 255);
      analogWrite(blueLed, 0);
    }
    else if (colorChoice =="blue")
    {
      analogWrite(redLed, 0);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 255);
    }
    else if (colorChoice =="cyan")
    {
      analogWrite(redLed, 0);
      analogWrite(greenLed, 255);
      analogWrite(blueLed, 255);
    } 
    else if (colorChoice == "purple" )
    {
      analogWrite(redLed, 128);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 128);
    } 
    else if (colorChoice =="magenta")
    {
      analogWrite(redLed, 255);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 255);
    } 
    else if (colorChoice=="yellow")
    {
      analogWrite(redLed, 255);
      analogWrite(greenLed, 255);
      analogWrite(blueLed, 0);
    } 
    else
    {
      //no correct input from user
      Serial.println("");   //print blank line
      Serial.println("No valid color"); //Inform user about wrong input.
      Serial.println("");   //print blank line
    }
    colorChoice = "";  // clear the line
  }
}

The more I look at this sketch, the worse it is. Someone could keep on sending serial data, causing the heap to fill and crash the Arduino board. It would be better not to use the String object and use a normal array as buffer and check for overflow.

Koepel:
Bak81, I have to agree with aarg.
The problem is the Serial.readString(). I tested the sketch in Tinkercad and it worked. Somehow the Serial input of Tinkercad works better together with the Serial.readString().

We don't use the Serial.readString(), readBytesUntil() and so on, because it is not well defined if the result is a zero-terminated string and how it behaves when the buffer is full.

When you send a command, it can be "red", but there can be a linefeed and/or carriage return after it. For example "red\r\n".
When only sending "red" as three bytes 'r', 'e', 'd', then you have to rely on a timeout to detect that nothing else will follow.
A good sketch should detect the linefeed and/or carriage return and also have a timeout.

When you set the baudrate in the sketch to 9600, then you should also set the serial monitor to 9600 baud.

Can you test this ?
I have only tested it in Tinkercad :confused:

const int redLed = 6;     // set pin 6 to red LED

const int greenLed = 10;  // set pin 10 to green LED
const int blueLed = 11;  // set pin 11 to blue LED
String colorChoice;      // variable for holding user input
unsigned long previousMillis; // for timeout

void setup()
{
  Serial.begin(9600);  //Open serial port to 9600baud

//setup outputs
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);

Serial.println("Please choose your color. (red, green, blue, cyan, purple, magenta or yellow )");  //Prombt user for color
}

void loop()
{
  bool processColor = false;
 
  if( Serial.available() > 0)
  {
    int inChar = Serial.read();
    previousMillis = millis();  // timestamp the last received character
    if( inChar == '\n' || inChar == '\r' || inChar == '\0' || inChar == -1)
    {
      // Ignore the received character.
      // If something valid was received before, then start processing it.
      if( colorChoice.length() > 0)
      {
        processColor = true;
      }
    }
    else
    {
      // The received byte is probably good data, add it to the others.
      colorChoice += (char) inChar;
    }
  }

if( colorChoice.length() > 0)  // busy with receiving data ?
  {
    if( millis() - previousMillis >= 200)  // nothing for 200 ms ?
    {
      processColor = true;  // start processing the data that was received up to now
    }
  }
 
  if( processColor)
  {
    Serial.println(colorChoice); // for checking the input

if (colorChoice=="red")
    {
      analogWrite(redLed, 255);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 0);
    }
    else if (colorChoice =="green")
    {
      analogWrite(redLed, 0);
      analogWrite(greenLed, 255);
      analogWrite(blueLed, 0);
    }
    else if (colorChoice =="blue")
    {
      analogWrite(redLed, 0);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 255);
    }
    else if (colorChoice =="cyan")
    {
      analogWrite(redLed, 0);
      analogWrite(greenLed, 255);
      analogWrite(blueLed, 255);
    }
    else if (colorChoice == "purple" )
    {
      analogWrite(redLed, 128);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 128);
    }
    else if (colorChoice =="magenta")
    {
      analogWrite(redLed, 255);
      analogWrite(greenLed, 0);
      analogWrite(blueLed, 255);
    }
    else if (colorChoice=="yellow")
    {
      analogWrite(redLed, 255);
      analogWrite(greenLed, 255);
      analogWrite(blueLed, 0);
    }
    else
    {
      //no correct input from user
      Serial.println("");  //print blank line
      Serial.println("No valid color"); //Inform user about wrong input.
      Serial.println("");  //print blank line
    }
    colorChoice = "";  // clear the line
  }
}




The more I look at this sketch, the worse it is. Someone could keep on sending serial data, causing the heap to fill and crash the Arduino board. It would be better not to use the String object and use a normal array as buffer and check for overflow.

The code works perfect. But now it is way of how this teacher, toptechboy was doing it. I can see I have to read up on some of the codes you used. I want to understand them and know the exactly meaning of them, so I can use them myselve in a given situation.

Thank you for your time and help

aarg:
Did you try changing the line ending in the serial monitor, as suggested in reply #1?

When it echos input strings, does it double space (put an additional line between output lines)?

By the way, the code is garbage. It's supposed to teach conditionals, and uses them very amateurishly.

Hi aarg.

Sorry for being a little slow in my mind. I just found out what you meant about changing the line ending. Thought it was some sort of code i need to write into my program, but i found out it was in the serial monitor(as you wrote). After doing this, my own code also worked.

Thank you very much

Did you miss reply #1 ?

UKHeliBob:
Did you miss reply #1 ?

UKHeliBob:
What have you got the Line ending set to in the Serial monitor ?

Anything except "No line ending" will add extra characters to the characters entered which may be interpreted as invalid user input

That was the issue. I wasn't aware of the different setups in the serial monitor. Only the one about baudrate.

Thank you very much

I suggest you drop that channel. The only thing you can learn there is bad programming habits.