etch-a-sketch continuous servo code issue

ok so i have two parallax continuous servos, and i easily made them turn using the sweep sample program. then i hooked them up to a etch-a-sketch and they make a continuous repeated pattern(still using sweep program).

but then i tired to write a program to control them over serial. i would send some thing like: <U,0500,> over serial to go up on the etch-a-sketch for 500ms. after i program the arduino and start the program but before i send that line(<U,0500,>) to the arduino over serial, one of the two servos start turning by its self. i added a serial.print line before when the servos(s) are actually supposed to turn to see if the code is some how "skipping" the serial stuff.

thanks

CODE:

#include <Servo.h>

Servo Xaxis;
Servo Yaxis;

int started = 0;
int inData[9];
int ended = 0;
char index = 0;
int final = 0;

void setup()
{
  Xaxis.attach(5);
  Yaxis.attach(6);

  Serial.begin(9600);
}

void loop()
{
  while(Serial.available() > 0)
  {
    char aChar = Serial.read();
    if(aChar == '<')
    {
      started = true;
      index = 0;
      inData[index] = '\0';
    }
    else if(aChar == '>')
    {
      ended = true;
    }

    else if(started)
    {
      inData[index] = aChar;
      index++;
      inData[index] = '\0';             
    }

    else if (aChar =='*')
    {
      final = true;
    }
  }

  if(started && ended)
  {
    const char*  strDelimiter = ",";

    char* p;
    char str[7] = {index}; //U,0500,
    int time;
    char dir;

    if ( p = strtok(str, strDelimiter) )
    { 
      dir = atoi(p); 
    }
    if ( p = strtok(str, strDelimiter) )
    { 
      time = atoi(p); 
    }

    // Get ready for the next time
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';   
 
    Move(dir, time);
  }
}

//Servos move the dot on etch-a-sketch screen Xin/sec 
void Move(char dir, int time)
{
  if (dir == 'U')
  {
    Yaxis.write(180);   
    delay(time);  
   Serial.print("Yaxis U for " time "ms"); 
  }
  
  if (dir == 'D')
  {
    Yaxis.write(0);
    delay(time);
    Serial.print("Yaxis D for " time "ms"); 
  }
  
  if (dir == 'L')
  {
    Xaxis.write(0);
    delay(time);
    Serial.print("Xaxis L for " time "ms"); 
  }
  
  if (dir == 'R')
  {
    Xaxis.write(180);
    delay(time);
    Serial.print("Xaxis R for " time "ms"); 
  }
}
  Xaxis.attach(5);
  Yaxis.attach(6);

Before attaching the servo, you should write some known value to it.

i added a serial.print line before when the servos(s) are actually supposed to turn to see if the code is some how "skipping" the serial stuff.

And?

    char str[7] = {index}; //U,0500,

Why are you initializing this variable to index? Doesn't make sense.

    if ( p = strtok(str, strDelimiter) )

You should be parsing inData. The str variable is junk.

    if ( p = strtok(str, strDelimiter) )
    { 
      time = atoi(p); 
    }

The two calls to strtok will return the same value. To continue parsing the same array, to get the next value, subsequent calls to strtok have NULL as the first argument.

Before attaching the servo, you should write some known value to it.

ahhh thats why my servos twitch alittle when the start. i moved:

  Yaxis.write(90);
  Xaxis.write(90);

before attaching them, now no twitching :slight_smile: thanks.

Why are you initializing this variable to index? Doesn't make sense.
You should be parsing inData. The str variable is junk.

because if i use inData i get:
error: cannot convert 'int*' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'

The two calls to strtok will return the same value. To continue parsing the same array, to get the next value, subsequent calls to strtok have NULL as the first argument.

ahh ok so like:

    if ( p = strtok(str, strDelimiter) )
    { 
      dir = atoi(p); 
    }
    if ( p = strtok(NULL, strDelimiter) )
    { 
      time = atoi(p); 
    }

do i even need the if statements? can i just:

p = strtok(str, strDelimiter);
dir = atoi(p); 

p = strtok(NULL, strDelimiter);
time = atoi(p);

also is atoi needed? it just converts from acii to integer. and dir isnt an integer so it would work, right? so just:

time = p;
and
dir = p;

thanks!

because if i use inData i get:
error: cannot convert 'int*' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'

int inData[9];

This variable should of of type char.

can i just:

