USB Library conflict with rangefinder?

I have been playing around with a "virtual" USB shield and library – it's pretty incredible. Very very simple, but the power in being able to send HID via Arduino is so rad.

I'm having an issue that I can't identify, when I try to use it in conjunction with an ultrasonic rangefinder. I'm telling it to look at whether the distance is increasing or decreasing, and send a keypress for each if statement. It works 5% of the time at best. I know my sensor is fine and the shield is working with it, I've tested other sketches not using the vUSB library, and I'm getting good readings from the sensor. I also know that the vUSB end of things is working – I'm able to do basics, such as sending a keypress when a button is pressed. It's when I combine the two that it stops working? what am I not seeing here?

#include "UsbKeyboard.h"

// for the usb --------------------------------
// If the timer isr is corrected
// to not take so long change this to 0.
#define BYPASS_TIMER_ISR 1
// for the usb --------------------------------

int aVolt=A1; //naming analog-in 1 as "aVolt"
int distance; // voltage from sensor
int pdistance; // previous voltage

void setup() {
  
  pinMode(aVolt, INPUT);  // sets "aVolt" as an input
  
  //timer for usb  ---------------------------------------
  #if BYPASS_TIMER_ISR
  // disable timer 0 overflow interrupt (used for millis)
  TIMSK0&=!(1<<TOIE0); // ++
  #endif
  //timer for usb -----------------------------------------
  
}


//timer for usb -------------------------------------------
#if BYPASS_TIMER_ISR
void delayMs(unsigned int ms) {
   /*
  */ 
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}
#endif
//timer for usb -------------------------------------------


void loop() {
  UsbKeyboard.update();
  distance = analogRead(aVolt);  //defines "distance" as the analog voltage input to aVolt
  // comenting this out for now // distance = map(distance,170,20,0,32); 
  // commenting this out for now // distance = constrain(distance,0,32);

  digitalWrite(13, !digitalRead(13)); // don't know what this is for
  
  
  if (distance > pdistance) {               // if you move further away
      UsbKeyboard.sendKeyStroke(KEY_F10);   // F10 is pressed
      #if BYPASS_TIMER_ISR  // check if timer isr fixed.
      delayMs(20);
      #else
      delay(20);
      #endif
   }
   
   
  if (distance < pdistance) {              // if you move closer
    UsbKeyboard.sendKeyStroke(KEY_F12);    // F12 is pressed
      #if BYPASS_TIMER_ISR  // check if timer isr fixed.
      delayMs(20);
      #else
      delay(20);
      #endif    
   }

  pdistance = distance; // stores the value of distance
}

Ideas?
Here's the library: Google Code Archive - Long-term storage for Google Code Project Hosting.
Here's the shield: practicalarduino.com

I'm using an UNO and IDE v.21
The library is known to work in v.20, which I tried to no avail.

plz ignore the iron-burn on the side of the sensor ::slight_smile:

  digitalWrite(13, !digitalRead(13)); // don't know what this is for

Two comments about this. One, if you don't know what it's for, why is it (still) here?
Second, a digital pin is in either input mode, and digitalRead() means something, or it is in output mode, and digitalWrite() means something. While the pin mode can be changed, you are not doing that here, so one of these calls is going to fail.

