servo motors explicate function

Ya’akov

Joined Jan 27, 2019
10,235
Here is a basic flow chart that takes into account direction polarity if the Start position is less than or greater than then End position.

The code is blocking, which is how the original code was written, but this can evolve to non-blocking with a more advanced next level "dispatching mode" flowchart implementation.

As is, for "blocking":
- Node 02 would have a Delay(15) or (20) and you would remove "Start Period Timer (20ms)" from Node 07.

For a "dispatch mode" flowchart conducive to "non-blocking":
- The Node reference is a variable Index pointer.
- Each Node does NOT call the next node in the flow but can change the Index pointer.
- Each Node returns to the main program where a dispatcher (If Index pointer is this then go to a corresponding Node).
This can be greatly simplified with the use of "switch case" and "goto" statements. Even though the goto statement is frowned upon, the use of it in this circumstance is an exception.
- This way with more complex designs you can have multiple flowcharts, each with their own Index Pointer, that interdigitate
their Node States.
- Node 02 simply looks for elapsed time to either count down or count up depending on how you write the code.
- Node 07 grabs a new starting point for the Period Counter with "Start Period Timer (20ms)" that Node 02 can reference.

View attachment 295927
Thanks for drawing this.
 

Ya’akov

Joined Jan 27, 2019
10,235
Code:
What do you mean by “slows down the spin”? Are to trying to slow the time it takes for a move from start to end? Or for the delays after the move to change?

The problem occurs in your for statement. You have used the += operator… but that only goes in one direction. And by incrementing versus decrementing, the servo will snap at the end as the loop won’t count the way you think it will.

You need to check if the end position is less than the start position and make sure that servoStepDegrees is negative. Or pass a negative value when going backward. Whichever is easier to you.

Code:
void loop() {  // much neater main loop logic, easy to foillow

  sweepServo( 0, 180, 1 );
  sweepServo( 180, 90, -1 );
  sweepServo( 90, 180, 1 );
  sweepServo( 180, 90, -1 );
  sweepServo( 90, 30, -1 );
  sweepServo( 30, 0, -1 );
  delay(100);

}
This example was really intended to demonstrate a better program structure so little oversights crept in. I appreciate your debugging and suggestions.

It turns out my servoStepDegrees had more than a theoretical application. It was included because it was clear there were cases adjusting it dynamically could arise. It shows that properly framed and named variables do things that are needed even when they are only anticipated as a class and not specifics.

I love it when a feature request can be answered “it already does that” even if it wasn’t directly contemplated. For me, it is one of the signs of a successful design.
 

Thread Starter

fredric58

Joined Nov 28, 2014
252
Beau, thank you but it is kinda over my head. So start at the beginning. What is it you mean by "blocking"? Granted, it is blocking something, but what/why is it blocking? This is a modified sweep servo program from the Arduino examples library. The servo just goes back and forth from 0 to 180 degrees.


Good day, OK, I tried this with a negative (-1) degree and the result is it goes forward then will pause during what should be the incremental return swing, and again it JUMPS back to 0. Which brings me to this line of the for loop. Do I need to establish a "negative" -= for the program to recognize the sweepServo (90, 60, -1); ? Something like "if" servo position is greater than end position, move position -= servo step? I've tried a couple things already but haven't gotten anywhere YET. Thanks, Fred

for ( MovePosition = servoStartPosition; MovePosition <= servoEndPosition; MovePosition += servoStepDegrees )


for ( MovePosition = servoStartPosition; MovePosition >= servoEndPosition; MovePosition -= servoStepDegrees ) I haven't tried it but it seems it would be appropriate?





Code:
void loop() {  // much neater main loop logic, easy to follow

  sweepServo( 0, 15, 1);     //works
  sweepServo( 15, 30, 1 );
  sweepServo( 30, 60, 1 );
  sweepServo( 60, 90, 1 );       //stops here, doesn't make this move  
  sweepServo( 90, 60, -1 );     //basically a 45mS pause then it races back to 0
  sweepServo( 60, 30, -1);
  sweepServo( 30, 0, -1);
  delay(15);
}
 
Last edited:

Beau Schwabe

Joined Nov 7, 2019
186
The term "blocking" means that your program is stuck in a loop waiting and can't do anything else. This is generally considered poor programming. In this example, the delay(15) prevents the program from doing anything else until the delay has finished.

