Continuous servo memory

Hi,

Can anyone help me with a small snippet of code? I’m trying to work on a way for a continuous servo (or the Particle itself, I should say) to remember the last action it did.

For example (not in real code, as I don’t understand how to do it properly, obviously). Hopefully you can see what I’m trying to accomplish.

position = 1
newposition = boolean-variable

if newposition = 2 {
if position = 1 { turn servo left 2000; position = 2 } else
if position = 2 { turn servo right 2000; position = 1 } else
if position = 3 { turn servo left 3000; position = 2 } else
return -1;
}

Thanks!

Tim

Why not make an additional variable lastAction and set that every time you do something?

That sounds like an excellent idea… how would that work in practice?

position = 1
newposition = boolean-variable

if (newposition == 2) {
  if (position == 1) { 
    turn servo left 2000; 
    position = 2 
  } 
  else if (position == 2) { 
    turn servo right 2000; 
    position = 1 
  } 
  else if (position == 3) { 
    turn servo left 3000; 
    position = 2 
  } 
  else {
    return -1;
  }
}

You had it already :wink: (this won't compile, but makes it a bit easier to read)

Or a bit neater (and syntactically correct - given one function void turnServo(int) to turn left and right just by sign :wink: )

  if (newposition == 2) {
    switch(position) {
      case 1:
        turnServo(+2000);
        position = 2;
        break;
      case 2:
        turnServo(-2000);
        position = 1;
        break;
      case 3:
        turnServo(-3000);
        position = 2;
        break;
      default:
        return -1;
    }
  }
  return position;

But I’d rather go for a mathematical approach to calculate the directions from the current position and the intended position without all these conditional blocks.

Thanks! I really appreciate your help. I wouldn’t have any idea where to begin on the mathematical approach. This is pushing my limits of understanding as it is. Happy to learn though if you can point me at something similar?

Mathematically I’d assume the three positions to be “equidistant” between adjacent positions and hence I’d understand the distance to travel as the difference between position number times a constant distance factor (with some roll-over logic)

e.g. something like this

 steps      = 2000;
 currentPos = 1;
 targetPos  = 3;
 travel = (targetPos - currentPos) * steps;

 turnServo(travel);

Maybe “remapping” the position numbers to 0~2 may be a good idea for that math approach too.

Hi,

I tried adding your above code (not the mathematical one, that’s still WAY over my head… although I’m working on it) and I’m getting a validation error that I don’t understand.

/workspace/twister.cpp:33:25: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]

Any help would be great!

Thanks

Tim

Servo timservo; 

int position = 0;    // variable to store the servo position
 
void setup()
{

//Setup the Servo to the function 
Particle.function("timservo", updatetimServo);
//Set pin D0 to be an output
pinMode(D0, OUTPUT);

//Take control over the LED on the board
RGB.control(true);

//There may be a better way to do this like turning it off, I found it just as easy to set the colour to nothing
RGB.color(0, 0, 0);
}
 
void loop()
{
// We don't need to do anything here
 
}
 
//This function is triggered by IFTTT - the 'command' word represents the object used to store the 'position' we send to the function.
//The 'position' we send represents where we want the servo to move to
int updatetimServo(String command)
{
    
  if (updatetimServo == 1) {
    switch(position) {
      case 1:
        turnServo(0);
        position = 1;
        break;
      case 2:
        turnServo(+2000);
        position = 2;
        break;
      case 3:
        turnServo(+4000);
        position = 3;
        break;
      default:
        return -1;
    }
  }

  if (updatetimServo == 2) {
    switch(position) {
      case 1:
        turnServo(-2000);
        position = 1;
        break;
      case 2:
        turnServo(0);
        position = 2;
        break;
      case 3:
        turnServo(+2000);
        position = 3;
        break;
      default:
        return -1;
    }
  }
    
  if (updatetimServo == 3) {
    switch(position) {
      case 1:
        turnServo(-4000);
        position = 1;
        break;
      case 2:
        turnServo(-2000);
        position = 2;
        break;
      case 3:
        turnServo(0);
        position = 3;
        break;
      default:
        return -1;
    }
  }
  return position;
  
}

