Creating a "purring" animal with a vibra

Hi everyone :D

I have a bit of a random question. I want to set a little toy up that feels as though it's purring really gently and inaudibly in response to a sensor input.

I'm reasonably confident about setting up the code for these conditions, but i'm having trouble setting up a circuit. I have a small vibration motor at 2-3.6V (http://www.coolcomponents.co.uk/catalog/product_info.php?products_id=177) which I'm running from a coin battery at 1.55V (http://www.dc-battery.co.uk/MAXELL+LR1120.html) in an effort to get it to vibrate more slowly, as it it too noisy and frankly sex-toy like at present.

This isn't working however, so my first question is, how can I make this thing vibrate more slowly? Can I "gear it down" somehow?

Secondly, and linked in, the arduino works at 5V and i don't want to put 5V into the motor. How can I set up a circuit which will put less voltage through it?

Sorry for the noobish questions, any pointers greatly appreciated!

-Susan

If you want a slow purr then I am afraid you have bought the wrong motor. You want something more like the larger ones found in playstation controllers.

That little vibration motor is designed more for notification buzzing like a mobile phone would do.

Mowcius

Hi! thanks for the advice, I'll see what else i can find.

Perhaps you want something like this... http://www.goldmine-elec-products.com/prodinfo.asp?number=G16777

Nope, that is still a notification buzzer such as is found in mobile phones.

You want something more like this:

Mowcius

Thanks for the pictures! I've manged to get my hands on an old wiimote, which has a rumble feature, but am having trouble getting into it as it has screws with a 3 pronged hole instead of a phillips or straight edge. I might just smash the thing.

I am having a bit of trouble with my code too... can arduino simultaneously send out data through the digital pins while reading data from the analog pins?

Thanks for the pictures! I've manged to get my hands on an old wiimote, which has a rumble feature, but am having trouble getting into it as it has screws with a 3 pronged hole instead of a phillips or straight edge. I might just smash the thing.

The motor in that should be better...

I would recommend a hex screwdriver and a dremel to take off 3 prongs :P That's what my 3 pronged screwdriver is... If not then sometimes you can manage with a very small flat bladed screwdriver. If you don't want to use the wii remote any more then you could drill out the heads of the screws. There are loads of other things you can use the wii remoter for (like IR LED tracking for multitouch etc) so don't just 'smash it' ;)

You probably want to look up interrupts if you want to do two things at the same time.

Mowcius

Thanks for the hint! I think my other half has just obliterated the screws with a dremel, so i hope i can salvage the rest of it!

Ah, i see, my code might be doomed to failure then. I’m trying to put a loop inside a function and it doesn’t like it >_<

Thanks for the hint! I think my other half has just obliterated the screws with a dremel, so i hope i can salvage the rest of it!

Yeah you should be able to... :)

Mowcius

Ah, i see, my code might be doomed to failure then. I’m trying to put a loop inside a function and it doesn’t like it >_<

Show us the code. Putting a loop in a function is easy. Putting the loop function inside a function is impossible.

Thanks for the hint! I think my other half has just obliterated the screws with a dremel, so i hope i can salvage the rest of it!

These kinds of screws are called “security screws”, and are meant to keep consumers out of devices, which is kinda pointless IMO, because you can pick up the bits to remove them, and cheaply:

http://www.harborfreight.com/100-piece-security-bit-set-91310.html
http://www.harborfreight.com/33-piece-security-bit-set-93388.html

If you are into “hacking” consumer devices (aren’t we all?), you owe it to yourself to purchase a set somewhere.

:slight_smile:

ah, good hint! If i want the actual circuit board intact… (oops…)

Ok, i’ll post my code… i’m having a bit of trouble, so if anyone can give me any hints that’s be great!

//this is a program designed to create a "purring" 
//interaction with a small coin vibration motor (2-3v)

//map:
//if analogue value is greater than threshold, add one to count 
//only add one per "sense"
//time between senses = waitTime
//if waitTime is greater than 3 seconds, reset count
//if count is less than 3 do nothing
//if count is more than 3 and less than 7, do purr1
//if count is more than 7, do purr 2
//purr1 is a slowly rising and falling analog output
//purr2 is a slowly rising and falling analog output which is larger than purr1



const int analogPin = 0;   //pin with sensor on it
const int ledPin = 9;   //led output
const int threshold = 10;  //threshold
//set up previous value variable
int prevValue=300; 
//set up previous time variable
int prevmillis = 0;
//start up wait time variable
int waitTime = 0;
//start counter
int count = 0;


void setup() {
//initialize led pin output
pinMode(ledPin, OUTPUT);
//serial communication
Serial.begin(9600);

}


// read in analog values. If analogue value is greater than threshold, add one to count

void loop() {

//read value of sensor
int analogValue = analogRead(analogPin);

//is button pressed?
if (analogValue <= threshold && prevValue > threshold ){

// do the function  
int doFunction;
doFunction= myPurrFunction();

}else{

//no = do nothing
}
//set new previous value
 prevValue=analogRead(analogPin);

 delay(10);
}






//my function

