guidance for a mouse

Status
Not open for further replies.

cncdan

Member
Hi all what I would like to do is make a mouse useing a Thumb Joystick like this one https://www.sparkfun.com/products/9032 and have 2 micro switches for left and right click it will be set up on a wheel chair with the joystick on the end of one arm and the two switches on the other arm.

what I need is guidance on what is the best board to use, it will just be through the usb cable for a start to a laptop what will be on a table mounted to the wheel chair, later down the line I would like to run it through bluetooth.

any idea`s help will be most welcome

Daniel
 
The minimum Teensy you can still buy should be enough to cover your stated purposes - if concerned much then the Teensy 3.1 is easily over-powered for it and pretty cheap for its capabilities, the Teensy LC is a lot less powerful but (imho) still rates as over-powered here and is even cheaper again.

I expect I could meet your aims with a Teensy 1.0 but fairly sure they are not for sale any more - when you start playing with physical parts identify the serial pins you will use for serial later so you don't have to shift things around when you go to add bluetooth functionality.

imho it will be best if you mount Teensy reasonably close to where the thumbstick is mounted, the buttons will suffer less than the thumbstick for being further away.
 
Agreed, any Teensy could easily do this. Teensy-LC is the least expensive option.

Teensy 2.0 could also. It actually costs more than Teensy-LC, even though it's less powerful. Teensy-LC is much newer technology, which is why you get much more technical capability for a much lower price.

The only compelling feature you get with 2.0 that isn't on LC (which you don't need for this project) is every pin has 5V signals. On Teensy-LC, there's one output-only 5V pin. All the others are 3.3V signals only. In these modern times, 3.3V signals are much more common than 5V, so 5V signals can be a big disadvantage if you're using stuff like the ILI9341 display that requires 3V signals. But 5 volt signals can be helpful if you're doing a project that involves connecting to lots of older stuff.
 
Sounds like a worthy cause to me (impression: enabling the less able) so don't hesitate to ask for help.
 
that's what it is for it`s for me for a start once I have it all worked out I will make them for other disabled people
I already have the table design`s done this is just the next step i can make up what`s required for 25% of what it cost to buy from medical suppler`s
 
Hi there all the bits have arrived I have put it together just a question on the code I am using the code from here https://brainy-bits.com/tutorials/a...nce for this axis: return distance; } [/CODE]
 
Looks to me like it should work - I haven't hardware configured the way you have so I cannot be 'that sure'. To be surer than I was at first it was easier to have something auto-format the code; I added your idea to the 'full code', the 'delay(100);' lines would very likely drive a gamer trying to use this out of their mind but it is probably OK for your purpose.
Code:
// Define Pins
const int startEmulation = 2;      // switch to turn on and off mouse emulation
const int mouseLeftButton = 4;    // input pin for the mouse left Button
const int mouseRightButton = 3;    // input pin for the mouse left Button
const int joystickX = A1;         // joystick X axis
const int joystickY = A0;         // joystick Y axis
// parameters for reading the joystick:
int cursorSpeed = 10;               // output speed of X or Y movement
int responseDelay = 5;        // response delay of the mouse, in ms
int threshold = cursorSpeed / 4;    // resting threshold
int center = cursorSpeed / 2;       // resting position value
boolean mouseIsActive = false;    // whether or not to control the mouse
int lastSwitchState = LOW;        // previous switch state
void setup() {
  pinMode(startEmulation, INPUT_PULLUP);   // the switch pin
  pinMode(mouseLeftButton, INPUT_PULLUP);  // the left mouse button pin
  pinMode(mouseRightButton, INPUT_PULLUP);  // the left mouse button pin
  Mouse.begin();  // take control of the mouse
}
void loop() {
  // read the switch:
  int switchState = digitalRead(startEmulation);
  // if it's changed and it's high, toggle the mouse state:
  if (switchState != lastSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
    }
  }
  // save switch state for next loop:
  lastSwitchState = switchState;
  // read and scale the two axes:
  int xReading = readAxis(A1);
  int yReading = readAxis(A0);
  // if the mouse control state is active, move the mouse:
  if (mouseIsActive) {
    Mouse.move(xReading, yReading, 0); // (x, y, scroll mouse wheel)
  }
  // read the mouse button and click or not click:
  // if the mouse button is pressed:
  if (digitalRead(mouseLeftButton) == HIGH) {
    // if the mouse is not pressed, press it:
    if (!Mouse.isPressed(MOUSE_LEFT)) {
      Mouse.press(MOUSE_LEFT);
      delay(100); // delay to enable single and double-click
    }
  }
  // else the mouse button is not pressed:
  else {
    // if the mouse is pressed, release it:
    if (Mouse.isPressed(MOUSE_LEFT)) {
      Mouse.release(MOUSE_LEFT);
    }
  }

  if (digitalRead(mouseRightButton) == HIGH) {
    // if the mouse is not pressed, press it:
    if (!Mouse.isPressed(MOUSE_RIGHT)) {
      Mouse.press(MOUSE_RIGHT);
      delay(100); // delay to enable single and double-click
    } // Rob's note: 'delay(x);' is not the best way to deal with timing where two (or more) events may be desirable to capture simulataneously.
  }
  // else the mouse button is not pressed:
  else {
    // if the mouse is pressed, release it:
    if (Mouse.isPressed(MOUSE_RIGHT)) {
      Mouse.release(MOUSE_RIGHT);
    }
  }

  delay(responseDelay);
}
/*
reads an axis (0 or 1 for x or y) and scales the
analog input range to a range from 0 to <range>
*/
int readAxis(int thisAxis) {
  // read the analog input:
  int reading = analogRead(thisAxis);
  // map the reading from the analog input range to the output range:
  reading = map(reading, 0, 1023, 0, cursorSpeed);
  // if the output reading is outside from the
  // rest position threshold,  use it:
  int distance = reading - center;
  if (abs(distance) < threshold) {
    distance = 0;
  }
  // return the distance for this axis:
  return distance;
}
 
thanks Paul got it all working just need to adjust and try and make it better get ride of the delays and that sort of thing

thanks all and by golly these boards are tiny
 
The Bounce library is usually the easiest (and best) way to avoid those delays. Pressing one button won't delay any of the others when you use Bounce. It's also simpler and easier to use than building your own with digitalRead.

Look at File > Examples > Teensy > USB_Joystick > Buttons for an example.
 
I have it working with bounce library that part work very well

the mouse movement using the joystick is a bit problematic it need to be adjusted speed of movement, delay if I changes those settings it runs away is there a better way of controlling the joystick.


Code:
#include <Bounce.h>

/// Define Pins
const int startEmulation = 2;      // switch to turn on and off mouse emulation
/////////////////////////////////////////////////////////////////////////////////
const int joystickX = A1;         // joystick X axis
const int joystickY = A0;         // joystick Y axis
// parameters for reading the joystick:
int cursorSpeed = 7;               // output speed of X or Y movement
int responseDelay = 5;        // response delay of the mouse, in ms
int threshold = cursorSpeed / 4;    // resting threshold
int center = cursorSpeed / 2;       // resting position value
boolean mouseIsActive = false;    // whether or not to control the mouse
int lastSwitchState = LOW;        // previous switch stat
//////////////////////////////////////////////////////////////////////////////////////
// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce button3 = Bounce(4, 10);  // if a button is too "sensitive"
Bounce button4 = Bounce(5, 10);  // to rapid touch, you can
Bounce button5 = Bounce(3, 10);  // increase this time.

byte left = 0;
byte middle = 0;
byte right = 0;
/////////////////////////////////////////////////////////////////////////////////

void setup() {
  pinMode(startEmulation, INPUT_PULLUP);   // the switch pin
  ///////////////////////////////////////////////////////////////////////////////////
  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);


  //////////////////////////////////////////////////////////////////////////////////
  Mouse.begin();  // take control of the mouse
}
void loop() {
  // read the switch:
  int switchState = digitalRead(startEmulation);
  // if it's changed and it's high, toggle the mouse state:
  if (switchState != lastSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
    }
  }
  // save switch state for next loop:
  lastSwitchState = switchState;
  // read and scale the two axes:
  int xReading = readAxis(A1);
  int yReading = readAxis(A0);
  // if the mouse control state is active, move the mouse:
  if (mouseIsActive) {
    Mouse.move(xReading, yReading, 0); // (x, y, scroll mouse wheel)
  }

  ///////////////////////////////////////////////////////////////////////////////////////////////////
  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.
  button3.update();
  button4.update();
  button5.update();

  // this variable will let us know if any button changes
  byte anyChange = 0;

  // Check each button for "falling" edge.
  // Change a mouse button when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)
  if (button3.fallingEdge()) {
    left = 1;
    anyChange = 1;
  }
  if (button4.fallingEdge()) {
    middle = 1;
    anyChange = 1;
  }
  if (button5.fallingEdge()) {
    right = 1;
    anyChange = 1;
  }

  // Check each button for "rising" edge
  // Change a mouse button when each button releases.
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)
  if (button3.risingEdge()) {
    left = 0;
    anyChange = 1;
  }
  if (button4.risingEdge()) {
    middle = 0;
    anyChange = 1;
  }
  if (button5.risingEdge()) {
    right = 0;
    anyChange = 1;
  }

  // if any changes were made, update the Mouse buttons
  if (anyChange) {
    Mouse.set_buttons(left, middle, right);
  }
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
reads an axis (0 or 1 for x or y) and scales the
analog input range to a range from 0 to <range>
*/
int readAxis(int thisAxis) {
  // read the analog input:
  int reading = analogRead(thisAxis);
  // map the reading from the analog input range to the output range:
  reading = map(reading, 0, 1023, 0, cursorSpeed);
  // if the output reading is outside from the
  // rest position threshold,  use it:
  int distance = reading - center;
  if (abs(distance) < threshold) {
    distance = 0;
  }
  // return the distance for this axis:
  return distance;
}
 
This is not directly compilable and I have not followed all your names nor used your readAxis function but I think this will give you more desirable control over the mouse cursor using the stick.

Code:
elapsedMillis timeThis;

loop()
{
  if(timeThis>29)
  {
    timeThis=0;
    int16_t nX=analogRead(XAXISPIN)-2048;
    int16_t nY=analogRead(YAXISPIN)-2048;
    if(abs(nX)>threshold) mX=nX/100; else mX=0; // 100 might be a bit too aggressive, this is a value worth experimenting with perhaps
    if(abs(nY)>threshold) mY=nY/100; else mY=0; 
    if(mouseIsActive)
    {
      Mouse.move(mX,mY,0);
    }
  }
}
Edit: Assuming that ADC is set to 12 bit resolution. Dividing by 100 also assumes threshold is > 99, tweaking that 100 should be all it takes to get a response you like from the stick.


Alternative: If your user can control a thumbstick maybe they can use a trackball; http://www.cursorcontrols.com/product-range/optical-trackball/
 
Last edited:
ok thanks that`s a bit over my head I am not very good at code