The term "non-blocking" means that your program is free to do other things. In the above case, instead of issuing a delay, read the current value of the system timer instead and add the equivalent of 15ms to that. The next time you read the system timer compare it to the previous value (plus 15ms). If the system timer is greater, then you know that the 15ms time has expired. Meanwhile during that 15ms you could have done other programming tasks.
 

djsfantasi

Joined Apr 11, 2010
9,237
In your requirements, it does not appear as if blocking is an issue. I don’t think you are trying to do anything else besides move the servo. So you don’t care if the code is blocking!

A different technique would be necessary if you needed to do something while the servo is moving or while you were pausing for the next move. Like checking for a button press…

But so far, it appears that you aren’t concerned about this. So you can ignore the “blocking” side effect of using the delay() function.
 

Thread Starter

fredric58

Joined Nov 28, 2014
252
I have heard there is sometimes a "conflict" between libraries. does anyone understand what this means? I would like to add the servo code to an existing code, a power down/sleep but I keep getting this error message. totally LOST here. Thanks, Fred


/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp: In function 'void __vector_3()':
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:82:44: error: cannot convert 'volatile uint8_t* {aka volatile unsigned char*}' to 'volatile uint16_t* {aka volatile unsigned int*}' for argument '2' to 'void handle_interrupts(timer16_Sequence_t, volatile uint16_t*, volatile uint16_t*)'
handle_interrupts(_timer1, &TCNT1, &OCR1A);
^
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp: In function 'void initISR(timer16_Sequence_t)':
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:129:5: error: 'TCCR1B' was not declared in this scope
TCCR1B = _BV(CS11); // set prescaler of 8
^~~~~~
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:129:5: note: suggested alternative: 'TCCR0B'
TCCR1B = _BV(CS11); // set prescaler of 8
^~~~~~
TCCR0B
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:136:5: error: 'TIFR1' was not declared in this scope
TIFR1 |= _BV(OCF1A); // clear any pending interrupts
^~~~~
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:136:5: note: suggested alternative: 'TIFR'
TIFR1 |= _BV(OCF1A); // clear any pending interrupts
^~~~~
TIFR
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:137:5: error: 'TIMSK1' was not declared in this scope
TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
^~~~~~
/Applications/Arduino-2.app/Contents/Java/libraries/Servo/src/avr/Servo.cpp:137:5: note: suggested alternative: 'TIMSK'
TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
^~~~~~
TIMSK
exit status 1
Error compiling for board ATtiny25/45/85.
 

BobTPH

Joined Jun 5, 2013
11,515
Do you realize that the loop is only needed if you want to control the speed of the movement?

I think everyone is making this more complicated than needed.

To simply move the servo from any position to another as fast as it can move, you just need a single call like this:

myServo.write(newPos);

A sequence if moves and pauses of 1 second would look like:

myServo.write(30);
delay(1000):
myServo.write(60);
delay(1000):
myServo.write(90);
delay(1000):

No loops needed!
 

djsfantasi

Joined Apr 11, 2010
9,237
Do you realize that the loop is only needed if you want to control the speed of the movement?

I think everyone is making this more complicated than needed.

To simply move the servo from any position to another as fast as it can move, you just need a single call like this:

myServo.write(newPos);

A sequence if moves and pauses of 1 second would look like:

myServo.write(30);
delay(1000):
myServo.write(60);
delay(1000):
myServo.write(90);
delay(1000):

No loops needed!
And this approach even works backwards!

Code:
myServo.write(60); // position at 60°
delay(1000):
myServo.write(30); // back to 30°
delay(1000):
myServo.write(90); // forward to 90°
delay(1000):
 

BobTPH

Joined Jun 5, 2013
11,515
Yep, all the API call does change the width of pulses sent to the servo every 20ms. The servo then goes to the position indicated by the width.

The TS started with code that did controlled movement over time by moving 1 degree at a time with a delay between moves. And everyone seemed to think this was the way to move the servo.
 

Thread Starter

fredric58

Joined Nov 28, 2014
252
Hey guys, after hours and hours of reading I discovered the problem is the Arduino servo sweep library is not compatible with the Attiny85 that I want to use to control the servo. I also discovered that 9 of the Attiny servo libraries I've tried so far to control a servo don't REALLY work very well. So I am still searching for something that will work.

myServo.write(30); THIS WOULD BE REALLY COOL!!! REALLY COOL!
delay(1000):
myServo.write(60);
delay(1000):
myServo.write(90);
delay(1000):
 

BobTPH

