This is to be (aka not done yet) an animatronic dragon's head. It currently has 3 PIR sensors to act as eyes. My goal is to have it interact on some limited level with people. The idea is to have to head turn right/left towards the most recent movement, and center itself on the 'target' and perform some other entertainment behaviors (open mouth, blink lights, etc..) So far I can get it to turn towards movement on it's right, but I seem to have a problem with the code to turn the other direction. I know the sense routine is working (I've checked the output), but the movement routine has a problem I was hoping someone on LMR can give me a hint to get me back on track. Yes, this is my first 'robot'.. I have no plans to leave the microcontroller imbeded, so I'm using an Arduino. Here's the function I'm having problems with...
void moveHeadNeck() { int alittle = 1; // a small move to one side for fine tuning int alot = 2; // a big move to one side when something new is noticed. int cPos = neck.read(); // current position of neck servo // Serial.print("cPos:"); Serial.println(cPos); // Serial.print("cPos-1:"); Serial.println(cPos-1); if (motionCenter==true) { if (motionRight==true) { // move a little to the right neck.write(cPos-alittle); Serial.println("Motion to the CENTER/RIGHT"); } if (motionLeft==true) { // move a little to the left neck.write(cPos+alittle); Serial.println("Motion to the CENTER/LEFT"); } } else { // motionCenter==false if (motionRight==true) { // move a lot to the right neck.write(cPos-alot); Serial.println("Motion to the RIGHT"); } if (motionRight==true) { // move a lot to the left neck.write(cPos+alot); Serial.println("Motion to the LEFT"); } } }
This moves to the right (adding) just fine, but refused to turn to the left (subtracting). Any suggestions?
Turn towards detected movement
Actuators / output devices: Servos, LEDs
Control method: autonomous with manual control over-ride options
CPU: Arduino
Power source: 5.6v via 4 rechargable AA batteries.
I did not center the servo prior to attaching it, no. I don’t think that’s the problem though.
When I use serial to echo the variables’ values, for some reason the -alittle/-alot seem to be added rather than subtracted from the cPos, so the value that it writes to the servo is always increasing.
Just to confirm, your code is hitting the logical block for if (motionLeft==true)? You are seeing the text “Motion to the CENTER/LEFT” or “Motion to teh LEFT” print out approprately when there is a person triggering the left sensor?
If I understand correctly, your moveHeadNeck() routine is called iteratively to turn the neck in increments of either 1 or 2 degrees, depending on whether the sensor in the center is triggered along with one of the side sensors. The routine is called repeatedly from outside the loop until you are positioned where you want to go?
Have you considered just moving the servo to the position you want?
void moveHeadNeck() {
int center = 90; // center position for neck servo int right = 0; // right position for neck servo int left = 180; // left position for neck sero
int center-right = 45; // mid-way between center and right
int center-left = 135; // mid-way between center and left if (motionCenter==true) { if (motionRight==true) { // look mid-way between center and right neck.write(center-right); Serial.println(“Motion to the CENTER/RIGHT”); } if (motionLeft==true) { // look mid-way between center and left neck.write(center-left); Serial.println(“Motion to the CENTER/LEFT”); } } else { // motionCenter==false if (motionRight==true) { // look right neck.write(right); Serial.println(“Motion to the RIGHT”); } if (motionRight==true) { // look left neck.write(left); Serial.println(“Motion to the LEFT”); } }
}
You can also use loops within the logic blocks above to move your servo to a set postion in steps, so you can control the speed.
I’m sorry, I don’t think I explained what I want it to do very well. I want it to sense movement on the right/left side, the move slightly in that direction based on it’s current position. This way, one person could be interacting with it, then another person walk up, and the head would turn towards the new arrival as long as they kept moving. There will be a ‘blind spot’ in the center where the head will not pick up movment, and thus be facing the “target”.
i noticed in the second half of your code (when there is no motion detected in the center) both of the if statements are testing for motion on the right. i assume the second one should be testing for motion on the left
this would cause it to go to the right more often than the left
Try reading through your code line by line, there could be several places where it can go wrong. In your function above I can see at least 1 instance which would cause a problem. The last motionRight should probably be motionLeft. Also if motionRight/Left etc are global variables be sure to reset them each loop.
I don’t know why I missed that. I read the code, I-don’t-know-how-many times… The head is moving right/left based on surrounding movement… ! ! !
Now if I can get the PIR’s to quit reporting false movement… I’ve inserted delays long enough for them to reset, and debounce, but I’m still getting a little random artifact from the side without movement. The loop() reads for motion, but waits for 400 millis before reading, to make sure the head isn’t picking up it’s own movement… :) Here’s the revised head move function…
void moveHeadNeck() { int alittle = 5; // a small move to one side for fine tuning int alot = 20; // a big move to one side when something new is noticed. int cPos = neck.read(); // current position of neck servo if (motionCenter==true) { if (motionRight==true) { // move a little to the right, closer to 0 neck.write(cPos-alittle); Serial.println(“Motion to the CENTER/RIGHT”); } if (motionLeft==true) { // move a little to the left, closer to 180 neck.write(cPos+alittle); Serial.println(“Motion to the CENTER/LEFT”); } } else { // motionCenter==false if (motionRight==true) { // move a lot to the right, closer to 0 neck.write(cPos-alot); Serial.println(“Motion to the RIGHT”); } if (motionLeft==true) { // move a lot to the left, closer to 180 neck.write(cPos+alot); Serial.println(“Motion to the LEFT”); } } moving = true; stopTime = millis() + 350; }
I got my PIR from Lady Ada, but the ones she sent me are a slightly different model than her tutorial shows. There weren’t jumpers on my PIRs when I got them, a jumper (wire) was soldered in place to the ‘hi’ setting. I removed this on each of my PIRs and put the pins in, and jumpers connecting to ‘low’. I’ve also calibrated each of them so their refresh rate is very short, about 300 to 350 millis is the average. With this in mind, I’ve set my readsensor function to self limit to reading once every 400 millis to avoid reacting multiple times to the same stimuli. I have also included a 400millis delay to allow for the servos to move. As it stands now, the sensors “see” movement, the servos react, then the whole thing just waits about 400 millis then reads again. The only problem I have now is that it’s a little jerky with it’s movements, not the fluid motion you’d expect to see in an organic.
Well, whatever the problem Well, whatever the problem is, I hope that you can get it working the way you want it to. It appears that you are going to have quite the robot that is going to be really cool to check out once it is completed.
ONLINE Casino
Glücksspieler wie ich lieben dieses ONLINE Casino bonus und ich werde in Zukunft sicher öfter zum Spielen vorbeischauen, solange es dieses Casino gibt.
I’m using an arduino, so I wrote a sketch that watches for the change of state in the PIRs. It records the time the reading on the PIR goes high, reports that time, and then waits for the reading to go low. When it goes from high to low it calculates the time since it went high then feeds it back to the computer via serial connection. The times it reported during each of the calibration process was right around 310 to 319 milliseconds. If you want, I’d be happy to share the sketch.
Since you haven’t shared the part of your code that does the sensing, I can’t be sure how that works. However, if the PIR stays high for 310 to 319 mS, I would think you would want your code to sample at more than 2x the max. This is sampling theory stuff. If you want to be sure to capture a sample of a signal, you sample at a frequency of at least 2x. So if you want to AVOID sampling the same signal twice, you want more than 2x the period (duration) of your signal.
Lets round up a bit for a factor of safety, and say the maximum time the PIR signal stays high is 350 mS. Try sampling at 700 mS and see if that fixes your problem.
Thank you for the tip, I’ll give it a try and let you know how it does…
Keep in mind I’m using analog pins to read the PIRs, it seems to work better than using the digital pins.
As to the PIR reading routine, here it is…
void ReadEyes() { int sensitivity = 200; // lower number = more false positives Serial.println(“reading eyes”); delay(400); // delay long enough for the PIRs to refresh ccVal = analogRead(cPin); crVal = analogRead(rPin); clVal = analogRead(lPin); if ((ccVal + crVal + clVal)>0) { Serial.print(“ccVal:”); Serial.println(ccVal); Serial.print(“crVal:”); Serial.println(crVal); Serial.print(“clVal:”); Serial.println(clVal); } motionCenter = false; motionRight = false; motionLeft = false; if (ccVal >= pcVal + sensitivity) motionCenter = true; if (crVal >= prVal + sensitivity) motionRight = true; if (clVal >= plVal + sensitivity) motionLeft = true; if (motionCenter==true) { if (motionRight==true) neck_gPos = constrain(neck_cPos - move_alittle, neck_min,neck_max); if (motionLeft==true) neck_gPos = constrain(neck_cPos + move_alittle, neck_min,neck_max); } if (motionCenter==false) { if (motionRight==true) neck_gPos = constrain(neck_cPos - move_alot, neck_min,neck_max); if (motionLeft==true) neck_gPos = constrain(neck_cPos + move_alot, neck_min,neck_max); } pcVal = ccVal; prVal = crVal; plVal = clVal; }
I have seperate routines for the head & neck to move if the servo isn’t at it’s gPos (goal position). I’ve rewritten the move routines to make the movements smooth by eliminating the use of delay().
After seeing your successes with the sharp sensors for motion tracking, I’m considering either doing an addition, or a redesign. I’m not sure yet, and I have not received the sharp sensors I ordered today…
Perhaps a combination of the two? The sharps for when you have someone to track, and the PIRs for when you haven’t found someone and are looking for a “target”?