trackball`s may be ok it`s more for people with muscular dystrophy yes that`s lots of them The biggest problem is muscle use and weakness that`s a big problem I needed to have it so there is only slight movement where your hand or thinger can just move the courser around the switches are easy as, leaver type micro switches. there are lots of bits around most of them are not that good. I use a big mouse and that get hard to use my hand gets tired and sore so having something to just rest onto and moment is very easy will make it easier if you wont to know I have BMD.

the main driveing forces behind this is cost I can make most bits need and get the parts for a lot less than what it cost`s to buy something already made like 75 to 50% less. my times free
 
ok thanks that`s a bit over my head I am not very good at code

...
Try this; whether or not it does any nearer what you want, I am very tempted to write a complete sketch up for you to play with.
Code:
#include <Bounce.h>

/// Define Pins
const int startEmulation = 2;      // switch to turn on and off mouse emulation
/////////////////////////////////////////////////////////////////////////////////
const int joystickX = A1;         // joystick X axis
const int joystickY = A0;         // joystick Y axis
// parameters for reading the joystick:
int cursorSpeed = 8;               // output speed of X or Y movement
// halving 7 (center, below) makes 3.5 which will only be stored as 3 in an integer, doesn't seem 'good' so I have changed above to 8 - Rob.
int responseDelay = 20;        // response delay of the mouse, in ms
// I made responseDelay bigger, maybe I should not have, try other values till you like movement of mouse for thumbstick - Rob.
int threshold = cursorSpeed / 4;    // resting threshold
int center = cursorSpeed / 2;       // resting position value
boolean mouseIsActive = false;    // whether or not to control the mouse
int lastSwitchState = LOW;        // previous switch stat
//////////////////////////////////////////////////////////////////////////////////////
// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce button3 = Bounce(4, 10);  // if a button is too "sensitive"
Bounce button4 = Bounce(5, 10);  // to rapid touch, you can
Bounce button5 = Bounce(3, 10);  // increase this time.

