Controling a servo with data received from PC

Hello everyone,

I'm working on a project where a have to control several servos with diferents scenarios, that I send via PC to the arduino. In the PC I created a program with VS that send the scenarios that are in a .txt file. In the arduino I store the file in a buffer and then I convert it into a String.

Now that's where my trouble begins, I can only move it once, it means I can only send one line to make the servo move. My question is, how can I send one line at a time with a String. Is it possible?

Here is the code, only the scenario part, of course:

Servo myservo;
String readString, servo1, servo2;

bool scenario1 = false;
bool scenario2 = false;
bool scenario3 = false;
char line;

 if (scenario1 && scenario2 && scenario3)
  {
    scenario1 = false;
    scenario2 = false;
    scenario3 = false;
    Serial2.println("SCENOK");
    Serial.println("SCENOK");
  }
 case '5': // reception scenario1
      scenario1 = true;
      scenario();
      break;

void scenario()   //lecture des scenarios
{
  for (int y = scen_min; y < scen_max; y++)
  {
    if (buffer[y] != ' ');
    line = buffer[y];
    Serial.print(line);   
    readString += line;
  }
}

void start_servo()  //mouvement des servos
{
  if (readString.length() > 0)
  {
    int x = 9;
    for (int i = 0; i < readString.length(); i++)
    {
      servo1 = readString.substring(0, i);
      //servo2 = readString.substring(x, x+9);
      Serial.println(servo1);
      //Serial.println(servo2);
      float n = servo1.toFloat();
      //n = servo2.toFloat();

      if (n <= 1)
      {
        pos = (n * 1000) + 1000;
      }
    }

    //readString = "";

This is what I tried until now.
If someone could help me, I really apreciate it

Jonathan

it is the most common habit of newbees to just post a part of their code.
In 95% of all cases the bug sits somewhere else than assumed.

So the bare minimum is to post your complete sketch. If you want to speed up solving your problem through getting good answers you add a description in normal words what your servos shall do.

Does "scenario" mean just rotate to a certain position?

or does "scenario" mean multiple servos must run down multiple speed-controlled movements in sync ?

We are talking about details. Please give an overview over your whole project.
in mimimum 70% of all cases knowing the whole thing offers completely different and much better working solutions.
This is like

Newbee: "I want to do better cutting please help me sharpening. "
Expert: Sure I can help you what cutting-tool are you using?
Newbee: a scissor.
Expert: OK take this sharpening tool
Newbee: Yea works great Next question How can I make it cut faster I need to finish faster.
expert: Motorised scissors.
newbee Yea works great though still not fast enough.

expert: Ok can you give an overview about what you are cutting.
newbee: the green of a football-arena.
expert: Oha! take a big mowing tractor with a seven boom spindel-mower and GPS-steering

In the beginning the newbee always just told details.
The expert was assuming the newbee knows that his basic approach is well suited.
which turns out to be very bad suited
that's the reason why it is always a good idea to give an overview and to explain what shall happen in the end.

best regards Stefan

then I convert it into a String.

Why ?

If you choose a suitable format for the messages then you do not need to convert the received data. Take a look at Serial input basics - updated for ideas, including parsing the received string (lowercase s)

UKHeliBob:
Why ?

This is the data I receive from the PC, from txt file.

1.00000005

-0.0040815

-0.0040815

-0.0040815

-0.0020405

-0.0020405

-0.0040815

-0.0040815

-0.0040815

-0.0040815

-0.0040815

-0.0040815

-0.0040815

-0.0040815

-0.0040815

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

1.00000005

0.96938775

0.92244895

0.80204085

0.64081635

0.44693875

0.23673466

And the reason I thought about convert it to a String was because of the formula that I use here:

if (readString.length() > 0)
  {
      int x = 9;
  
      servo1 = readString.substring(0, x);
      //servo2 = readString.substring(x, x+9);
      Serial.println(servo1);
      //Serial.println(servo2);
      float n = servo1.toFloat();
      //n = servo2.toFloat();

      if (n <= 1)
      {
        pos = (n * 1000) + 1000;
      }
    }

It those the right thing, but only with one line and moves the servo only once.

Using the data received in your example how does the Arduino know which servo to move, where to move it to and when it should be moved ? Please provide an interpretation of the data or better still change the format to make it more explicit. What would a typical scenario consist of ? Are you controlling a robot arm by any chance ?

the reason I thought about convert it to a String was because of the formula that I use here

You have that back to front. If you saved the data as a string (lowercase s) then you would not (could not) use those functions but other methods are available

Hello friend,
Is the servo mechanical?

usually servos are positioned either by

.write(posDegrees);

or by

 .writeMicroseconds()

The code you have provided so far shows nothing about

  • how the variables servo1, servo2 are defined
  • how the received values are processed and how the commands look like

So these are additionally reason to post your entire sketch from the very first line
to the very last line easiest way to do so is

press Ctrl-T inside aurduino-IDE
do a right-click with the mouse
choose copy for forum
paste clipboard-content into a posting

best regards Stefan

Yes, you are right. I'll post the code, just the part needed because the rest is for other things other than the servos.
What this program is meant to do is, receive a scenario with various servo movements from 1 to 2ms, that's why those values from the data received. The timestamp for the servo movement is 20ms.

This is where i declare all the variables needed and the buffer for data received from the PC

Servo myservo;
String str, servo1, servo2;

char buffer[100];  //buffer for serial data receive from PC

bool scenario1 = false;
bool scenario2 = false;
bool scenario3 = false;
char line;

This is where I process the incoming data

void ReadDataPC (const byte inByte)
{
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
  {

    case '\n':   // end of text

      buffer [input_pos] = '\n';  // terminating null byte

      // terminator reached! process input_line here ...
      DataPC();

      // reset buffer  next time
      input_pos = 0;
      break;

    case '\r':   // discard carriage return


      break;

    default:     // keep adding if not full ... allow  terminating null byte

      if (input_pos < (MAX_INPUT - 1))
        buffer [input_pos++] = inByte;
      break;

  }  // end of switch

} // end of processIncomingByte

void DataPC()
{
  Serial.println(buffer[0]);
  switch (buffer[0])  // premier case de data recu determine dans quelle cas de config on se trouve
  {
    case '0':   //reception des trame configuration
      configuration();
      break;

    case '1': // cas ou l'operateur n'a pas recu le premier sms on renvoye a nouveau
      Send_msg(_message);
      break;

    case '2': //
      config_gsm ();
      break;

    case '3': // cas ou la config gps a echoué on refait une tentative
      config_gps ();
      break;

    case '4': //
      config_servo ();
      break;

    case '5': // reception scenario1
      scenario1 = true;
      scenario();
      break;

    case '6': //reception scenario2
      scenario2 = true;
      break;

    case '7': // reception scenario3
      scenario3 = true;
      break;

    case '8': // start
      Serial2.println( "STARTOK");
      startOK = true;
      Serial.println( "STARTOK");
      start_enrg = true;
      break;

    case '9': // stop
      Serial2.println( "STOP");
      Serial.println( "STOP");
      startOK = false;
      compteur10 = 0;
      start_enrg = false;
      send_enrg = false;
      break;

    case 'A': // SI LE PC REPOND PRESENT IL PEU ENVOYER LES ENREGISTREMENTS
      send_enrg = true;
      Serial.println("RECU A");
      break;

  }

Here is where I go look in the buffer if the file is correctly stored and where I got stuck

void scenario()   //lecture des scenarios
{
  for (int y = scen_min; y < scen_max; y++)
  {
    if (buffer[y] != ' ');
    line = buffer[y];
    str += line;
    Serial.print(line);
  }
}

Here is where I try to make the servo move, right now I'm just trying with one servo

void start_servo()  //mouvement des servos
{
  /*if (str.length() > 0)
  {
      int x = 9;
  
      servo1 = str.substring(0, x);
      //servo2 = readString.substring(x, x+9);
      Serial.println(servo1);
      //Serial.println(servo2);
      float n = servo1.toFloat();
      //n = servo2.toFloat();

      if (n <= 1)
      {
        pos = (n * 1000) + 1000;
      }
    }

    str = "";
*/
    /*if (currentMillis - previousServoMillis >= servoInterval)
    {
      previousServoMillis += servoInterval;

      servoPosition = servoPosition + servoDegrees;

      if (servoPosition <= servoMinDegrees)
      {
        if (servoInterval == servoSlowInterval)
        {
          servoInterval = servoFastInterval;
        }
        else
        {
          servoInterval = servoSlowInterval;
        }
      }
      if ((servoPosition >= servoMaxDegrees) || (servoPosition <= servoMinDegrees))
      {
        servoDegrees = - servoDegrees;
        servoPosition = servoPosition + servoDegrees;
      }
      myservo.writeMicroseconds(servoPosition);
    }*/


  if(str.length() > 0)
    {
    servo1 = str.length();
    Serial.println(servo1);
    float n = servo1.toFloat();

    if(n <= 1)
    {
      pos = (n * 1000) + 1000;
      Serial.println(pos);
      myservo.writeMicroseconds(pos);
    }
    str = "";
    }
}

I just send this part of the code, because all the rest as nothing to do with it and works fine
Hope it help you see where I'm wrong

I suggest that you provide a complete example of the receipt and resulting action of servo commands so that we see exactly what you are doing and how. By all means leave out the parts of the code which do not deal with the servo but make sure that the code compiles

In the little snippets you insist on sending you have only one servo. It is never attached to a pin. 95% of the code in start_servo() is commented out so it's not surprising it doesn't do much. The bit that's left in is useless.

If you want help a complete, compilable program that demonstrates your problem would be useful. Anything else would not.

Steve

I second what slipstick wrote.

additional: what you call a "scenario" is simply a single RC-Servo-control-pulse which boils down to a single rectangular-pulse of lenghtes between 1,0 milliseconds and 2,0 milliseconds.
Where of course to keep a servo in position this rectangular pulse must be repeated every 20 milliseconds.
But that is done for you in the backround by the servo-library.

The pulse itself
1,0 milliseconds represents turn servo-horn to the min-position
1,5 milliseconds represents turn servo-horn to the middle-position
2,0 milliseconds represents turn servo-horn to the max-position

I recommend using the common words to be easier to understand.

Of course you can go on trying to "solve" your problem inside your fully code.
I don't recommend that. Modifying your complete code means there are a lot of places that can cause bugs
and you have to check through a lot of more things because you have to check all the combinations.

I recommend the opposite. Write a small testprogram that does nothing more than receiving your string
convert it to an integer representing microseconds and print out this value to the serial monitor.

If this works reliable make it a function "receiveMicroSecs" or whatever name you like.
Then add the function that hands over this value to put the servo in position.

Some people seem to prefer beeing hectical busy hopping around trying this trying that to slow down their progress in finishing their project.

This thread offers some additional things to learn:
expanding your own capabilities in changing your posting / working-style to the way you were asked for.
This is an expansion. Of course you can keep the way you have done it in the postings before.

This is just an offer: Of course you are still free to do whatever you want.

best regards Stefan

I would recommend replacing your String based code with my SafeString replacement library (from the Arduino library manager)
Lots of examples include with the library.
All the methods are non-blocking so they will not interfer with the rest of your loop.
See a detailed tutorial here