Friday, September 30, 2011

Sand Gloves

I started looking at the hand support options today.  I originally was considering using silicon coated modeling clay, but I don't think it will be quite stiff enough.  This morning, I grabbed a couple of latex medical type gloves and filled them with some wet sand.  Obviously, the laytex gloves are a temporary solution to play with.  The first one had way too much water in it and is too squishy.  On the second one, I went very sparingly on the water and it turned out much better.  It makes for a moldable blob that is very firm that should serve as a hand support.  Eventually, the buttons and trackball will be attached via velcro around the front and side portions.  This would allow the end user to rearrange the trackball and buttons in any order they want and custom fit the support to their hand.  It should allow maximum flexiblity and comfort. 

As you can see on the breadboard, I have three wires arranged as touch sensors (one with a quarter attached) for left, middle and right clicks.  I also got the scroll wheel functioning with the rotary encoder there on the board.  Lastly, there is a button and associated tri-color LED that is used to swap between the four user selectable resolution modes inside the optical sensor.  This essentially controls how much movement the pointer makes relative to the amount of movement you put into the trackball, allowing for either lightning fast moves or very slow accurate moving.  It operates somewhat like what happens when you change the gears on your bicycle.

3 comments:

  1. Something else you might try for easily allowing both fine control at slow speeds and fast movement with quick rolls is to scale the raw sensor readings down, then apply an exponential power, and finally scale them back up (if necessary). Use a float/double variable to store the raw readings, find a happy medium speed and use that for the scale factor. Then using something between 1 and 2 for the exponent (I've tried 1.3 with some success, but my hardware and application is very different from yours).

    For example, let's say your raw sensor readings range from 0 to 1000, where 0 is stopped and 1000 is as fast as the sensor will read. Let's also say that a reading of 150 is a reasonable "normal" speed. The X component of your calibrated speed could then be:

    xCalibrated = ((xRaw/150) ^ 1.5) * 150

    ...or, in Arduino:

    xCalibrated = pow(xRaw/150.0, 1.5) * 150;

    You might need to accommodate for both positive and negative raw sensor readings, something like this:

    xCalibrated += (xRaw < 0) ? -pow(-xRaw/150.0, 1.5) * 150 : pow(xRaw/150.0, 1.5) * 150;

    What happens is that the raw readings are scaled down by a factor of 150, so anything below 150 becomes less than 1, and anything above 150 is greater than 1. When this scaled value is raised to a power > 1, it will either shrink or grow further depending on whether it's less than or greater than 1. The result is that very slow movements of the ball will give you very, very slow movements of the cursor (fine control), while very quick movements of the ball will give you very, very fast movements of the cursor (good speed).

    It may or may not be helpful, but you can try it if you want. :-)

    ReplyDelete
  2. I like the idea of how that can work. I'm thinking that this is what would be known as software acceleration, and to a certain degree, deceleration on the fly. Ultimately, I would also like this to be used in my CAD work, in which, very slow, fine movements could benefit from something like this. Of course, gaming could also benefit.

    While I like what you are getting at, I need to find a way to implement it. Currently, I have the trackball setup on a hardware interrupt pin. When the optical sensor has data to read, it sends the motion pin low and executes the interrupt subroutine that just grabs the movement amount from the X & Y registers and passes that directly to Mouse.move(). Typically, the data is just a single “1” each time, and every once in a while, a “2” if I move it really super fast. The two are so in sync that it just sends a series of 1 normally though. So, implementation of something like this would probably involve storing times to determine the frequency of movement updates we're getting in the last x timeframe and then, apply what you are talking about to scale the movement based upon frequency. That could then be used as a multiplier with rounding against the series of 1's the sensor is sending, to determine if Mouse.move() gets an update or not. Does that sound about right?

    ReplyDelete
  3. Ah, that's an interesting issue with small readings all the time. Assuming your sketch runs at a pretty constant speed, you might be able to easily accomplish what you're going for just by sending the x/y movements only every [n] "ticks" through the main loop() function. Something like:

    loop() {

    loopCounter++;

    if (motionAvailable) {
    x += getXMovement();
    y += getYMovement();
    }

    if (loopCounter % 8 == 0) {
    Mouse.move(x, y);
    x = 0;
    y = 0;
    }

    }

    (Pardon the ugly formatting; Blogger won't let me put HTML in comments.)

    This is overly simple, of course, and it's missing variable declarations and other stuff, but it demonstrates the idea. The modulo will make sure the mouse is only moved once every 8 ticks, while each new reading is simply added to the x/y variables every time it's available. If only one "1" measurement gets taken during the whole 8-tick period, then the mouse will only move 1px at the end of the 8-tick period. But if it reads eight "1" measurements, then it will move 8px.

    It might have some problems that I'm not thinking of, but that simple approach would at least give you a larger range, perhaps between 0-10 instead of just 0-1. It might not feel quite as smooth though. Hmm.

    ReplyDelete