Is there some reason to disable timer 0? I can't see it if there is.

  if (distance > pdistance) {               // if you move further away
  if (distance < pdistance) {              // if you move closer

Two questions. First, is it ever possible to execute both blocks of code? I don't see a way. So, the second should be an else if statement.

Second, nothing happens if the two values are equal. Is this by design? Is this the usual case, or are the values generally increasing or decreasing?

I don't see that you are using Serial.begin() in setup and Serial.print(ln)() in loop(). I'd use these to show the current and previous readings from the sensor. This way, you could determine if the problem is with the reading of the sensor or somewhere else.

  digitalWrite(13, !digitalRead(13)); // don't know what this is for

Two comments about this. One, if you don't know what it's for, why is it (still) here?
Second, a digital pin is in either input mode, and digitalRead() means something, or it is in output mode, and digitalWrite() means something. While the pin mode can be changed, you are not doing that here, so one of these calls is going to fail.

No, this is perfectly valid - digitalRead and digitalWrite are valid at all times. If a pin is an INPUT then digitalWrite controls the internal pull-ups, if a pin is an OUTPUT, digitalRead returns it state (so you don't need to remember it in a variable)

No, this is perfectly valid

I doubt that the intent of this code is to turn on and off the pull-up resistors. I can't imagine a case where that needs to be done.

It seems more likely that the code is trying to turn the LED on and off, which implies that it is an OUTPUT pin. The lack of a pinMode contra-indicates this, though.

So, we must assume that the pin is in it's default state of INPUT, and indeed the code is turning the pull-up resistors off and on. A strange thing to do, in my opinion.

It seems more likely that the code is trying to turn the LED on and off, which implies that it is an OUTPUT pin. The lack of a pinMode contra-indicates this, though.

That makes sense - when it was working very briefly, the LED would blink. I just kept it because I don't understand the vUSB library 100%, and found it being there, or not, didn't affect my program.

First, is it ever possible to execute both blocks of code? I don't see a way. So, the second should be an else if statement.

Is this necessary? I found that it (at least when I'm not using the rangefinder and vUSB together) behaved properly in choosing between two if statements.

I don't see that you are using Serial.begin() in setup and Serial.print(ln)() in loop(). I'd use these to show the current and previous readings from the sensor. This way, you could determine if the problem is with the reading of the sensor or somewhere else.

This is where it gets interesting? something fishy is going on with the serial data. Like I said, I'm able to use the shield & library just fine when doing something basic like a switch. It's sending serial data just fine, but there is some kind of weird glitch going on when it prints "setup finishes"

And that is via the following

#include "UsbKeyboard.h"

#define BUTTON_PIN 12

// If the timer isr is corrected
// to not take so long change this to 0.
#define BYPASS_TIMER_ISR 1

void setup() {
  Serial.begin(9600);    // setting serial port at speed of 9600 bits per second
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH);
  
#if BYPASS_TIMER_ISR
  // disable timer 0 overflow interrupt (used for millis)
  TIMSK0&=!(1<<TOIE0); // ++
#endif
 Serial.println("setup finishes");
}

#if BYPASS_TIMER_ISR
void delayMs(unsigned int ms) {
   /*
  */ 
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}
#endif

void loop() {
  
  UsbKeyboard.update();

  digitalWrite(13, !digitalRead(13));

  if (digitalRead(BUTTON_PIN) == 0) {
    
    //UsbKeyboard.sendKeyStroke(KEY_B, MOD_GUI_LEFT);
    
    UsbKeyboard.sendKeyStroke(KEY_H);
    UsbKeyboard.sendKeyStroke(KEY_E);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_O);

    UsbKeyboard.sendKeyStroke(KEY_SPACE);

    UsbKeyboard.sendKeyStroke(KEY_W);
    UsbKeyboard.sendKeyStroke(KEY_O);
    UsbKeyboard.sendKeyStroke(KEY_R);
    UsbKeyboard.sendKeyStroke(KEY_L);
    UsbKeyboard.sendKeyStroke(KEY_D);
    //UsbKeyboard.sendKeyStroke(KEY_B, MOD_GUI_LEFT);

    UsbKeyboard.sendKeyStroke(KEY_ENTER);
    Serial.print("Hello world");
    Serial.print(" \n");
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
    
   }

}

However, when I print serial data from the rangefinder, I get absolutely nothing, just the garbled version of "setup finishes". Again, I can get serial data just fine when I'm not using the vUSB library? i.e.

// getting voltage from the proximity sensor and re-mapping it to 32 "steps"
// no big deal
// pin hookup for sensor:
// bw  
// pw
// an = analog voltage out - input 5v yields 9.8mV/in
// rx 
// tx
// +5  
// gnd

int aVolt=A1; //naming analog-in 1 as "aVolt"

int distance; // naming variable for voltage
int pdistance; // naming variable for previous voltage and setting initial value to zero

void setup()
{
  Serial.begin(9600);    // setting serial port at speed of 9600 bits per second
  
 pinMode(aVolt, INPUT);  // sets "aVolt" as an input
 pinMode(13, OUTPUT);
 pinMode(12, OUTPUT);
 
 Serial.println("setup finishes");
}

void loop()
{
  
  
  distance = analogRead(aVolt);  //defines "distance" as the analog voltage input to aVolt
  distance = map(distance,170,20,0,32);
  distance = constrain(distance,0,32);
  
  if (distance > pdistance) {
    digitalWrite(13, HIGH);   // set the LED on
    digitalWrite(12, LOW);   // set the LED off
  }
  
  if (distance < pdistance) {
    digitalWrite(12, HIGH);   // set the LED on
    digitalWrite(13, LOW);   // set the LED off
  }
  
  Serial.print("you are this far"); // duh
  Serial.print(distance); // prints remapped voltage
  Serial.print(" "); //ending with a space
  Serial.print(" \n"); //line break
  pdistance = distance; // stores the value of distance
  delay(100); //computers need rest too

  
  
  
}

yields the following:

And this is with the sensor soldered on my vUSB shield. So this shows that the sensor is working fine with the shield, and we know that the shield is able to send HID just fine, from the 'hello world' test. So it's a question of what is causing the conflict between the sensor and library, or the vUSB syntax in the program. Hmmmm......

One of the questions that I asked earlier, that perhaps you missed, was why you are disabling timer 0. Lots of things depend on this timer. I see nothing in the code that suggests why doing so is necessary/desirable.

Is this necessary? I found that it (at least when I'm not using the rangefinder and vUSB together) behaved properly in choosing between two if statements.

Necessary? No.

On the other hand,

  if (distance > pdistance)
  {
  }
  else if (distance < pdistance)
  {
  }

means that the 2nd if does not need to be evaluated if the first if was true, and makes it clear that you recognize that the cases are mutually exclusive.

means that the 2nd if does not need to be evaluated if the first if was true, and makes it clear that you recognize that the cases are mutually exclusive.

Ah, now I get it!

Lots of things depend on this timer. I see nothing in the code that suggests why doing so is necessary/desirable.

I don't understand it, but according to Jonathan Oxer, one of the contributors to the vUSB project:

  // Disable timer0 since it can mess with the USB timing. Note that
  // this means some functions such as delay() will no longer work.

(from VirtualUsbKeyboard/VirtualUsbKeyboard.pde at master · practicalarduino/VirtualUsbKeyboard · GitHub)

Good news though – with some fiddling I was able to get it half-working?
At this point I'm getting serial.print to work, AND getting it to send a keystroke. The weird thing is, it will only do one keystroke. In other words, if I make the contents of my first if statement a keystroke, everything stops working. Quite strange indeed?

#include <UsbKeyboard.h>

int aVolt=A1; //naming analog-in 1 as "aVolt"

int distance; // naming variable for voltage
int pdistance; // naming variable for previous voltage and setting initial value to zero

// If the timer isr is corrected
// to not take so long change this to 0.
#define BYPASS_TIMER_ISR 1

void setup()
{
  Serial.begin(9600);    // setting serial port at speed of 9600 bits per second
  
 pinMode(aVolt, INPUT);  // sets "aVolt" as an input
 pinMode(13, OUTPUT);
 
 Serial.println("setup finishes");
 
 #if BYPASS_TIMER_ISR
  // disable timer 0 overflow interrupt (used for millis)
  TIMSK0&=!(1<<TOIE0); // ++
#endif
 
   // Clear interrupts while performing time-critical operations
  cli();

  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();
 
}


#if BYPASS_TIMER_ISR
void delayMs(unsigned int ms) {
   /*
  */ 
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}
#endif



void loop()
{
  UsbKeyboard.update();
//  digitalWrite(13, !digitalRead(13));
  distance = analogRead(aVolt);  //defines "distance" as the analog voltage input to aVolt
  distance = map(distance,170,20,0,32);
  distance = constrain(distance,0,32);

  if (distance > pdistance) {
    digitalWrite(13, HIGH);   // set the LED on
  }
  
  else if (distance < pdistance) {
     UsbKeyboard.sendKeyStroke(KEY_F10);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  }
  
  Serial.print("you are this far"); // duh
  Serial.print(distance); // prints voltage... 
  Serial.print(" "); //ending with a space cause peter said so
  Serial.print(" \n"); //line break
  pdistance = distance; // stores the value of distance
  
  
}

To answer your earlier question, it is intentional that nothing occurs if distance = pdistance. As if all of this wasn't enough I'm going to have to dive into the library once it's actually working, because it wasn't written to support more than two simultaneous keypresses? such as UsbKeyboard.sendKeyStroke(KEY_B, MOD_GUI_LEFT); :o

OK, I have somewhat isolated the issue? it turns out that if rather than:

  if (distance > pdistance) {
     UsbKeyboard.sendKeyStroke(KEY_S, MOD_GUI_LEFT);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  Serial.print("zooming out");
  Serial.print(" \n"); //line break
  }
  
   if (distance < pdistance) {
     UsbKeyboard.sendKeyStroke(KEY_G, MOD_GUI_LEFT);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  Serial.print("zooming in");
  Serial.print(" \n"); //line break
  }

I replace "pdistance" with an integer, i.e.

  if (distance > 25) {
   UsbKeyboard.sendKeyStroke(KEY_S, MOD_GUI_LEFT);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  Serial.print("zooming out");
  Serial.print(" \n"); //line break
  }
  
   if (distance < 15) {
     UsbKeyboard.sendKeyStroke(KEY_G, MOD_GUI_LEFT);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  Serial.print("zooming in");
  Serial.print(" \n"); //line break
  }

it "works" but this of course is no help to me, since I need to send the keypresses ONLY when "distance" increases or decreases. Is there a better way of writing this than comparing "distance" to "pdistance"?

#include <UsbKeyboard.h>

int aVolt=A1; //naming analog-in 1 as "aVolt"

/*
  Smoothing Code By David A. Mellis  <dam@mellis.org>
  http://www.arduino.cc/en/Tutorial/Smoothing
*/


// Define the number of samples to keep track of.  The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input.  Using a constant rather than a normal variable lets
// use this value to determine the size of the readings array.
const int numReadings = 40;

int readings[numReadings];      // the readings from the proximity sensor
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int distance = 0;               // the average distance
int pdistance = 0;                  // the previous average distanace

// If the timer isr is corrected
// to not take so long change this to 0.
#define BYPASS_TIMER_ISR 1

void setup()
{
  Serial.begin(9600);    // setting serial port at speed of 9600 bits per second
   // initialize all the readings to 0: 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;     
 pinMode(aVolt, INPUT);  // sets "aVolt" as an input
 pinMode(13, OUTPUT);
 pinMode(12, OUTPUT);
 
 Serial.println("setup finishes");
 
 #if BYPASS_TIMER_ISR
  // disable timer 0 overflow interrupt (used for millis)
  TIMSK0&=!(1<<TOIE0); // ++
#endif
 
   // Clear interrupts while performing time-critical operations
  cli();

  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();
 
}


#if BYPASS_TIMER_ISR
void delayMs(unsigned int ms) {
   /*
  */ 
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}
#endif



void loop()
{
  UsbKeyboard.update();
  
   // subtract the last reading:
  total= total - readings[index];         
  // read from the sensor:  
  readings[index] = analogRead(aVolt); 
  // add the reading to the total:
  total= total + readings[index];       
  // advance to the next position in the array:  
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)              
    // ...wrap around to the beginning: 
    index = 0;                           

  // calculate the average:
  distance = total / numReadings;
  
//  digitalWrite(13, !digitalRead(13));
  distance = analogRead(aVolt);  //defines "distance" as the analog voltage input to aVolt
 distance = map(distance,125,12,0,32);
 distance = constrain(distance,0,32);

  if (distance > pdistance) {
    // UsbKeyboard.sendKeyStroke(KEY_S, MOD_GUI_LEFT);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  Serial.print("zooming out");
  Serial.print(" \n"); //line break
  }
  
   if (distance < pdistance) {
     UsbKeyboard.sendKeyStroke(KEY_G, MOD_GUI_LEFT);
digitalWrite(13, LOW);   // set the LED off
#if BYPASS_TIMER_ISR  // check if timer isr fixed.
    delayMs(20);
#else
    delay(20);
#endif
  Serial.print("zooming in");
  Serial.print(" \n"); //line break
  }
  
 /* Serial.print("you are this far"); // duh
  Serial.print(distance); // prints voltage... 
  Serial.print(" "); //ending with a space cause peter said so
  Serial.print(" \n"); //line break */
  pdistance = distance; // stores the value of distance
  
  
}

Any ideas?

You have some stuff in the code that is not right.

int aVolt=A1; //naming analog-in 1 as "aVolt"

The value assigned to A1 is 15 on the Duemilanove. Did you plug your sensor into analog pin 15?

The value for aVolt needs to match the pin number you are trying to read from, most likely 1.

 pinMode(aVolt, INPUT);  // sets "aVolt" as an input

Analog pins are read only. The pinMode command affects the digital pins. Are you planning to use this pin as a digital pin or an analog pin?

const int numReadings = 40;

int readings[numReadings];      // the readings from the proximity sensor
  total= total - readings[index];        
  // read from the sensor:  
  readings[index] = analogRead(aVolt);
  // add the reading to the total:
  total= total + readings[index];      
  // advance to the next position in the array:  
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)              
    // ...wrap around to the beginning:
    index = 0;                          

  // calculate the average:
  distance = total / numReadings;

Average a bunch of readings. Good.

  distance = analogRead(aVolt);  //defines "distance" as the analog voltage input to aVolt
 distance = map(distance,125,12,0,32);
 distance = constrain(distance,0,32);

Then, throw the average out and use a single reading, instead. Why?

Do you KNOW that distance is in the range 125 to 12? Why is that range inverted? You don't read distance from an analog pin. You read voltage. Distance may be a function of voltage, but it is rarely a 1-1 correspondence, either.

digitalWrite(13, !digitalRead(13)); // don't know what this is for

@PaulS:

I doubt that the intent of this code is to turn on and off the pull-up resistors. I can't imagine a case where that needs to be done.

It seems more likely that the code is trying to turn the LED on and off, which implies that it is an OUTPUT pin. The lack of a pinMode contra-indicates this, though.

So, we must assume that the pin is in it's default state of INPUT, and indeed the code is turning the pull-up resistors off and on. A strange thing to do, in my opinion.

You're right, it's missing a pinMode command. The example sketch in Practical Arduino includes the pinMode command and an explanation of what that line is trying to do.

Basically it's exploiting the fact that you can read from a pin even when it's in output mode, allowing the pin itself to act as a state flag that is inverted on each pass to cause the state to toggle. It just reads the pin, then writes the opposite value of that reading back to it.

Jon

For what it's worth, I had big problems trying to get VUSB to cooperate with analog readings. The timing is just too critical. For example, I did this little hack using a DS touchscreen to control Frozen Bubble:

My first attempt used one Arduino to read the touchscreen (which requires multiple analog reads) and then send the appropriate events to the host using VUSB. That totally failed, so for that video I used two Arduinos: 1 to read the touchscreen and interpret the coordinates to determine what event to send, and 1 running VUSB to send the actual event to the host. I just used digital I/O between the two so that the first Arduino could trigger USB events on the second.

Jon

Thanks for chiming in Jon!

For what it's worth, I had big problems trying to get VUSB to cooperate with analog readings. The timing is just too critical.

It just occurred to me? the sensor can also output digital serial and pulse width. Would I be likely to have better luck with those options? This is the model I'm using.http://maxbotix.com/uploads/LV-MaxSonar-EZ1-Datasheet.pdf

The value assigned to A1 is 15 on the Duemilanove. Did you plug your sensor into analog pin 15?

This hasn't been a problem, Paul. I'm using an UNO – reading the value via analog pin 1 has been fine, other issues aside. I'm remapping/constraining to 0-32 due to the nature of the software I am sending HID data to. Should I be applying the averaging after mapping and constraining? the 125-12 is not definite, I fine tune this depending on the room the device is in, but it is more or less close to the general max/min sensor outputs.

Here's the current state of things?

#include <UsbKeyboard.h>

int aVolt=A1; //naming analog-in 1 as "aVolt"

/*
  using a proximity sensor with Jonathan Oxer's vUSB shield, and Hugh Blemming's vUSB library
  to send a keypress when sensor value increases, and another when it decreases
  Virtual USB library built by Hugh Blemmings:  http://code.google.com/p/vusb-for-arduino/
  Virtual USB shield designed by Jonathan Oxer: http://www.practicalarduino.com/projects/virtual-usb-keyboard
  Smoothing Code By David A. Mellis  <dam@mellis.org>
  http://www.arduino.cc/en/Tutorial/Smoothing
  TODO: get it actually working.

*/


// Define the number of samples to keep track of.  The higher the number,
// the more the readings will be smoothed, but the slower the output will
// respond to the input.  Using a constant rather than a normal variable lets
// use this value to determine the size of the readings array.
const int numReadings = 40;

int readings[numReadings];      // the readings from the proximity sensor
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int distance = 0;               // the average distance
int pdistance = 0;                  // the previous average distanace
int pdistance2 = 0;

// If the timer isr is corrected
// to not take so long change this to 0.
#define BYPASS_TIMER_ISR 1

void setup()
{
  Serial.begin(9600);    // setting serial port at speed of 9600 bits per second
  // initialize all the readings to 0: 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
  readings[thisReading] = 0;     
  Serial.println("setup finishes");
 
  #if BYPASS_TIMER_ISR
  // disable timer 0 overflow interrupt (used for millis)
  TIMSK0&=!(1<<TOIE0); // ++
  #endif
 
   // Clear interrupts while performing time-critical operations
  cli();

  // Force re-enumeration so the host will detect us
  usbDeviceDisconnect();
  delayMs(250);
  usbDeviceConnect();

  // Set interrupts again
  sei();
 
}


#if BYPASS_TIMER_ISR
void delayMs(unsigned int ms) {
   /*
  */ 
  for (int i = 0; i < ms; i++) {
    delayMicroseconds(1000);
  }
}
#endif



void loop()
{
  
  UsbKeyboard.update();
  
  // subtract the last reading:
  total= total - readings[index];         
  // read from the sensor:  
  readings[index] = analogRead(aVolt); 
  // add the reading to the total:
  total= total + readings[index];       
  // advance to the next position in the array:  
  index = index + 1;                    
  // if we're at the end of the array...
  if (index >= numReadings)              
  // ...wrap around to the beginning: 
  index = 0;                           
  // calculate the average:
  distance = total / numReadings;
 
 distance = analogRead(aVolt);  //defines "distance" as the analog voltage input to aVolt
 distance = map(distance,125,12,0,32);
 distance = constrain(distance,0,32);
  
  
// if distance increases =====================================  
   if (distance > pdistance2) {
  //  UsbKeyboard.sendKeyStroke(KEY_S, MOD_GUI_LEFT);
        #if BYPASS_TIMER_ISR  // check if timer isr fixed.
        delayMs(20);
        #else
        delay(20);
        #endif
  Serial.print("zooming out");
  Serial.print(" \n"); //line break
  }
// if distance decreases =====================================
   if (distance < pdistance) {
   UsbKeyboard.sendKeyStroke(KEY_G, MOD_GUI_LEFT);
        #if BYPASS_TIMER_ISR  // check if timer isr fixed.
        delayMs(20);
        #else
        delay(20);
        #endif
   Serial.print("zooming in");
   Serial.print(" \n"); //line break
  }
// ===========================================================




  Serial.print("you are this far"); // duh
  Serial.print(distance); // prints voltage... 
  Serial.print(" "); //ending with a space cause peter said so
  Serial.print(" \n"); //line break 
  pdistance = distance; // stores the value of distance
  pdistance2 = distance;
  
  
}

the sensor can also output digital serial and pulse width

I haven't used that specific sensor before, but I'd certainly be tempted to try switching to digital comms for this purpose if the sensor supports it. Use the hardware UART though, not SoftwareSerial, otherwise you'll be back in the land of painful timing interactions.

Jon

Porcupine Electronics has an inexpensive way to add a USB interface to an off the shelf laser rangefinder. The laser rangefinder will be much more accurate than ultrasonic.