Your updatetimServo() is a function:

int updatetimServo(String command)

which takes a String called command and returns an int

when making this comparison:

if (updatetimServo == 1) {

the name of a function resolves to a pointer to that function, that is why you get that error.

command contains the data you seek…

If you are not sure what command contains, try printing command in the function. Then, you will have to extract position from that data.

2 Likes

Your problem isn’t my code but what you did there

int updatetimServo(String command)
{
    
  if (updatetimServo == 1) {

  ...
}

You can’t use the same term for your function name and a variable in it.


@BulldogLowell, you were just that bit faster again

2 Likes

Thanks both of you (@BulldogLowell).

That seems to have solved it, I’ve also gone back to the the writing the servo moves in the int (I know that works) here’s the final code.

Do you have any improvements I could make to do the same job? I’m trying to learn as fast as I can and I bow to both of your infinite wisdomness.

Servo timservo; 

int position = 0;    // variable to store the servo position
int newposition = 1;
 
void setup()
{

//Setup the Servo to the function 
Particle.function("timservo", updatetimServo);
//Set pin D0 to be an output
pinMode(D0, OUTPUT);

//Take control over the LED on the board
RGB.control(true);

//There may be a better way to do this like turning it off, I found it just as easy to set the colour to nothing
RGB.color(0, 0, 0);
}
 
void loop()
{

 
}
 
//This function is triggered by IFTTT - the 'command' word represents the object used to store the 'position' we send to the function.
//The 'position' we send represents where we want the servo to move to
int updatetimServo(String command)
{

uint8_t newposition = command.toInt();

// 45deg
    
  if (newposition == 1) {
    switch(position) {
      case 1:
        position = 1;
        break;
      case 2:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:
		timservo.write( 100 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 3;
        break;
      case 4:
		timservo.write( 100 ); 
		delay( 3000 ); 
		timservo.write( 90 );
        position = 4;
      default:
        return -1;
    }
  }

// 90deg

  if (newposition == 2) {
    switch(position) {
      case 1:
		timservo.write( 80 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 1;
        break;
      case 2:
        position = 2;
        break;
      case 3:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 3;
        break;
      case 4:
		timservo.write( 100 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 4;
      default:
        return -1;
    }
  }
  
// 135deg
    
  if (newposition == 3) {
    switch(position) {
      case 1:
		timservo.write( 80 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 1;
        break;
      case 2:
		timservo.write( 80 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:
        position = 3;
        break;
      case 4:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 4;
        break;
      default:
        return -1;
    }
  }

// 180deg
  
    if (newposition == 4) {
    switch(position) {
      case 1:
		timservo.write( 80 ); 
		delay( 3000 ); 
		timservo.write( 90 );
        position = 1;
        break;
      case 2:
		timservo.write( 80 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:
		timservo.write( 80 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 3;
        break;
      case 4:
        position = 4;
      default:
        return -1;
    }
  }
  return position;
  
}
 switch(position) {
      case 1:
        position = 1;
        break;
      case 2:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:

this is all very strange to me.

it reads:

if(position == 1)
  postion = 1;
else if(postion == 2)
  position = 2;
else if(position = 3)
  position = 3;
/// and so on...

further, where do you assign a value to position?

Hi!

What I’m trying to do is (roughly plain english)

if (newposition = 1) check current position (1-4) and act accordingly.

The newposition comes in as a variable from IFTTT and position is defined by the last action that the servo has taken.

So position from the last action directs what happens next, based on the type of action requested by newposition. Does that make any sense?

I have since updated the int in the header to bool, if that’s what you mean from your last point?

Servo timservo; 

bool position = 0;    // variable to store the servo position
bool newposition = 0;
 
void setup()
{

//Setup the Servo to the function 
Particle.function("timservo", updatetimServo);
//Set pin D0 to be an output
pinMode(D0, OUTPUT);

//Take control over the LED on the board
RGB.control(true);

//There may be a better way to do this like turning it off, I found it just as easy to set the colour to nothing
RGB.color(0, 0, 0);
}
 
void loop()
{

 
}
 
//This function is triggered by IFTTT - the 'command' word represents the object used to store the 'position' we send to the function.
//The 'position' we send represents where we want the servo to move to
int updatetimServo(String command)
{

uint8_t newposition = command.toInt();

// 45deg
    
  if (newposition == 1) {
    switch(position) {
      case 1:
        position = 1;
        break;
      case 2:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:
		timservo.write( 100 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 3;
        break;
      case 4:
		timservo.write( 100 ); 
		delay( 3000 ); 
		timservo.write( 90 );
        position = 4;
      default:
        return -1;
    }
  }

// 90deg

  if (newposition == 2) {
    switch(position) {
      case 1:
		timservo.write( 80 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 1;
        break;
      case 2:
        position = 2;
        break;
      case 3:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 3;
        break;
      case 4:
		timservo.write( 100 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 4;
      default:
        return -1;
    }
  }
  
// 135deg
    
  if (newposition == 3) {
    switch(position) {
      case 1:
		timservo.write( 80 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 1;
        break;
      case 2:
		timservo.write( 80 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:
        position = 3;
        break;
      case 4:
		timservo.write( 100 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 4;
        break;
      default:
        return -1;
    }
  }

// 180deg
  
    if (newposition == 4) {
    switch(position) {
      case 1:
		timservo.write( 80 ); 
		delay( 3000 ); 
		timservo.write( 90 );
        position = 1;
        break;
      case 2:
		timservo.write( 80 ); 
		delay( 2000 ); 
		timservo.write( 90 );
        position = 2;
        break;
      case 3:
		timservo.write( 80 ); 
		delay( 1000 ); 
		timservo.write( 90 );
        position = 3;
        break;
      case 4:
        position = 4;
      default:
        return -1;
    }
  }
  return position;
  
}

No, this is not what he meant; you still want that to be an int. What he meant, is that it makes no sense to set position to the value that it already equals. Take you first case for instance,

switch(position) {
      case 1:
        position = 1;
        break;

The code will only enter this branch of the switch statement if position = 1, so why set it to 1? You do this in all your cases.

Also, at the top of your updatetimServo function you create a new local variable called newposition with this line,

uint8_t newposition = command.toInt();

If you mean to be using your global variable that you created at the top of the program, then you should not be declaring a new local variable here. The line should be,

newposition = command.toInt();

BTW, are you really using a continuous servo as you say in your first post? The servo.write() function sets the speed of a continuous servo, not its position, so are you relying on the time that it runs (with your delays) to get the servo to a known position? If so, that seems a little risky, since any small errors in speed (is 90 exactly no movement, for instance?) will accumulate over many moves of the servo.

Hi Ric, thanks so much for your response here.

I’ve updated the code, below, with your points… I think I’m finally understanding the switch statement now!

Unfortunately I need to use a continuous servo because I need 3 or 4 rotations to get to the correct position, rather than just a point on a 180* turn. 90deg on my servo keeps it really still, so I’m hoping I don’t have the problem you mention. If I could have done that, this would have been much easier to do. :slight_smile:

Thanks

Tim

    Servo timservo; 

    int position = 0;    // variable to store the servo position
    int newposition = 0;
     
    void setup()
    {

    //Setup the Servo to the function 
    Particle.function("timservo", updatetimServo);
    //Set pin D0 to be an output
    pinMode(D0, OUTPUT);

    //Take control over the LED on the board
    RGB.control(true);

    //There may be a better way to do this like turning it off, I found it just as easy to set the colour to nothing
    RGB.color(0, 0, 0);
    }
     
    void loop()
    {

     
    }
     
    //This function is triggered by IFTTT - the 'command' word represents the object used to store the 'position' we send to the function.
    //The 'position' we send represents where we want the servo to move to
    int updatetimServo(String command)
    {

    newposition = command.toInt();

    // 0deg
        
      if (newposition == 1) {
        switch(position) {
          case 2:
    		timservo.write( 100 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 2;
            break;
          case 3:
    		timservo.write( 100 ); 
    		delay( 2000 ); 
    		timservo.write( 90 );
            position = 3;
            break;
          case 4:
    		timservo.write( 100 ); 
    		delay( 3000 ); 
    		timservo.write( 90 );
            position = 4;
          default:
            return -1;
        }
      }

    // 45deg

      if (newposition == 2) {
        switch(position) {
          case 1:
    		timservo.write( 80 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 1;
            break;
          case 3:
    		timservo.write( 100 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 3;
            break;
          case 4:
    		timservo.write( 100 ); 
    		delay( 2000 ); 
    		timservo.write( 90 );
            position = 4;
          default:
            return -1;
        }
      }
      
    // 90deg
        
      if (newposition == 3) {
        switch(position) {
          case 1:
    		timservo.write( 80 ); 
    		delay( 2000 ); 
    		timservo.write( 90 );
            position = 1;
            break;
          case 2:
    		timservo.write( 80 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 2;
            break;
          case 4:
    		timservo.write( 100 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 4;
            break;
          default:
            return -1;
        }
      }

    // 135deg
      
        if (newposition == 4) {
        switch(position) {
          case 1:
    		timservo.write( 80 ); 
    		delay( 3000 ); 
    		timservo.write( 90 );
            position = 1;
            break;
          case 2:
    		timservo.write( 80 ); 
    		delay( 2000 ); 
    		timservo.write( 90 );
            position = 2;
            break;
          case 3:
    		timservo.write( 80 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 3;
            break;
          default:
            return -1;
        }
      }
      return position;
      
    }

I don't understand why you would need 3 or 4 rotations to get to a particular position. It would be interesting to know what you're actually doing with this servo. Can you tell us what your physical setup is?

You may understand, but you're still setting position to the value that it already equals in every one of your cases. All those "position =" statements are unnecessary.

Hi Ric, I’m trying to get my vertical blinds to change position. Unfortunately they’re geared at the head so it takes a number of rotations of the servo (because I can’t put a big enough gear on it) to get it to the right position. I am planning on adding buttons to allow for fine adjustment on the finished product but that bit is easy so I’m leaving it until last.

Ok, I think I see your logic for the second part. Should it be as follows do you think? Sorry for my lack of perceived common sense here… I’m a HTML/CSS/Javascript guy, this is only my second proper attempt at these particle things. :slight_smile:

if (newposition == 3) {
        switch(position) {
          case 1:
    		timservo.write( 80 ); 
    		delay( 2000 ); 
    		timservo.write( 90 );
            position = 3;
            break;
          case 2:
    		timservo.write( 80 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 3;
            break;
          case 4:
    		timservo.write( 100 ); 
    		delay( 1000 ); 
    		timservo.write( 90 );
            position = 3;
            break;
          default:
            return -1;
        }
      }

I don't really know, since I don't quite understand your logic. What you're saying with this code is,

if newposition == 3, then no matter what position equals now, set position to 3.

Is that what you want to happen?

Yes, that’s right. The switch options are based on what position it is in NOW, so the servo actions before each “position = X” are different.

I could have done it (if I knew how) with nested if statements along these lines:

If newposition = 3 {
If position = 1 { turn left 2 turns, set position to 3, break }
If position = 2 { turn left 1 turn, set position to 3, break }
If position = 3 { ignore }
If position = 4 { turn right 1 turn, set position to 3, break }
} etc.

The positions are 45 degree turns at 0, 45, 90, 135 so once the movement is completed it knows what happened last, that way the logic knows which action to take next depending on the input (1,2,3,4)

Does that make sense?

Since you bail out of your function on error, you could put the line position = newposition; at the end of your function instead of having all these position = x; lines clutter up your function :wink: