Sending Full Words from Serial Monitor

Hi

I have been trying to figure out a way to send a full word from the serial monitor to the Arduino to turn something on or off. In this case, I am trying to turn an LED on or off by entering true or false. I successfully did this with a single character. Also, what if you want to include a second criteria, say PWM data following true or false. I.e. true, 255.

Thanks

int ledPin = 13;
char trueState[] = "true";
char falseState[] = "false";
char ledState[5];

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

void loop()
{
  if(Serial.available())
  {
    Serial.read = ledState[];
    if(ledState[5] == trueState[])
    {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED on.");
    }
    if(ledState[5] == falseState[])
    {
      digitalWrite(ledPin, LOW);
      Serial.println("LED off.");
    }
  }
}

You need to define a command packet, and a piece of code that reads a complete packet. How do you know its complete? The trick is to add a separator that is no part of the command. Example

true,255# false,113# Note that the , functions as separator

You need something like this readCommand() [not tested] to read one complete command; then you can split command into fields ( search for strtok() example )

int readCommand()
{
  char lastchar = ''';
  int i= 0;
  while (lastchar != '#')
  {
    if (Serial.available()>0)
    {
      lastchar = Serial.Read();
      if (lastchar == #) 
      {
         command[i] = '\0'; 
      } else command[i++] = lastchar;
    }
  }
}

Hopes this helpes

The below is for servos, but you should be able to modify it to your needs. Send your info in a string to the arduino, and then using the string functions, parse out the info you want to use. The number part of the string is captured and is turned into an integer to control a servo (you would do similar for PWM).

// zoomkat 11-22-10 serial servo (2) test
// for writeMicroseconds, use a value like 1500
// for IDE 0019 and later
// Powering a servo from the arduino usually DOES NOT WORK.
// two servo setup with two servo commands
// send eight character string like 15001500 or 14501550

#include <Servo.h> 
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo 
Servo myservo2;

void setup() {
  Serial.begin(9600);
  myservo1.attach(6);  //the pin for the servo control 
  myservo2.attach(7);
  Serial.println("servo-test-21"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    delay(1);  
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }

  if (readString.length() >0) {
      Serial.println(readString); //see what was received
      
      // expect a string like 07002100 containing the two servo positions      
      servo1 = readString.substring(0, 4); //get the first four characters
      servo2 = readString.substring(4, 8); //get the next four characters 
      
      Serial.println(servo1);  //print to serial monitor to see results
      Serial.println(servo2);
      
      int n1; //declare as number  
      int n2;
      
      char carray1[6]; //magic needed to convert string to a number 
      servo1.toCharArray(carray1, sizeof(carray1));
      n1 = atoi(carray1); 
      
      char carray2[6];
      servo2.toCharArray(carray2, sizeof(carray2));
      n2 = atoi(carray2); 
      
      myservo1.writeMicroseconds(n1); //set servo position 
      myservo2.writeMicroseconds(n2);
    readString="";
  } 
}

Awesome! Thanks. That answers my question about multiple parameters. Does anybody know about how to send a single word from the serial monitor to do something? What would data type would it be?

Thanks!

Does anybody know about how to send a single word from the serial monitor to do something?

You need to give an example of "a single word". The word "word" has multiple meanings, including some that are specific to Microslop operating systems.

A word like "on" or "off" sent via serial

A word like “on” or “off” sent via serial

You mean an array of characters like “on” or “off”.

First question to ask yourself is how will you know, when reading the characters one at a time from the serial port, using Serial.read(), that you have read the last character in the “word”?

And end-of-packet marker will be essential to know when to stop reading and when to start parsing what you have read.

char inData[10];
byte index = 0;
char EOP = ';';

void loop()
{
  while(Serial.available() > 0)
  {
     char inByte = Serial.read();
     if(index < 10)
     {
        inData[index] = inByte;
        inData[index+1] = '\0';
     }
  }

  if(inData[index] == EOP)
  {
    // Parse and use the data
    if(strcmp(inData, "on")
        // Do whatever on means
    else if(strcmp(inData, "off")
        // Do whatever off means

    inData[0] = '\0';
    index = 0;
  }
}

Some simple code that might be of interest.

// zoomkat 8-6-10 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

String readString;


void setup() {
    Serial.begin(9600);
        pinMode(13, OUTPUT);
        Serial.println("serial test 0021"); // so I can keep track of what is loaded
        }

void loop() {

        while (Serial.available()) {
        delay(1);  
      char c = Serial.read();
        readString += c; 
        }
        
      if (readString.length() >0) {
      Serial.println(readString);
     
    if (readString == "on") {
    digitalWrite(13, HIGH);
        Serial.println("Led On");
    }
   if (readString == "off") {
    digitalWrite(13, LOW);
        Serial.println("Led Off");
    }
        readString="";
   } 
}

OK. I have integrated the strcmp into my RC car code. My question is, I’d like to add to other criteria to be entered in—a pwm speed, and an amount of time (in milliseconds). How would I set this up?
(As you can see, I already set up a byte for the speed, and an int for the duration. I understand that I’ll probably have to do a little math to convert the duration to milliseconds for the delay function.)

#include <AFMotor.h>

AF_DCMotor motor1(1);
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

AF_DCMotor allMotors[4] = {
  motor1, motor2, motor3, motor4};
AF_DCMotor rightSide[2] = {
  motor1, motor2};
AF_DCMotor leftSide[2] = {
  motor3, motor4};

byte inputSpeed;
AF_DCMotor controlSet[3] = {
  allMotors[4], rightSide[2], leftSide[2]};
int duration;
char EOP = ';';
byte index = 0;
char inData[9];


void setup()
{
  Serial.begin(9600);
  Serial.println("RC Car Project Mark I connected.");
}

void loop()
{
  while(Serial.available() > 0)
  {
    char inByte = Serial.read();
    if(index < 9)
    {
      inData[index] = inByte;
      inData[index+1] = '\0';
    }
    if(inData[index] == EOP)
    {
      if(strcmp(inData, "forward"))
      {
        allMotors[4].run(FORWARD);
        Serial.println("Moving backward...");
      }
      if(strcmp(inData, "backward"))
      {
        allMotors[4].run(BACKWARD);
      }
    }
  }
}
AF_DCMotor controlSet[3] = {
  allMotors[4], rightSide[2], leftSide[2]};
        allMotors[4].run(FORWARD);

This code won't work. The range of indices for the allMotors array is 0 to 3. 4 is not in that range. The other indices are wrong, too.

If you want to send something like "forward, 10, 100;" to make the device move forward at a speed of 10 for 100 milliseconds, you'll need to collect all the data into the array (which will obviously need to be larger), and then use strtok() to parse the inData array. Each token will be used for a different purpose. The atoi() function will bear looking into, too.

I tried making the array controlSet[4], but it won’t let me. The reason I have the control set is to encompass the four main functions—forward, backward, and turning.

It's not the size of controlSet that is a problem. The array is currently sized to hold 3 objects of type AF_DCMotor.

4 is not a valid index into the allMotors array, so whatever follows the allMotors array in memory, which is most likely NOT a AF_DCMotor object is what will be stored in the first position of the controlSet array. That block of memory will most likely NOT respond correctly to an attempt to invoke its run function.

So how would I initialize an array that properly encompasses those items? :blush:

So how would I initialize an array that properly encompasses those items?

Depends on which item in each of the three existing arrays you want the new array to point to.

I don't see that controlSet is doing anything useful for you. Please explain it's function.

ControlSet is basically encompassing the three different arrays. I thought that it would be used for one of the criteria—forward, backward, right, left—but it may not be needed.

ControlSet is basically encompassing the three different arrays. I thought that it would be used for one of the criteria—forward, backward, right, left—but it may not be needed.

You've only got 4 motors, and they are already all defined in allMotors, and some are duplicated in rightSide and leftSide.

I can't see a use for controlSet. As a result, I can't see how to define or initialize it.

You're definitely right. I thought that I would need controlSet in the array that I am pulling data from. But I want to make allMotors = "forward" or "backward". Could you please explain WHAT index, EOP, and inData[9] are actually doing? How would I implement extra criteria like the speed and time in the strcmp function?

OK. I think I might be on to something, but I’m getting a lot of error messages saying things like "invalid conversion from ‘char’ to ‘const char*’.
Also, does EOP stand for the separator between criteria?
Here is my code:

#include <AFMotor.h>

AF_DCMotor motor1(1);
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);

AF_DCMotor allMotors[4] = {motor1, motor2, motor3, motor4};
AF_DCMotor rightSide[2] = {motor1, motor2};
AF_DCMotor leftSide[2] = {motor3, motor4};

byte inputSpeed;
int duration;
char EOP = ';';
byte index = 0;
char inData[9];



void setup()
{
  Serial.begin(9600);
  Serial.println("RC Car Project Mark I connected.");
}

void loop()
{
  while(Serial.available() > 0)
  {
    char inByte = Serial.read();
    if(index < 9)
    {
      inData[index] = inByte;
      inData[index+1] = '\0';
    }
    if(inData[index] == EOP)
    {
      if(strcmp(inData, EOP, inputSpeed, EOP, duration))
      { 
        if(inData == "forward")
        {
          allMotors[4].setSpeed(inputSpeed);
          allMotors[4].run(FORWARD);
          Serial.println("Moving forward...");
          delay(duration);
        }
        if(inData == "backward")
        {
          allMotors[4].setSpeed(inputSpeed);
          allMotors[4].run(BACKWARD);
          Serial.println("Moving backward...");
          delay(duration);
        }
      }
      if(strcmp(inData, EOP))
      {
        if(inData == "right")
        {
          rightSide[2].setSpeed(100);
          rightSide[2].run(FORWARD);
          Serial.println("Turning right...");
          delay(1000);
        }
        if(inData == "left")
        {
          leftSide[2].setSpeed(100);
          leftSide[2].run(FORWARD);
          Serial.println("Turning left...");
          delay(1000);
        }
      }
    }
  }
}
      if(strcmp(inData, EOP, inputSpeed, EOP, duration))

The strcmp() function takes two arguments - the strings to compare. You are trying to call it with 4 arguments.

Once you have the complete string (and, no, EOP is not the separator - it is the end of packet marker. You need a different separator), you need to call strtok() to extract the tokens (the strings that contain the command, the speed, and the duration). Once you have the tokens, you need to see if the command is something ("forward" or "backward"). If so, you might need to convert the speed and duration tokens to ints (using atoi()). I would not expect all commands to have speed and duration associated with them. "stop" hardly needs to know how fast to stop.

          allMotors[4].setSpeed(inputSpeed);

You only have 4 motors. The indices (the values in the []) are 0 to 3. You can't make all 4 motors do something using a command like this. You need 4 separate statements to make all 4 motors do something.

Could you please give a code example of the extraction of those things from the strcmp() function? What about atoi()? How would that be set up?