You need the if tests. If the strtok operation fails, because of bad input, it returns a NULL pointer. Passing a NULL pointer to atoi() is not a good idea.

also is atoi needed? it just converts from acii to integer. and dir isnt an integer so it would work, right?

dir isn't an int, but time is.

This variable should of of type char.

ok i see, thanks.

ok well having a letter in the serial "command" is causing issues(the U in <U,0500,>) i put a serial.print to return the value of dir after getting it from serial and writing to a char, and it was some weird square shape symbol. so i just made it a number instead so its <1,0500,>

in the line char inData[9]; should the number(currently 9) be the number of characters with or without the "< >" like: <1,0500,> without the <>, so it would be 5, right?

but it does work... probably because of the dir was causing issues. thanks!

in the line char inData[9]; should the number(currently 9) be the number of characters with or without the "< >" like: <1,0500,> without the <>, so it would be 5, right?

You are not storing the '<' or the '>', so no need to count them. You are storing "1,0500", which I make to be 6 characters. You are also (properly) storing a trailing NULL, so the minimum size would be 7. Slightly bigger is better, though.

Really, Thanks for your help! i can use all that info in other projects.

so right now im expanding my void Move() to have more than just lines and diagonals. im try to get a Circle, but i have no clue on how to do that with my code. ive found examples like: http://arduino.cc/forum/index.php/topic,18965.0.html
but they use x,y coordinates, i have Up, down, Left, Right, and how long for each. how do i implement a circle drawing function?

this is the latrest code that works 100%:

#include <Servo.h>

Servo Xaxis;
Servo Yaxis;

int started = 0;
char inData[8];
int ended = 0;
char index = 0;
int final = 0;

void setup()
{
  Xaxis.write(90);  
  Xaxis.attach(6);
  
  Yaxis.write(90);
  Yaxis.attach(5);

  Serial.begin(9600);
}

void loop()
{
  while(Serial.available() > 0)
  {
    char aChar = Serial.read();
    if(aChar == '<')
    {
      started = true;
      index = 0;
      inData[index] = '\0';
    }
    else if(aChar == '>')
    {
      ended = true;
    }

    else if(started)
    {
      inData[index] = aChar;
      index++;
      inData[index] = '\0';             
    }

    else if (aChar =='*')
    {
      final = true;
    }
  }

  if(started && ended)
  {
    const char*  strDelimiter = ",";

    char* p;
    int time;
    int dir;

    if ( p = strtok(inData, strDelimiter) )
    { 
      dir = atoi(p); 
    }
    if ( p = strtok(NULL, strDelimiter) )
    { 
      time = atoi(p); 
    }

    // Get ready for the next time
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';   
 
    Move(dir, time);
  }
}

//Servos move the dot on etch-a-sketch screen Xin/sec 
void Move(int dir, int time)
{
  if (dir == 1)
  {
    Serial.print("Xaxis Right for ");
    Serial.print(time);
    Serial.print("ms");
    Serial.println();
    Xaxis.write(180);   
    delay(time);
    Xaxis.write(90);
  }

  if (dir == 2)
  {
    Serial.print("Xaxis Left for ");
    Serial.print(time);
    Serial.print("ms"); 
    Serial.println();
    Xaxis.write(0);
    delay(time);
    Xaxis.write(90);
  }

  if (dir == 3)
  {
    Serial.print("Yaxis Down for "); 
    Serial.print(time);
    Serial.print("ms");
    Serial.println();
    Yaxis.write(0);
    delay(time);
    Yaxis.write(90);
  }

  if (dir == 4)
  {
    Serial.print("Yaxis Up for "); 
    Serial.print(time);
    Serial.print("ms");
    Serial.println();
    Yaxis.write(180);
    delay(time);
    Yaxis.write(90);
  }

  if (dir == 5)
  {
    Serial.print("Down+Left diagonal for ");
    Serial.print(time);
    Serial.print("ms");
    Serial.println();   

    Yaxis.write(0);      // tell servo to go to position in variable 'pos' 
    Xaxis.write(0);
    delay(time);       // waits 15ms for the servo to reach the position 

    Xaxis.write(90); 
    Yaxis.write(90);
  }

  if (dir == 6)
  {
    Serial.print("Down+Right diagonal for ");
    Serial.print(time);
    Serial.print("ms");
    Serial.println();
    Yaxis.write(0);
    Xaxis.write(180);   
    delay(time);
    Yaxis.write(90);
  }

  if (dir == 7)
  {
    Serial.print("Up+Left diagonal for ");
    Serial.print(time);
    Serial.print("ms");
    Serial.println();
    Yaxis.write(180);
    Xaxis.write(0);   
    delay(time);
    Yaxis.write(90);
  }

  if (dir == 8)
  {
    Serial.print("Up+Right diagonal for ");
    Serial.print(time);
    Serial.print("ms");
    Serial.println();
    Yaxis.write(180);
    Xaxis.write(180);   
    delay(time);
    Yaxis.write(90);
  }
}

