Help with servos and rangefinder

I need some help with using a Parallax Ping ultrasonic rangefinder and HS-322HD Hitec servos. My goal would be to replicate something such as this: Lula · robotic Hang player on Vimeo

I would pretty much like to copy this. I would want several servos (at least 6) to move in sequence, and would want that sequence to move faster as an object moves closer to the rangefinder, and slower as the object moves away. It would be nice to do all this without using another chip or servo controller of some sort. The more compact the package the better. My futile attempts at manipulating the Ping and Servo codes are catastrophic failures resulting in the servo either twitching or not moving at all.

If anyone could point me in the right direction or tell me how to do this I would greatly appreciate it. I'm new to the whole programming deal and my head hurts after several days of trying to get this to work.

Hi Jimmy, if you posted the code you are having trouble with, perhaps someone here can suggest how to fix the problem

I was trying to combine this servo code...

#include <Servo.h>

Servo servo1; Servo servo2; 


void setup()
{
  pinMode(1,OUTPUT);
  servo1.attach(14); //analog pin 0
  servo1.setMaximumPulse(2400);
  servo1.setMinimumPulse(00);
  Serial.begin(9600);
  Serial.println("Ready");
}

void loop()
{
 static int v = 0;
 if ( Serial.available()) 
 {
    char ch = Serial.read();
    switch(ch)
    {
      case '0'...'9':
        v = v * 10 + ch - '0';
        break;
      case 's':
        servo1.write(v);
        v = 0;
        break;
    }
  }

  Servo::refresh();

}

and this rangefinder code.

 unsigned long echo = 0;
 int ultraSoundSignal = 9; // Ultrasound signal pin
 unsigned long ultrasoundValue = 0;

 void setup()
 {
 Serial.begin(9600);
 pinMode(ultraSoundSignal,OUTPUT);
 }

 unsigned long ping(){
 pinMode(ultraSoundSignal, OUTPUT); // Switch signalpin to output
 digitalWrite(ultraSoundSignal, LOW); // Send low pulse
 delayMicroseconds(2); // Wait for 2 microseconds
 digitalWrite(ultraSoundSignal, HIGH); // Send high pulse
 delayMicroseconds(5); // Wait for 5 microseconds
 digitalWrite(ultraSoundSignal, LOW); // Holdoff
 pinMode(ultraSoundSignal, INPUT); // Switch signalpin to input
 digitalWrite(ultraSoundSignal, HIGH); // Turn on pullup resistor
  echo = pulseIn(ultraSoundSignal, HIGH); //Listen for echo
  ultrasoundValue = (echo / 58.138) * .39; //convert to CM then to inches
 return ultrasoundValue;
 }

 void loop()
 {
 int x = 0;
 x = ping();
  Serial.println(x);
  delay(250); //delay 1/4 seconds.
 }

I would like the ultrasoundValue (x) to be the delay amount between the servo movements. The servo movement would be about twenty degrees. So I want it to start at zero degrees, move to twenty, move back to zero. Multiple servos would be doing this one after the other. So after one servo completed the movement the next servo would move, then the next servo, and the next servo. The delay(x) should go between servo movements so the closer something got to the rangefinder the faster the servos would move together.

Thats the plan, but I can't get it to work. Heck, I can't even get a servo to move to twenty degrees and back to zero. The servo library has a code that uses serial communication to make the servos move. I would like for them to move on their own, but in a controlled manner, that is, with a delay between the movements.

Here is some code to get you going, it moves six servos with delays determined by a pot on analog pin 0. Its not tested so you may need to do some debugging to get it working as you want. If you are not clear how the code moves the servos, read up on how pulse durations determine servo position. You may want to sprinkle some Serial.print statements in the code so you can see what is happening in the positionServo function. After you have the servos working as you want you can replace the pot with rangefinder code.

Good luck!

int servos[6] = {2,3,4,5,6,7}; // servos on pins 2 through 7)

int position1 = 1000;  // these are the two servo positions in microseconds
int position2 = 1500;

void setup(){  
 for( int i=0; i < 6; i++) 
    pinMode(i, OUTPUT);
 Serial.begin(9600);
}
 
 void positionServo( int servoIndex, int position, int durationMs){
// move the servo at the given index
// to the position (as microseconds between 750 and 2500)
// for the given nbr of milliseconds

  while(durationMs > 0){      
     digitalWrite(servos[servoIndex], HIGH);
     delayMicroseconds(position);
     digitalWrite(servos[servoIndex], LOW);
     delay(20);  // 20 millisecond delay between pulses is required for the servo
     durationMs -= 20;
  }
}