byte left = 0;
byte middle = 0;
byte right = 0;
/////////////////////////////////////////////////////////////////////////////////

void setup() {
  pinMode(startEmulation, INPUT_PULLUP);   // the switch pin
  ///////////////////////////////////////////////////////////////////////////////////
  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);


  //////////////////////////////////////////////////////////////////////////////////
  Mouse.begin();  // take control of the mouse
}
elapsedMillis moveDelay;
void loop() {
  // read the switch:
  int switchState = digitalRead(startEmulation);
  // if it's changed and it's high, toggle the mouse state:
  if (switchState != lastSwitchState) {
    if (switchState == LOW) {
      mouseIsActive = !mouseIsActive;
    }
  }
  // save switch state for next loop:
  lastSwitchState = switchState;
  // read and scale the two axes:
  if(moveDelay>responseDelay-1)
  {
    moveDelay=0;
    int xReading = readAxis(A1);
    int yReading = readAxis(A0);
    // if the mouse control state is active, move the mouse:
    if (mouseIsActive) {
      Mouse.move(xReading, yReading, 0); // (x, y, scroll mouse wheel)
    }
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.
  button3.update();
  button4.update();
  button5.update();

  // this variable will let us know if any button changes
  byte anyChange = 0;

  // Check each button for "falling" edge.
  // Change a mouse button when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)
  if (button3.fallingEdge()) {
    left = 1;
    anyChange = 1;
  }
  if (button4.fallingEdge()) {
    middle = 1;
    anyChange = 1;
  }
  if (button5.fallingEdge()) {
    right = 1;
    anyChange = 1;
  }

  // Check each button for "rising" edge
  // Change a mouse button when each button releases.
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)
  if (button3.risingEdge()) {
    left = 0;
    anyChange = 1;
  }
  if (button4.risingEdge()) {
    middle = 0;
    anyChange = 1;
  }
  if (button5.risingEdge()) {
    right = 0;
    anyChange = 1;
  }

  // if any changes were made, update the Mouse buttons
  if (anyChange) {
    Mouse.set_buttons(left, middle, right);
  }
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
reads an axis (0 or 1 for x or y) and scales the
analog input range to a range from 0 to <range>
*/
int readAxis(int thisAxis) {
  // read the analog input:
  int reading = analogRead(thisAxis);
  // map the reading from the analog input range to the output range:
  reading = map(reading, 0, 1023, 0, cursorSpeed);
  // if the output reading is outside from the
  // rest position threshold,  use it:
  int distance = reading - center;
  if (abs(distance) < threshold) {
    distance = 0;
  }
  // return the distance for this axis:
  return distance;
}
I haven't read the code I have modified here as much as I would prefer to, to be surer it is 'good', before modifying it - I am at work and just sneaking this in between tapping out lines for the semi-epic monster they have me working on :)
 
thank you rob what you changed works 100% better than how it was increasing the delay has improved the response time it just need to go a little bit faster and she be all good

again Thank you I am going to credit you in it
 
Very welcome.

Re: Mouse movement speed; In the last batch of code look for
Code:
int responseDelay = 20;        // response delay of the mouse, in ms
// I made responseDelay bigger, maybe I should not have, try other values till you like movement of mouse for thumbstick - Rob.
Make responseDelay smaller to make the mouse move more rapidly, larger to make it slower; you probably want 10 or 15 there by the sound of it.

If I make you a new batch of code from scratch I will try to make more obvious 'what to tweak' for what effect.
 
thank you, having this bit at int cursorSpeed = 12; with int threshold = cursorSpeed / 6; and this left at 2 int center = cursorSpeed / 2; work good.

if you do do something better make sure you credit your self in it

thanks
 
silly question have finally got back to this project I have the joystick working good just need to finish the mount, buttons left, middle, right good as gold.
now to my question I am think about the best way to have the mouse scroll setup, what I am thinking of useing is a spdt center off momentary toggle switch one that snaps back to off, so it will be scroll down, nothing, scroll up could this idea work.

the reason for this is I do a lot of cad/cam, I use the scroll wheel all the time I am finding my finger get quite sore (trigger finger) so if I was able to just push on a switch to scroll up, down and in, out in cam it would be helpful.
 
Last edited:
is this a good way to have the mouse.scroll code or is there a better way to do it, this is the last bit of code I want to add in for now, I still have to finish making the key and joystick mounts and work out how to mount them to my wheelchair.
the scroll I will just use two switches in a mount with a rocker between them or a on off on switch mounted to the side of the key mount or a diy optical encoder

Code:
 /*
 * scroll wheel
 */

int previousVal = 0;
int val = 0;
int ledPin = 11;
int scrollWheelupPin = 10;
int scrollWheeldownPin = 12;
int velocity = 10;

void setup() {
  //Serial.begin(9600);
  pinMode(scrollWheelupPin, INPUT_PULLUP);
  pinMode(scrollWheeldownPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  delay(1000);
  //Serial.println("All set");
}

void loop() {
  val = digitalRead(scrollWheelupPin);
  if (val != previousVal) {
   // Serial.println(val);
    digitalWrite(ledPin, val);
    Mouse.scroll(-1 * velocity);
    delay(300);
    previousVal = val;
    
    val = digitalRead(scrollWheeldownPin);
  if (val != previousVal) {
   // Serial.println(val);
    Mouse.scroll(1 * velocity);
    delay(300);
    previousVal = val;
  }
}
}
 
Status
Not open for further replies.
Back
Top