controlling a motor with pwm

Hi, I’m trying to make small device that uses an ultrasonic rangefinder and a motor to change the intensity of its vibration depending on how far away something is from the rangefinder. It uses a teensyduino and I have the rangefinder working with it and tested it by outputting a tone that changed with distance from the rangefinder, but I can’t figure out how to control the intensity of the motor. If I hook it up to a pwm pin, it vibrates but the vibration doesn’t change no matter what I send through the port.

Heres the code:

//#include <math.h>


int VIBRATION_PIN = 15;
int SOUNDOUT_PIN = 17;
int INPUT_PIN = 18;

double MAX_MOTOR = 255;

int VIBRATE = 0, SOUND = 1, CURRENT_MODE = 0;
double scaleFactor, inputVal;
unsigned long duration, value;
//long inputVal;  //pwm value from the rangefinder
int x = 1;
long FLOOR, CEILING, DIST;
double TONE_CEILING = 400;
int count = 0, ceiling = 50;
int soundOut, vibrationOut;

void setup(){
  pinMode( INPUT_PIN, INPUT);
  digitalWrite( INPUT_PIN, HIGH); // turn on internal pullup, pin will be HIGH unless connected to GND by switch

  scaleFactor = 0;  //ratio comprised of rangefinder input value over max rangefinder value, applied to max output(audio or vibration) to get output value
  //setMode( SOUND );  //just do this for now until we get vibration working
  Serial.begin( 9600 );
  FLOOR = 0;
  CEILING = 20000;
  DIST = CEILING - FLOOR;
  Serial.println( "Done" );
}

//main loop
void loop(){
  //pinMode( INPUT_PIN, INPUT );
  //duration = pulseIn( INPUT_PIN, HIGH );
  //duration = microsecondsToInches( duration );

    //Serial.println( "16" );
   // count++;
    //if( count > ceiling ){
      vibrationOut  = 200;//= ping();  200 IS JUST FOR TESTING PURPOSES
      //count = 0;
        
    //}
    
    //Serial.println( "16" );


  //send feedback in appropriate mode
  //if( CURRENT_MODE == SOUND){
    writeVibration( vibrationOut );
  //}
}

unsigned long ping(){
  /*pinMode( INPUT_PIN, OUTPUT );
  digitalWrite( INPUT_PIN, LOW );
  delayMicroseconds( 2 );
  digitalWrite( INPUT_PIN, HIGH );
  delayMicroseconds( 5 );
  digitalWrite( INPUT_PIN, LOW );*/

  pinMode( INPUT_PIN, INPUT );
  digitalWrite( INPUT_PIN, HIGH );
  //digitalWrite( INPUT_PIN, HIGH );

//calculate a ratio from the found range/max range and apply it to the max tone to calculate the tone to output
  duration = pulseIn( INPUT_PIN, HIGH );
  //Serial.println( duration );
  //duration = 200000;
  scaleFactor = ( DIST - duration );
  //printDouble( scaleFactor, 100 );
   double distTemp = DIST;
  scaleFactor /= distTemp;
  
  inputVal = MAX_MOTOR * scaleFactor;
  
    //printDouble( scaleFactor, 100 );
  //inputVal = TONE_CEILING - ( scaleFactor * TONE_CEILING );
  //printDouble( inputVal, 100 );
  return inputVal;
}

void printDouble( double val, unsigned int precision){
// prints val with number of decimal places determine by precision
// NOTE: precision is 1 followed by the number of zeros for the desired number of decimial places
// example: printDouble( 3.1415, 100); // prints 3.14 (two decimal places)

    Serial.print (int(val));  //prints the int part
    Serial.print("."); // print the decimal point
    unsigned int frac;
    if(val >= 0)
        frac = (val - int(val)) * precision;
    else
        frac = (int(val)- val ) * precision;
    Serial.println(frac,DEC) ;
}


