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;
}
Or a bit neater (and syntactically correct - given one function void turnServo(int) to turn left and right just by sign )
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)
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;
}
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;
}
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.
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.
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.
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;
}
}
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)
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