void loop(){
  int potValue = analogRead(0); // read the pot on analog pin 0
  
  for(int servo =0; servo < 6; servo++){
      int duration = potValue * 10; // delay between 0 and 10 seconds depending on pot value 
      positionServo(servo, position1, duration);
      positionServo(servo, position2, duration); // you may want different durations between these movements           
  }
}

Awesome! My servo is actually doing what I want it to do. I'll be sure to read up on pulse durations so I could change this around a bit. Thanks for your help.

Good to hear you are making progress. It looks to be an interesting project, keep us posted and perhaps post a video in the exhibition forum when its done.

I will be sure to show it off when it is completed. If you watched the video in the original post then imagine a stringed instrument instead of a hang drum.

imagine a stringed instrument instead of a hang drum

Something like a micro harpsichord?

BTW, one of the side affects of the simple servo code posted above is that the servos are only driven when the positionServo function is called. This is ok for an arrangement like the drum in the video clip because there is not much torque on the servo arms when they are idle. But be aware that when a servo is not being pulsed every 20ms or so, its holding torque is much reduced, so if your are swinging great big hammers at your strings, we may need add some refresh logic to the idle servos.

Have fun!

The instrument will be made by me! It will be mostly metal but with a fiberglass dome where the bridge and soundboard will be. Imagine a harp... but different. And I don't think the hammers will be that heavy. I don't exactly know right now what I will use but I will be sure to not make it very heavy. I want them to move pretty quick, so the less mass the "hammers" have the better.

looking forward to seeing/hearing it!

I have another question. There is a delay when the servo moves from position1 to position2. This delay becomes longer when I move the pot to change the main delay between movements between different servos. Is there any way to remove this delay? Because if I do use hammers to strike the strings I would like them to hit the sting and immediately return to the first position. Right now the hammer would be resting on the string until its told to move back.

you can modify the last paramter in these two calls to positionServo

positionServo(servo, position1, strikeDuration);
positionServo(servo, position2, pauseDuration);

you would set strikeDuration as the total time (in milliseconds) for the hammer to move from rest to hit the instrument

pauseDuration is the total time for the hammer to move back and pause in its rest position before the next hammer starts to move

Neat! The hammer is coming back real quick now.

I orders a couple more servos so I could test out having multiple servos. Right now I only have one. Looking at the code, shouldn't I be able to hook up a servo on 2 through 13 by changing a few digits in the code? Because right now its only set up for pins 2 through 7.

Yes, and you can even do 2 through 19 if you need that many. 14 through 19 are the same as analog pins 0 through 5.

Just add the servo pins to the servos array and change the 6 to the number of servos in the places this is used in the code. If you want to, you could replace the constant 6 with a #define

#define NUMBER_OF_SERVOS 6
int servos[NUMBER_OF_SERVOS] = {2,3,4,5,6,7};

for( int i=0; i < NUMBER_OF_SERVOS; i++)

Mem -- this is great stuff. Thanks for sharing, here and everywhere on this forum.

Jimmy -- I am also keenly interested in your project, as I'm working on something almost exactly the same. Inspired by the "Ruby on Bells" Arduino project (Ruby on Bells -- RAD Madrona Fork on Vimeo), I decided to make something similar, using windchime tubes from a local manufacturer (http://www.musicofspheres.com/) instead of water glasses. I want to do something like what you envision -- build a device that plays music and varies itself based on environmental inputs.

My hangup is that I have virtually no experience solving the mundane problems of how to technically construct the thing: what kind of hammers to use, how to mount them securely and attractively to the servos, how to build the infrastructure to hold the tubes, how to mount the motors to the cabinet, how to make the whole piece look like a craftsman made it, etc.

Please keep us posted on your progress!

Mikal

Yes yes, Big thanks to mem for helping me out. I certanly couldn't have gotten this far without you. I definatly couldn't have figured out this code without your help.

mikalhart, I too saw the Ruby on Bells video, along with some others, that gave me the idea to do a stringed instrument. With my instrument I plan on hiding the servos and hammers within the "body" of the instrument. The body will be a 15 inch diameter half sphere. I plan to place the arduino and servos in the half sphere and hope to have enough room for the hammers to move freely. I will be making this by hand out of fiberglass, so if its too small I could always change it up a bit. The bridge of the instrument will also be mounted to the inside of the half sphere, making the strings appear as if they were not mounted to anything in perticular. Maybe I should scan in my sketches for this to make more sense. ;D

But what I am getting at is that you don't have to make the servos exposed. You could fabricate a nice wooden inclosure to hide the servos and such. I know it would be difficult to make servos and hammers apear attractive. That is why I'm choosing to hide them. I also want people to question how an instrument is playing itself. :slight_smile:

Wonderful. Thanks. Please do scan the sketches if and when it seems appropriate. Is it easy to synthesize stuff from fiberglass?

M