//send tone signal
void writeTone( int freq ){
      pinMode( SOUNDOUT_PIN, OUTPUT );
  
  digitalWrite( SOUNDOUT_PIN, HIGH );
  //delayMicroseconds( freq );

  digitalWrite( SOUNDOUT_PIN, LOW );
  delayMicroseconds( freq );
}

void writeVibration( double intensity ){
  intensity = MAX_MOTOR - intensity;
  pinMode( VIBRATION_PIN, OUTPUT );
  
   digitalWrite( VIBRATION_PIN, HIGH );
   delayMicroseconds( (int)(intensity / 2) );
   //digitalWrite( VIBRATION_PIN, LOW );
   //delayMicroseconds( (int)(intensity / 2) );
}

thanks, any help would be really appreciated
-Sam

but I can't figure out how to control the intensity of the motor.

PWM will only control the speed of a motor subject to some mechanical load.

However, just try setting it to zero and it should be off, if setting it to 1 is no diffrent than setting it to 255 then there is not enough load to slow the motor down. You could try dropping the voltage you drive the motor with to 2V or so. I assume you are driving the motor through a transistor and not direct from the arduino. The other way might be to put a large capacitor across the motor to get true DC out of the PWM pin.

Also use PWM by analogWrite(VIBRATION_PIN,value) not:- digitalWrite( VIBRATION_PIN, HIGH );

alright, it worked! Thanks for your help!

for anyone interested, here’s the modified code

//program to vibrate a motor based on ultrasonic rangefinder data

int VIBRATION_PIN = 17;
int INPUT_PIN = 18;
unsigned long duration;  //the duration of the pwm signal that will be retrieved from the rangefinder
int maxCount = 200, count = 0;  //for counting so that it is not gathering rangefinder data every single refresh cycle
double vib_intensity = 0, vib_max = 255, vib_min = 90;
int ranges[] = { 700, 750, 800, 850, 900, 1000, 1250, 1500, 1750, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000, 7500, 8000, 9000, 10000 };  //for rounding


void setup(){
    Serial.begin( 9600 );
    pinMode( VIBRATION_PIN, OUTPUT );
    pinMode( INPUT_PIN, INPUT );
}

void loop(){
  count++;
  //if( count > maxCount ){
    vib_intensity = ping();
    //count = 0;
  //}
  vibrate( vib_intensity );
}

//returns the speed of the motor between 0 and 255 
double ping(){
  pinMode( INPUT_PIN, INPUT );
  duration = pulseIn( INPUT_PIN, HIGH );
  Serial.println( duration );
  duration = roundValue( duration );
  Serial.println( duration );
  
  double ratio = ( (double)duration - 700 ) / ( 10000 - 700 );
  double returnVal = 90 + ( ( 255 - 90 ) * ratio );
  printDouble( returnVal, 5 );
  return returnVal;
}

//write the vibration instensity
void vibrate( int intensity ){
  analogWrite( VIBRATION_PIN, intensity );
  delay( 1000 );
  //analogWrite( VIBRATION_PIN, LOW );
  //delay( 1000 );
}

int roundValue( long input ){
  if ( input < ranges[0] )
    return ranges[0];
  for ( int x = 1; x < 23; x++ ){
    if( input < ranges[x] && input >= ranges[x-1] )
      return ranges[x];
  }
  if( input >= ranges[23] )
    return ranges[23];
}

//got this from someone else
void printDouble( double val, unsigned int precision){
// prints val with number of decimal places determine by precision
// NOTE: precision is 1 followed by the number of zeros for the desired number of decimial places
// example: printDouble( 3.1415, 100); // prints 3.14 (two decimal places)

    Serial.print (int(val));  //prints the int part
    Serial.print("."); // print the decimal point
    unsigned int frac;
    if(val >= 0)
        frac = (val - int(val)) * precision;
    else
        frac = (int(val)- val ) * precision;
    Serial.println(frac,DEC) ;
}

now all that’s left is to put it in its case and hook it up to battery power