i have Up, down, Left, Right, and how long for each.

If you can use these functions to go to any point, you can draw a circle.

Performing a linear approximation of a circle is not difficult. That link should have enough information to do it.

Once you have a series of x,y locations, you can move from point to point.

If the problem is how to move left for some time and up for some time to get to a specific point, that is a different issue.

i didnt want to use x,y, just draw a circle at the current place(where ever teh etch-a-sketch point is)

im not sure, maybe like have one motor going 50% constant in one direction for a second, then mean while have the other axis motor start from 90 then increase to 180 in 500msec then decrease from 180 to 90 in another 500msec.

i didnt want to use x,y, just draw a circle at the current place(where ever teh etch-a-sketch point is)

im not sure, maybe like have one motor going 50% constant in one direction for a second, then mean while have the other axis motor start from 90 then increase to 180 in 500msec then decrease from 180 to 90 in another 500msec. that would create a semicircle or an arc

ok another quick question.

i have this code which does this: when it receives <2,100>(for example, 2 could be 3 or 4 depending on what direction i want to go) over serial it writes 2 to int dir and writes 100 to int time(time isnt important in this variation of the program, just a filler) then i have modified Move() so that it runs whatever motor which coordinates with int dir, which is 2, until it receives instructions other wise via serial with another command like <3,100>. but since its running motor "2" forever, its not checking for new commands overserial. so it doesnt stop.

how do i make it so that it checks for new serial commands while running a motor "forever"?

#include <Servo.h>

Servo Xaxis;
Servo Yaxis;

int started = 0;
char inData[8];
int ended = 0;
char index = 0;
int final = 0;

void setup()
{
  Xaxis.write(90);  
  Xaxis.attach(6);

  Yaxis.write(90);
  Yaxis.attach(5);

  Serial.begin(9600);
}

void loop()
{
  while(Serial.available() > 0)
  {
    char aChar = Serial.read();
    if(aChar == '<')
    {
      started = true;
      index = 0;
      inData[index] = '\0';
    }
    else if(aChar == '>')
    {
      ended = true;
    }

    else if(started)
    {
      inData[index] = aChar;
      index++;
      inData[index] = '\0';             
    }

    else if (aChar =='*')
    {
      final = true;
    }
  }

  if(started && ended)
  {
    const char*  strDelimiter = ",";

    char* p;
    int time;
    int dir;

    if ( p = strtok(inData, strDelimiter) )
    { 
      dir = atoi(p); 
    }
    if ( p = strtok(NULL, strDelimiter) )
    { 
      time = atoi(p); 
    }

    // Get ready for the next time
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';   

    Move(dir, time);
  }
}

void Move(int dir, int time)
{
  while(dir == 1)
  {
    //Xaxis Right
    Xaxis.write(180);   
    //
  }

  while(dir == 2)
  {
    //Xaxis Left
    Xaxis.write(0);
  }

  while(dir == 3)
  {
    //Yaxis Down
    Yaxis.write(0);
  }

  while(dir == 4)
  {
    //Yaxis Up 
    Yaxis.write(180);
  }
  while(dir == 9)
  {
    //stop both motors
    stop();
  }
}

void stop()
{
  Yaxis.write(90);
  Xaxis.write(90);
}

how do i make it so that it checks for new serial commands while running a motor "forever"?

You have this code:

  while(dir == 1)
  {
    //Xaxis Right
    Xaxis.write(180);   
    //
  }

In the "forever" loops, you right the same value to the servo over and over. Once you start the servo moving, it will keep moving until you tell it to stop. You don't need to tell it over and over to keep moving. It isn't a 14 year old, after all.

Change the while to if.

thanks, i dont know why i didnt catch that. i should have seen it from the code i did before...