int myPurrFunction(){
  
  //check wait time
    waitTime = (millis() - prevmillis);
    prevmillis= millis();
    Serial.print ("Wait time:"); Serial.println (waitTime);
  
  if(waitTime < 5000){ //if the delay between presses (waitTime) is less than 5 sec
  
  //add one to count
count ++;
Serial.print ("count: "); Serial.println (count);
  
      if ((count > 0)&&(count <= 3)){
            //do nothing,

                //Serial.print ("count: "); Serial.println (count);
               }
        if ((count > 3)&&(count <= 7)){
                Serial.println ("smallpurr");
                //do function PurrFunctionSoft
                int doFunction2;
                doFunction2= PurrFunctionSoft();
                
               }

        if (count > 7){
            Serial.println ("bigpurr");
          //do function PurrFunctionHard
          int doFunction3;
          doFunction3= PurrFunctionHard();
    }
}else{//reset count
  count=0;}
}


int PurrFunctionSoft(){
                void loop(){
                // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 125; fadeValue +=10) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 125 ; fadeValue >= 0; fadeValue -=5) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                }  
                  }
                }
                
        int PurrFunctionHard(){
           void loop(){
          // fade in from min to max in increments of 5 points:
          for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
          // sets the value (range from 0 to 255):
          analogWrite(ledPin, fadeValue);         
          // wait for 30 milliseconds to see the dimming effect    
          delay(30);                            
          } 

          // fade out from max to min in increments of 5 points:
          for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
          // sets the value (range from 0 to 255):
          analogWrite(ledPin, fadeValue);         
           // wait for 30 milliseconds to see the dimming effect    
          delay(30);  }                          
          } 
         }

It really doesn’t like the void loop parts in my two “purring” functions. The counting up and the myWait value both work fine, but getting the vibration out isn’t working :frowning:

Any help would be awesome!

ah ha! it seems to like it when i change the functions to do/while loops…

int PurrFunctionSoft(){
                do{
                // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 125; fadeValue +=10) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 125 ; fadeValue >= 0; fadeValue -=5) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                }  
                  }while((count > 3)&&(count <= 7));
                }
                
        int PurrFunctionHard(){
           do{
          // fade in from min to max in increments of 5 points:
          for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
          // sets the value (range from 0 to 255):
          analogWrite(ledPin, fadeValue);         
          // wait for 30 milliseconds to see the dimming effect    
          delay(30);                            
          } 

          // fade out from max to min in increments of 5 points:
          for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { 
          // sets the value (range from 0 to 255):
          analogWrite(ledPin, fadeValue);         
           // wait for 30 milliseconds to see the dimming effect    
          delay(30);  }                          
          }while( count <7); 
         }

But it stops reading the sensor input once it starts the PurrFunctionSoft function! buhhh, is this something i need to use inturrupts for?

An if block is not a loop. A do/while is. So is a for loop. So adding loops making it work makes sense.

A do/while loop is usually used when the number of iterations is not know. Do something while the switch is off. Do something while the temperature is below 40 degrees.

A for loop is usually used when the number of iterations is known.

In the PurrFunctionSoft, you have a do/while loop that executes while count is greater than 3 and less than or equal to 7. Nothing in the function changes the value of count. How does PurrFunctionSoft ever return?

Same question for PurrFunctionHard.

I'm sorry, I'm a real noob at this. Should i use a for loop? the sensor adds to the count but the code bit for that is in the initial loop, how can i get it to return to that? or should i write it again?

I'm really confused :(

There are some issues with your code. Both PurrFunctionSoft and PurrFunctionHard are defined to return integer values, but neither contains a return statement to actually return a value.

The value that isn't returned (by MyPurrFunction that was the predecessor of PurrFunctionSoft and PurrFunctionHard) is then stored in a variable that is never referenced again.

What value should the purr functions return? Or should the function return types be void?

Once the function is called, the value of count is not changed inside the function, so neither will ever return. Since that is probably not what you want, then, yes, you should write it again.

Start by explaining what you want to have happen, in English (or whatever your native language is). Then, write code to implement those statements.

Ok, I'll write it out. deep breath Ideally:

Program starts If the sensor is pressed, it adds one to the count If the sensor is pressed four times, the motor starts "purring" softly The motor continues to "purr" while the sensor continues to be pressed, each time adding 1 to the count When the count reaches 8 the motor starts "purring" harder. If the sensor is not pressed for 5 seconds, the motor slows and stops gradually.

The purr functions should "purr" once, and return. That is, cycle up to full speed then back down to stopped. No do/while loop in either one.

The appropriate purr function, based on count, should be called each pass through loop, if there has been a sensor change in the last 5 seconds. Don't forget to decrement count if 5 seconds elapses with no sensor change.

Ok, here’s what I have so far, it seems to work right up to the first slow purr “if” function, then stops doing anything. I tried to do as you suggested, just putting an “if” instead of a “while”. Any clues on what i’m doing wrong?

//second attempt at purring function

//Program starts
const int analogPin = 0;   //pin with sensor on it
const int ledPin = 9;   //led output
const int threshold = 10;  //threshold
//set up previous value variable
int prevValue=300; 
//set up previous time variable
int prevmillis = 0;
//start up wait time variable
int waitTime = 0;
//start counter
int count = 0;


