Originally Posted by
manasij7479
If you're wondering, I tried to make the mouse cursor move from accelerometer input.
You need a native USB microcontroller for that; a serial-to-USB -bridged one like most of the Arduinos won't work.
With a Teensy (1.0, 1.0++, 2.0, or 2.0++), the mouse example is here, including the sources. The example contains all the mouse-related stuff you need, and the usb_mouse_move(±x, ±y, ±wheel) interface is perfect for your case. Remember: mice report relative movement only. (Absolute positions are also possible, they're just touchpads or similar, not mice.)
Originally Posted by
manasij7479
Totally had no idea about what to do with the data once I got it.
Did you ask here? (I don't visit the C++ forums, so I've missed those. Pity; I could've helped with the quaternion stuff, I like using those for rotations.)
Accelerometers provide signed values indicating acceleration along or around an axis. Typically, the first three degrees of freedom are the normal Cartesian axes, X, Y, and Z. The others are typically rotations around each axis.
First step would have been to just have a prototype output the accelerometer values without any kind of mouse stuff. With a Teensy, you could do this very easily using the USB Debug example. You would just look at the accelerometer values to get a feel as to its sensitivity; you could even write a test app running on your host, simulating mouse movement.
Most accelerometers use 3.3V supply and signal levels, so with a Teensy, you'd need a logic level converter. You would of course use an accelerometer with a good sensitivity and high sample rate -- something like MMA8452Q, up to 800 Hz sample rate with 12-bit sensitivity at ±2g looks quite good to me. (Teensies can do full 12Mbit/s, or a bit over 1 megabyte per second over the USB, so a 10-byte HID frame 500 to 1000 times a second should not be a problem.)
Now, an accelerometer measures acceleration, not movement or speed. Since the human hand movement range is quite limited, we cannot accelerate our hands for more than a fraction of a second at a time. Thus, we cannot use the acceleration directly as the relative mouse movement reports. Our hands would slam into objects or detach from our torsos, and even if in a large room with microgravity, our hands would tire quite quickly.
There are two approaches you could try here:
- Integrate the acceleration to get velocity, and report the velocity as the mouse movement
This basically uses the accelerometer sensors to replicate the sensed movement as the mouse movement.
You'll probably get very good results, if you consider small velocities in magnitude as zero (to counter drift), and add "drag", reducing the velocity by a small scale factor each time step (also to counter drift).
This leads to pretty intuitive behaviour, but you need to test in practice to find good numerical values to use. - Use the acceleration as a trigger, with the twice-integrated displacement determining the mouse velocity
This way, the accelerometer movement is considered a command. For example, if the sensor was at the tip of your finger, and you moved it slowly up, then held there, the mouse would start moving up at a constant velocity. When you move it back down, the mouse stops.
I'm not sure how intuitive this is, but it might work, because there should be less movement necessary to achieve desired mouse movement. I haven't tried this myself.
USB HID (Human Interface Device) devices are reserved 1000 reports per second on the USB bus. Using something like 100 to say 250 reports per second should suffice, and have little enough latency to feel "natural". Depending on the sensor output, you might wish to "average" few samples to reduce the noise. I'm not exactly sure about the typical mouse report rate, but deviating too much from those might confuse some operating systems.
Although human time perception is such that 20ms (1/50th of a second) feels instantaneous to most, pointing devices have multiple axes and curved movement does not look smooth if you don't have high enough sample rate.
So, all that said, with a MMA8452Q accelerometer, my main loop would likely be something like
Code:
/* Maximum 16-bit signed integer that will not overflow if a 12-bit signed value is added */
#define V_MAX 30719
/* Inverse velocity decay rate, higher is slower */
#define V_RATE 128
/* Zero range */
#define V_ZERO 1024
/* Velocity to mouse report divisor */
#define V_SCALE 128
/* Number of accelerometer samples per mouse report */
#define SAMPLES_PER_REPORT 2
/* These would be updated by read_MMA8452Q(), and sign-extended to 16 bits */
static int16_t a_x, a_y, a_z;
/* These are the internal velocity counters */
static int16_t v_x = 0, v_y = 0, v_z = 0;
/* Mouse report */
signed char m_x, m_y, m_z;
/* Just a loop variable */
unsigned char i;
while (1) {
for (i = 0; i < SAMPLES_PER_REPORT; i++) {
read_MMA8452Q();
v_x += a_x;
v_y += a_y;
v_z += a_z;
if (v_x > V_MAX)
v_x = V_MAX;
else
if (v_x < -V_MAX)
v_x = -V_MAX;
else
v_x = v_x - (v_x / V_RATE);
/*
* Same as above for v_y and v_z
*/
}
if (v_x > V_ZERO)
m_x = (v_x - V_ZERO) / V_SCALE;
else
if (v_x < V_ZERO)
m_x = (v_x + V_ZERO) / V_SCALE;
else
m_x = 0;
/* Same for m_y and m_z, perhaps
* larger V_SCALE for m_z (mouse wheel) */
usb_mouse_move(m_x, m_y, m_z);
}
Note that because we have discrete samples with a constant interval, integration becomes a simple addition.
The V_ZERO, V_SCALE, and V_MAX constants I drew out of my behind, so they're likely wrong.
You might also make the velocities 32-bit, to allow for larger integration range. With 16 bits, there's just 4 bits for integration room, meaning 16 consecutive samples result in clipping already. With 32 bits, we'd have 20 bits, meaning you'd need 220 = 1,048,576 consecutive maximum samples to hit the limit.
I don't have an accelerometer to play with, so I'm not sure if the above works in practice, but from a physics point of view, I don't see why it would not.
Going back to the original topic, manasij7479's experience is a perfect example of why you should also make sure you have a community where you can ask for help, if you hit a snag. With things like accelerometers, you might need a bit of physics to immediately see how they can be used, so having a community where you can ask for specific details and help, is quite important, in my opinion.
Which is to say: Find a good community, and pick the right boards there to ask the questions in, always give enough context (in case your approach itself is wrong), and for good measure make sure you always show your own efforts, too, so that other members see you're not asking others to do your work for you. (There's tons of freeloaders and leeches in discussion boards looking for free homework services, so initial reactions may be quite negative if you happen to be misunderstood in your purpose.)
As to the language, embedded C or C++ (meaning a freestanding C or C++ environment, with no standard libraries, only special-purpose libraries like Arduino libraries or vendor-specific libraries), is certainly a valid choice, and one I would personally recommend. Reasons are the ubiquity of Arduino, the number and quality of the free tools (many of the commercial development environments use the free GCC compiler suite!), and the number of long-term supported, commercial embedded C/C++ environments.