Hello all. Thank you for taking the time to read this post. I have a sketch that does some pretty cool stuff with a robotic skeleton for Halloween. When he is not actively sensing motion, i want him to randomly look around as if a real person can. I have modified a standard sweep sketch to do just what him to do. Only problem is that it uses delays so the motion detector never fires the "action". I ran across this sketch that sweep without delays and considered it. Unfortunately this goes from 0-180 on a regular basis. I need to modify it to only go from 120-170(randomly) but with completely random timing. Any enlightenment of this code would be much appreciated. Thank you .
#include <Servo.h>
class Sweeper
{
Servo servo; // the servo
int pos; // current servo position
int increment; // increment to move for each interval
int updateInterval; // interval between updates
unsigned long lastUpdate; // last update of position
public:
Sweeper(int interval)
{
updateInterval = interval;
increment = 1;
}
void Attach(int pin)
{
servo.attach(pin);
}
void Detach()
{
servo.detach();
}
void Update()
{
if((millis() - lastUpdate) > updateInterval) // time to update
{
lastUpdate = millis();
pos += increment;
servo.write(pos);
Serial.println(pos);
if ((pos >= 180) || (pos <= 0)) // end of sweep
{
// reverse direction
increment = -increment;
}
}
}
};
Sweeper sweeper1(20);
void setup()
{
Serial.begin(9600);
sweeper1.Attach(9);
}
void loop()
{
sweeper1.Update();
}
Thank you Robin. I have been able to modify the sketch to accomplish one of my needs.
if (servoPosition <= servoMinDegrees) {
// when the servo gets to its minimum position change the interval to change the speed
if (servoInterval == servoSlowInterval) {
servoFastInterval = random(10, 60); (I ADDED THIS PART)
servoInterval = servoFastInterval;
}
else {
servoSlowInterval = random(60, 100); (I ADDED THIS PART)
servoInterval = servoSlowInterval;
}
This seems to have changed the speed to be random. I still cant figure out how to "pause" between left and right movements for a random period(between 1000ms and 10000ms will do). I think in need to add some ms amounts in the part where it equals position and changed speed.
I may have figured out the random positions but until I get the pause in between positions i cant tell. again thank you for your help.
In general you need code that checks for the point at which you want to pause and which then sets a variable to prevent the movement. When the pause time has elapsed the variable can be changed to allow movement. The variable might be a boolean called allowServoToMove and set it to false when you don't want movement
This is my current draft. It seems to almost do what i need. I get random servo target positions, random delays between target position movements, but it moves to the target too quick. I adjust my servo speed variable but it doesn't seem to affect it. Do you see something that I have overlooked? Thank you.
#include <Servo.h>
int servoPos ; //Current position of servo
int targetPos; //Position that each step is aiming for, updated at target position
int servoSpeed; //Speed of servo movement, updated at target position
int servoDelay; //Delay in between servo targets, updated at target position
unsigned long currentMillis = 0; //Current time when called on
unsigned long previousMillis = 0; //Last time millis was recorded
unsigned long posMillis = 0; //Last time target position was changed, updated at target position
Servo myServo;
void setup() {
// put your setup code here, to run once:
myServo.attach(5); //Assign servo to pin 5
myServo.write(140); //Set initial position for servo
servoSpeed = 100; //Set initial servo speed
servoDelay = 1000; //Set initial servo delay
targetPos = random(120, 175); //Choose initial random target position
Serial.begin(9600);
}
void loop() {
currentMillis = millis();
// put your main code here, to run repeatedly:
//Check to see if last time servo moved is greater than chosen delay time
if (currentMillis - posMillis >= servoDelay){
servoUpdate();
Serial.println(servoPos);
}
}
void servoUpdate(){
if (currentMillis - previousMillis >= servoSpeed){ //Check to see if its time to move again
if (servoPos < targetPos){ // Check to see if current servo position is les than target position
Serial.println(servoPos); //if it is write to servo the position and increment by 1
myServo.write(servoPos);
servoPos ++;
previousMillis == currentMillis; //Assign previous millis to current millis
} else{
if (servoPos > targetPos){ // Check to see if current position is
myServo.write(servoPos);
servoPos --;
previousMillis == currentMillis;
}
}
if (servoPos == targetPos){ //If current position reachs the target position then update the following
posMillis = currentMillis; //Update last time target position was reached
targetPos = random(120,150); //Assign a new random target position
servoSpeed = random(100, 200); //Assign a new servo speed
servoDelay = random(1000, 10000); //Assign a new servo delay between position changes
}
}
}
Go and read the forum instructions so that you can go back and modify each of your posts - the "More -> Modify" option below the right hand corner of your post - to mark up your code as such using the "</>" icon in the posting window. Just highlight each section of code (or output) from the IDE and click the icon. In fact, the IDE has a "copy for forum" link to put these markings on for you so you then just paste it here in a posting window.
It is inappropriate to attach it as a ".ino" file. People can usually see the mistakes directly and do not want to have to actually load it in their own IDE. And that would also assume they are using a PC and have the IDE running on that PC.
But don't forget to use the "Auto-Format" (Ctrl-T) option first to make it easy to read. If you do not post it as "code", it can be quite garbled and is always more difficult to read.
Also tidy up your blank space. Use blank lines only between functional blocks.
Your code is too long for me to study quickly without copying to my text editor. The text editor shows line numbers, identifies matching brackets and allows me to search for things like all instances of a particular variable or function.
My apologies. I should have been a good noob and read the instructions. LOL. I did not mention that this is on an UNO for testing, but it will used on a NANO when completed. I have to get this code working before I integrate it into another code. It will move a skeleton head around at random as if he were looking around. There is a motion sensor in his chest that will do other things. I just need this random sweep to allow a signal from the motion detector to be "seen" by the code at all times. Thank you
#include <Servo.h>
int servoPos; //Current position of servo
int targetPos; //Position that each step is aiming for, updated at target position
int servoSpeed; //Speed of servo movement, updated at target position
int servoDelay; //Delay in between servo targets, updated at target position
unsigned long currentMillis = 0; //Current time when called on
unsigned long previousMillis = 0; //Last time millis was recorded
unsigned long posMillis = 0; //Last time target position was changed, updated at target position
Servo myServo;
void setup() {
myServo.attach(9); //Tell servo to connect to pin 9
servoSpeed = 100; //Set initial servo speed
servoDelay = 1000; //Set initial servo delay
targetPos = random(120, 175); //Choose initial random target position
Serial.begin(9600);
servoPos = myServo.read();
}
void loop() {
currentMillis = millis(); //Check to see if last time servo moved is greater than chosen delay time
if (currentMillis - posMillis >= servoDelay) { //If the difference between now and last time target position was reached is greater than chosen delay time, then update now
servoUpdate();
}
}
void servoUpdate() {
if (currentMillis - previousMillis >= servoSpeed ) { //Check to see if its time to move again
if (servoPos <= targetPos) { // Check to see if current servo position is les than target position
myServo.write(servoPos); //if it is write to servo the position and increment by 1
servoPos ++;
previousMillis += servoSpeed; //Assign previous millis to current millis
} else {
if (servoPos >= targetPos) { // Check to see if current position is
myServo.write(servoPos);
servoPos --;
previousMillis -= servoSpeed;
}
}
if (servoPos == targetPos) { //If current position reachs the target position then update the following
posMillis = currentMillis; //Update last time target position was reached
targetPos = random(120, 175); //Assign a new random target position
servoSpeed = random(70, 150); //Assign a new servo speed
servoDelay = random(2000, 10000); //Assign a new servo delay between position changes
}
}
}
void servoUpdate() {
if (currentMillis - previousMillis >= servoSpeed ) { //Check to see if its time to move again
if (servoPos <= targetPos) { // Check to see if current servo position is les than target position
myServo.write(servoPos); //if it is write to servo the position and increment by 1
servoPos ++;
previousMillis += servoSpeed; //Assign previous millis to current millis
} else {
if (servoPos >= targetPos) { // Check to see if current position is
myServo.write(servoPos);
servoPos --;
previousMillis -= servoSpeed;
}
}
should be
void servoUpdate() {
if (currentMillis - previousMillis >= servoSpeed ) { //Check to see if its time to move again
previousMillis += servoSpeed;
if (servoPos <= targetPos) { // Check to see if current servo position is les than target position
myServo.write(servoPos); //if it is write to servo the position and increment by 1
servoPos ++;
} else {
if (servoPos >= targetPos) { // Check to see if current position is
myServo.write(servoPos);
servoPos --;
}
}
You should never have
previousMillis -= servoSpeed;
as that implies going back in time. Einstein forbade that for ordinary mortals.
I have made the necessary changes. The head seems to "jerk" when moving a long distance too quick. I have tried to adjust the "servoSpeed" but I don't see any changes. I need slow the movement of the sweep. I'm not sure where to make the change.
I could see how too many random actions could yield undesirable results. I could sacrifice the random target positions if if means getting adjustable speed of movement. That seems more desirable to me. Here is the code as it stands
#include <Servo.h>
int servoPos; //Current position of servo
int targetPos; //Position that each step is aiming for, updated at target position
int servoSpeed; //Speed of servo movement, updated at target position
int servoDelay; //Delay in between servo targets, updated at target position
unsigned long currentMillis = 0; //Current time when called on
unsigned long previousMillis = 0; //Last time millis was recorded
unsigned long posMillis = 0; //Last time target position was changed, updated at target position
Servo myServo;
void setup() {
myServo.attach(9); //Tell servo to connect to pin 9
servoSpeed = 100; //Set initial servo speed
servoDelay = 1000; //Set initial servo delay
targetPos = random(120, 175); //Choose initial random target position
Serial.begin(9600);
servoPos = myServo.read();
}
void loop() {
currentMillis = millis(); //Check to see if last time servo moved is greater than chosen delay time
if (currentMillis - posMillis >= servoDelay) { //If the difference between now and last time target position was reached is greater than chosen delay time, then update now
servoUpdate();
}
}
void servoUpdate() {
if (currentMillis - previousMillis >= servoSpeed ) { //Check to see if its time to move again
previousMillis += servoSpeed;
if (servoPos <= targetPos) { // Check to see if current servo position is les than target position
myServo.write(servoPos); //if it is write to servo the position and increment by 1
servoPos ++;
//Assign previous millis to current millis
} else {
if (servoPos >= targetPos) { // Check to see if current position is
myServo.write(servoPos);
servoPos --;
}
}
if (servoPos == targetPos) { //If current position reachs the target position then update the following
posMillis = currentMillis; //Update last time target position was reached
targetPos = random(120, 175); //Assign a new random target position
servoSpeed = 500; //Assign a new servo speed
servoDelay = random(2000, 10000); //Assign a new servo delay between position changes
}
}
}
Before I look at your code, have you done some tests without the random() element to discover what speeds you consider appropriate?
Testing with random values can be complicated. Maybe make up an array of values and cycle through that to simulate a series of disconnected values which you can repeat as often as you want.
Personally I suspect that random distances would be more important than changing speeds. I'm imagining a person on sentry duty who scans the scene from left to right. The risk for the burglar is that the sentry only completes half of his scan before returning to the start.
void loop() {
currentMillis = millis(); //Check to see if last time servo moved is greater than chosen delay time
if (currentMillis - posMillis >= servoDelay) { //If the difference between now and last time target position was reached is greater than chosen delay time, then update now
servoUpdate();
}
}
void servoUpdate() {
if (currentMillis - previousMillis >= servoSpeed ) { //Check to see if its time to move again
previousMillis += servoSpeed;
the two time tests will interfere with each other. Think about the situation where the first interval is 1000 (never mind what units) and the second interval is 2000. By the time the code gets to the second time half of the 2000 will already be over.
I suspect you should simply delete the time test from loop()
Sorry for the long delay in response. Its been a busy week at work. I seem to have found my solution.
#include <Servo.h>
int servoPos; //Current position of servo
int targetPos; //Position that each step is aiming for, updated at target position
int servoSpeed; //Speed of servo movement, updated at target position
int servoDelay; //Delay in between servo targets, updated at target position
unsigned long currentMillis = 0; //Current time when called on
unsigned long previousMillis = 0; //Last time millis was recorded
unsigned long posMillis = 0; //Last time target position was changed, updated at target position
Servo myServo;
void setup() {
myServo.attach(9); //Tell servo to connect to pin 9
servoSpeed = 50; //Set initial servo speed
servoDelay = 1000; //Set initial servo delay
targetPos = random(120, 175); //Choose initial random target position
Serial.begin(9600);
servoPos = myServo.read();
}
void loop() {
currentMillis = millis(); //Check to see if last time servo moved is greater than chosen delay time
if (currentMillis - posMillis >= servoDelay) { //If the difference between now and last time target position was reached is greater than chosen delay time, then update now
servoUpdate();
}
}
void servoUpdate() {
if (currentMillis - previousMillis >= servoSpeed) { //Check to see if its time to move again
previousMillis = millis(); //THIS WAS MY FIX!!!!!!
if (servoPos <= targetPos) { // Check to see if current servo position is les than target position
myServo.write(servoPos); //if it is write to servo the position and increment by 1
servoPos ++;
//Assign previous millis to current millis
} else {
if (servoPos >= targetPos) { // Check to see if current position is
myServo.write(servoPos);
servoPos --;
}
}
if (servoPos == targetPos) { //If current position reachs the target position then update the following
posMillis = currentMillis; //Update last time target position was reached
targetPos = random(120, 175); //Assign a new random target position
servoSpeed = random(10, 80); //Assign a new servo speed
servoDelay = random(2000, 10000); //Assign a new servo delay between position changes
}
}
}
It seems that I wasn't updating previous millis with the current millis properly in the servoupdate function. After doing that I was able to change sweepspeed to random after target position was reached. That seemed to control the speed of each sweep to a random range of my choosing. Now its time to integrate this code into my larger code. Thank you for all your help.