Joined Jun 5, 2013
11,515
Hey guys, after hours and hours of reading I discovered the problem is the Arduino servo sweep library is not compatible with the Attiny85 that I want to use to control the servo. I also discovered that 9 of the Attiny servo libraries I've tried so far to control a servo don't REALLY work very well. So I am still searching for something that will work.

myServo.write(30); THIS WOULD BE REALLY COOL!!! REALLY COOL!
delay(1000):
myServo.write(60);
delay(1000):
myServo.write(90);
delay(1000):
Then try it.
 

Thread Starter

fredric58

Joined Nov 28, 2014
252
I appreciate everyones help. however, this is what I would call a complicated merge of (2) libraries. one lib is the "SLEEP MODE" program that runs off the WDT. pre-scaled to 8mHz and (i'll check) about the other (2). (0) and (1). It isn't as simple as writing

myServo.write(30); THIS WOULD BE REALLY COOL!!! REALLY COOL!
delay(1000):
myServo.write(60);
delay(1000):
myServo.write(90);
delay(1000):

It doesn't work that way! The At 328P is 16 mHz, The tiny is 8mHz, There is a "conflict" between the libraries I have yet to figure out, but I will. My original goal was to use pin 0 of the Attiny85 to source the gate of a buz11 MOSFET to turn the servo power ON. (separate power supply) Then use pin 1 to source the run code to the servo. However, with the timers involved it won't work. My other thought was to use the Attiny85 to "POWER/CONTROL" a 328P and let it run the servo code. more involved, more expensive, more of a pain....anyone have a work around???
 

Thread Starter

fredric58

Joined Nov 28, 2014
252
I found some code that works without a library (no library required) to conflict with the one already in use and have a question. Code attached. It's rather long and cumbersome. The question is, since the author mapped out (3) servo motor positions. Wouldn't, or would it be possible to map angle to degrees. So the call could be simplified to be written as previously explained in post #30. (below) It would have to be something like degree = 0 + 1 in steps of say 30 degrees Something like that.... I don't want to write 180 lines and I am not using all 180, more like 0, 45, 90, 120 and 180, or 30, 60 , 90, 120, 150, 180 (the actual travel).....but couldn't it be "mapped"? It would seem that everything BELOW servo test could possibly be eliminated because it seems redundant? This program actually works, however I still haven't figured out how to control the speed of the sweep.


"myServo.write(30); THIS WOULD BE REALLY COOL!!! REALLY COOL!
delay(1000):
myServo.write(60);
delay(1000):
myServo.write(90);
delay(1000):"







Code:
// Author: mcapurso. Tested on attiny 85 with servo towerpro microservo 90 SG90
// 08/jan/2014 servo data on www.servodatabase.com 25


int servoPin = 0; // servo connected to digital pin 0

void setup()
{
pinMode(servoPin, OUTPUT); // sets the servoPin to be an output
}

void loop() // run over and over again
{
servowrite(servoPin, 0, 500, 2400);
servowrite(servoPin, 90, 500, 2400);
servowrite(servoPin, 180, 500, 2400);
// servotest();
}

void servowrite(int pin, int angle, int microzero, int micro180)
{
// pin for servo, angle to move, microseconds for zero degrees, microseconds for 180 degrees
int microvalue= map(angle, 0, 180, microzero, micro180); //map angle to microseconds
int i;
for (i = 0; i < 50; i++) //Send 50 pwm pulses with width microvalue uS . 
{
analogWrite(servoPin,255); //Pulse high for microvalue uS
delayMicroseconds(microvalue);
analogWrite(servoPin,0); //Pulse low for 15mS
delay(15);
}
delay(10); //Pause
}

void servotest()
// test servo
{
int i;

for (i = 0; i < 50; i++) //Send 50 pulses with width 500 uS
{
analogWrite(servoPin,255); //Pulse high for 500uS
delayMicroseconds(500);
analogWrite(servoPin,0); //Pulse low for 15mS
delay(15);
}
delay(100); //Pause for 100mS

for (i = 0; i < 50; i++) //Send 50 pulses with width 1.25mS
{
analogWrite(servoPin,255);
//Pulse high for 1.4 mS
delayMicroseconds(1400);
analogWrite(servoPin,0);
delay(15);
}
delay(100);

for (i = 0; i < 50; i++) //Send 50 pulses with width 2.4ms
{
analogWrite(servoPin,255);
delayMicroseconds(2400);
analogWrite(servoPin,0);
delay(15);
}
delay(100);

}
 
Top