void setup() {
//initialize led pin output
pinMode(ledPin, OUTPUT);
//serial communication
Serial.begin(9600);

}

//If the sensor is pressed, it adds one to the count, but only once per count
void loop() {

//read value of sensor
int analogValue = analogRead(analogPin);

//is button pressed?
if (analogValue <= threshold && prevValue > threshold ){
//add one to the count
count++;
int prevmillis=millis();
}else{

//no = do nothing
}
//set new previous value
 prevValue=analogRead(analogPin);

delay(10);

//If the sensor is pressed four times, the motor starts "purring" softly
if ((count > 3)&&(count <= 7)){
                // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 125; fadeValue +=10) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 125 ; fadeValue >= 0; fadeValue -=5) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                }  
                  }
//When the count reaches 8 the motor starts "purring" harder.                   
if (count > 7){
                // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 125; fadeValue +=10) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 125 ; fadeValue >= 0; fadeValue -=5) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                }  
                  }                  

//The motor continues to "purr" while the sensor continues to be pressed, each time adding 1 to the count 
//If the sensor is not pressed for 5 seconds, the motor slows and stops gradually. 
int myWait = millis() - prevmillis;
if (myWait > 5000){
  //reset count
  count=0;
}
}
prevValue=analogRead(analogPin);

The previous value equals a new reading? I don't think so. Set prevValue to analogValue.

int prevmillis=millis();

This declares a new variable (of the wrong type) that immediately goes out of scope (no longer exists). Not a particularly useful thing to do.

int myWait = millis() - prevmillis;
if (myWait > 5000){
  //reset count
  count=0;
}

The global prevmillis never gets valued, so it retains it's original value, which is 0. So, myWait is always set to not. After the Arduino has been running for 5 seconds, count will be set to 0 on every pass through loop.

The local variable prevmillis declared inside loop hides the global variable. It should not be declared and used. Use the global variable, instead.

Also, millis() returns a value whose type is unsigned long, not int.

Problem resolved!

I got the effect I was after using this code:

//second attempt at purring function

//Program starts
const int analogPin = 0;   //pin with sensor on it
const int ledPin = 9;   //led output
const int threshold = 100;  //threshold

//set up previous time variable
int prevmillis = 0;
//start up wait time variable
int waitTime = 0;
//start counter
int count = 0;


void setup() {
//initialize led pin output
pinMode(ledPin, OUTPUT);
//serial communication
Serial.begin(9600);

}

//If the sensor is pressed, it adds one to the count, but only once per count
void loop() {
//read value of sensor
int analogValue = analogRead(analogPin);

//is sensor being touched?
if (analogValue <= threshold){
//add one to the count
count++;
Serial.print ("count: "); Serial.println (count);

prevmillis=millis();
}

delay(10);

//If the sensor is pressed four times, the motor starts "purring" softly
if ((count > 40)&&(count <= 45)){
                // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 80; fadeValue +=2) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 80 ; fadeValue >= 0; fadeValue -=2) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
  
                    
                delay(30);
              }                            
                //make sure there is nothing
                analogWrite(ledPin, 0);
                // wait for 30 milliseconds to see the dimming effect
                //stop
                
                waitTime = millis() - prevmillis;
                Serial.print ("waitTimesoft: "); Serial.println (waitTime);

                    if (waitTime > 5000){
                   
                      //do slow purr once
                     // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 60; fadeValue +=1) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 60 ; fadeValue >= 0; fadeValue -=1) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
  
                    
                delay(30);
              }
                     Serial.print ("slooooowwww purr");
                      //reset count
                    count=0;
                    }
                
                
                return;
                
              }  
                  
//When the count reaches 8 the motor starts "purring" harder.                   
if (count > 45){
                // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 120; fadeValue +=4) { 
                // sets the value (range from 0 to 120):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 120 ; fadeValue >= 0; fadeValue -=4) { 
                // sets the value (range from 0 to 120):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);
                }
                //make sure there is nothing
                analogWrite(ledPin, 0);
                //stop
                
                waitTime = millis() - prevmillis;
                Serial.print ("waitTimehard: "); Serial.println (waitTime);

                    if (waitTime > 5000){
                    
                    //do slow purr once
                     // fade in from min to max in increments of 10 points:
                for(int fadeValue = 0 ; fadeValue <= 60; fadeValue +=1) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
                // wait for 30 milliseconds to see the dimming effect    
                delay(30);                            
                 } 

                // fade out from max to min in increments of 5 points:
                for(int fadeValue = 60 ; fadeValue >= 0; fadeValue -=1) { 
                // sets the value (range from 0 to 125):
                analogWrite(ledPin, fadeValue);         
  
                    
                delay(30);
                }
                  Serial.print ("slooooowwww purr");
                    
                    //reset count
                    
                    count=0;
                    }
                
                
                return;
                
                }  
                                    

//The motor continues to "purr" while the sensor continues to be pressed, each time adding 1 to the count 
//If the sensor is not pressed for 5 seconds, the motor slows and stops gradually. 
 //define waittime  


}

Thanks for all your help!

-Susan