Arduino Accelerometer: detect braking/ deceleration on a bike - arduino

I have the following issue: I'm having an Arduino + accelerometer(MMA8452Q) mounted on a bike. I'm trying to read decelerations when braking. The issue is that, due to design constraints, I can only mount the above hardware setup on the bike rider. Since the rider will change position very often the accelerometer will also change the base values I'm using for measuring decelerations (e.g. when the Z axis is perpendicular to the ground it will measure 1g, but at a different angle it will show a different value), thus rendering my code unusable.
Here are some snippets from my code:
/* Set up thresholds - 0.42g is maximum braking force the bike can do */
maximum_value = 0.7;
soft_braking = 0.4 * maximum_value;
strong_braking = 0.6 * maximum_value;
if(val > strong_braking)
{
analogWrite(ledPin, 255);
}
else if(acc > soft_braking)
{
analogWrite(ledPin, 127);
}
*val is the acceleration on the axis I'm using for measuring deceleration (after some moving average filtering).
How I can reliably compute deceleration considering that the hardware is not having a fixed position relative to the bike frame and also readings are influenced by the angle of the terrain? I'm considering using a 6DOF board (e.g. MPU6050) with a gyro and measure the angle of the board continually and adjust accelerations values based on this, but I do not know on what math I should use for this? Does anybody had the same issue or can direct me to some similar project?

You're going to have to give up on using the acceleration in a particular direction, but you can use the norm of the acceleration measurement and infer the deceleration in the forward direction by assuming that it is roughly perpendicular to the acceleration downwards.
As for mounting on the rider, I suggest a belt around the waist. This is near the center of gravity of the rider, and you can ignore shortlived accelerations from the rider moving by standing up, etc.
Don't bother trying to track the angle of the board with a gyro. The movements are so small and the uncertainties accumulate so quickly that you won't get a useful result.
For the math, let g be the acceleration due to gravity, gb be the acceleration/deceleration of the bicycle, and gx, gy, gz, be the measurements of acceleration from the device. Then by the Pytagorean theorem, the square of the acceleration
gx^2 + gy^2 + gz^2 = g^2 + gb^2
gb = sqrt(gx^2 + gy^2 + gz^2 - g^2)

Related

Need help figuring out orbits in 2D for my game

In a game that I'm making, the idea is that the mouse cursor is representing a center of mass and there are objects orbiting around it.
The cursor itself is not an object and there is no collision between the cursor and the objects.
The ideal method would be the one where I can enter x and y coordinates of the target, and maybe the orbit radius, and the object would go into orbit and would be accelerating constantly.
When I move the mouse, the object would follow; and when I stop it, it would fall back into the same orbit radius.
The objects acceleration should also be able to change so it gives an effect that the mouse has more or less mass.
I thought the best way to achieve this would probably be with vectors.
In the Projectile class I gave each projectile 4 fields: x coordinate, y coordinate, PVector speed and PVector acc (acceleration).
The first thing I tried is giving the object constant acceleration. Speed vector starts as zero, the acceleration vector is calculated, its magnitude is then set to some value and it is added to the speed vector.
This produced very large orbits, slow acceleration and when the mouse is moved, the orbit just became larger.
Next I tried making the acceleration increase when it is closer to the center of mass inspired by the actual planets. This did not work either. The orbits were still too large and not controllable. Kind o disappointed I tried making the acceleration constantly increasing which gave the best results. The orbit is now getting smaller, but it just keeps decreasing to some radius and then stops. This would be perfect if the radius at which it stops decreasing would be configurable, but no matter the parameters the orbit is always too large and the orbit size keeps decreasing frustratingly slowly. My guess is that the acceleration and speed somehow end up in an equilibrium, and then the orbit stops decreasing.
void move(float x,float y,float accm)
{
PVector target = new PVector(x, y);
PVector ball = new PVector(this.x, this.y);
acc = PVector.sub(target, ball);
acc.setMag(accm);
speed.add(acc);
println(acc.mag() + " " + speed.mag());
this.x = this.x + speed.x;
this.y = this.y + speed.y;
}
This is the function that gave the best results. The function is called in draw():
if(mousePressed == true)
{
for(i=0;i<nproj;i++)
{
a[i].move(mouseX, mouseY,k);
}
k += n;
}
k is the number given to the function and n is the rate at which acceleration increases. I tried many different acceleration magnitudes and different rates of acceleration and just couldn't figure it out. Nproj is the number of projectiles and a is the name of the projectile array.
I found that for k = 0 and n = 0.002 it gave the most reliable and stable results. If n is larger (around 0.01 or larger), the objects sometimes randomly flies off way further than expected, and it actually increases the orbit radius. As the acceleration increases this happens more often, and the object sometimes ends up off the screen and then it never comes back. I know that orbit radius doesn't exist because the orbits are elliptical, but it just makes it easier to explain.
Update:
This is what I came up with so far
void move(float x,float y,float accm)
{
PVector target = new PVector(x, y);
PVector ball = new PVector(this.x, this.y);
acc = PVector.sub(target, ball);
acc.setMag(accm);
vel.add(acc);
this.x = this.x + vel.x;
this.y = this.y + vel.y;
vel.limit(15);
}
and in draw()
if(mousePressed == true)
{
for(i=0;i<nproj;i++)
{
a[i].move(mouseX, mouseY,k);
}
k += n;
if(k > 25)
n = 0;
}
By limiting the velocity vector and constantly increasing acceleration vector, magnitude difference begins to increase and since the acceleration vector is increasing and the velocity vector is constant and acceleration vector points towards the target the sum of the vectors starts slowly pointing more and more towards the target. The condition if(k < 25) is there to limit the acceleration and by changing the limit of the acceleration you can change the orbit radius.
I think you probably would have gotten a quicker answer over at https://physics.stackexchange.com/ and framing your question as "how do I simulate gravity in a game?"
Anyway I will give it a try...
In the class Projectile I gave each projectile 4 fields: x coordinate, y coordinate PVector speed and PVector acc
Sounds good so far, except you don't need to store the acceleration vector with the object. You'll calculate a new acceleration vector for each object on each "tick" of your simulation.
I would use standard physics terminology here and call each object's vector velocity instead of speed.
Next I tried making the acceleration increase when it is closer to the center of mass inspired by the actual planets.
This behavior should just happen naturally if you use the right algorithm for calculating an orbit.
Your "sun" and the "planets" each have a mass. Masses attract each other with a gravitational force, which is F = G * m1 * m2 / d^2 from Wikipedia.
Remember that Force = mass * acceleration, and you have the acceleration as a = m * G / d^2 where m is the mass of the other object (in this case the sun), and d is the distance between the two objects. So the important part is that the acceleration of an object due to gravity varies with the distance squared between the two objects.
So your basic algorithm for a single tick of your simulation looks like this:
For each planet, calculate an acceleration vector
Use the distance to the "sun" squared as the magnitude of the acceleration vector (times a constant value that depends on your "gravitational constant" and your sun's mass), and the direction is of course the direction from the planet towards the sun
Add this acceleration vector to the velocity vector for the planet
Add the velocity vector to the (x, y) position of the planet to move it forward.
With appropriate values for the length of each simulation tick, the gravitational constant, and the sun's mass, this should start to look pretty reasonable.
Since you're assuming that the planets are all independent and cannot collide, you can just do the calculation independently for each planet.
However, I think the game might be more interesting with a more accurate simulation. In reality, every object has a gravitational force on every other object. This would mean looping over all pairs of objects and doing the same kind of acceleration/velocity/position calculation.
The point of the game could then be to get the "planets" from one side of the screen to the other, in increasingly difficult starting configurations as they are all affecting each other and moving in different directions.
In order to make all of this work well, it would be important to set the mass of the "sun" many times higher than the mass of the planets, and to choose a reasonable value for your gravitational constant based on the timing of your simulation. You'll have to play with these constants to find the best results.

Can I cancel out gravity only with gyro and magnetometer?

On a device I want to detect a range of forces: small forces (Minimum around 0.01g) but also stronger forces like 0.1g - 0.15g.
This device will have different positions in 3d space so in order to detect the small forces I have to know its angle in order to be able to subtract 1g. Because the device can have a random position (angle position).
What I did so far: I used the MPU6050 and used a complementary filter with accel. and gyro.
It's something like:
agnleX_k+1 = 0.98*(angle_k + deltaT * gyro_k+1) + 0.02*angle_acc_k+1;
angle_acc is the angle calculated from the accel. sensor. Something like:
arctan(accelX / sqrt(accelX^2 + accelY^2 + accelZ^2 + ))
So I am interested in:
forceX_k+1 = accelX_k+1 - 1g*sin(agnleX_k+1)
The problem is:
If I want to detect a small force coming in very fast, let's say on accelX_k+1 I would want to detect a Change from 0g to 0.01g or more but in a very small time range. The problem is that my calculated angle would then also be influenced by this small and fast change of the accel. sensor although the angle haven't really changed.
I think I would have to do the angle calculation independent of the accel. sensor. Can I do something like a complementary filter with gyro and magnetometer? Would that work the same as my filter described above but just with the mag. sensor instead? Or how would you do that? I was thinking about using MPU9250.
You stated using MPU6050, which contains both an accelerometer and a gyrosocpe. You could use them independantly - get acceleration from the accelerometer and get angles from the gyroscope, and then use the angles to compensate for rotation. There is no need for the angle to depend on your accelerometer.
Using DMP library fromJeff Rowberg will do the work for you.
it can compensate gravity acceleration internally way faster that Arduino code.
Link to github

Gravity's acceleration between two objects

So I am making a program, where you can have two objects (circles). I want them to orbit like planets around each other, but only in 2D.
I know that using Newtons Universal Law of Gravitation I can get the force between the two objects. I also know A = F / M. My question is how would I take the A from the previous equation and change it into a vector?
You need to use vector equations:
// init values (per object)
double ax=0.0,ay=0.0,az=0.0; // acceleration [m/s^2]
double vx=0.0,vy=0.0,vz=0.0; // velocity [m/s]
double x=0.0, y=0.0, z=0.0; // position [m]
double m=1.0; // mass [kg]
// iteration inside some timer (dt [seconds] period) ...
int i; double a,dx,dy,dz; // first compute acceleration
for (ax=0.0,ay=0.0,az=0.0,i=0;i<obj.num;i++)
if (obj[i]!=this) // ignore gravity from itself
{
dx=obj[i].x-x;
dy=obj[i].y-y;
dz=obj[i].z-z;
a=sqrt((dx*dx)+(dy*dy)+(dz*dz)); // a=distance to obj[i]
a=6.67384e-11*(obj[i].m*m)/(a*a*a); // a=acceleration/distance to make dx,dy,dz unit vector
ax+=a*dx; // ax,ay,az = actual acceleration vector (integration)
ay+=a*dy;
az+=a*dz;
}
vx+=ax*dt; // update speed via integration of acceleration
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt; // update position via integration of velocity
y+=vy*dt;
z+=vz*dt;
Code is taken from here
obj[] is list of all your objects
obj.num is the count of them
I recommend to create object class with all the variables inside (ax,ay,az,...m), init them once and then continuously update (iteration) in some timer. If you want more accuracy then you should compute ax,ay,az for all objects first and only after update speed and position (to avoid change of position of objects during gravity computation). If you want to drive an object (like with truster) then just add its acceleration to ax,ay,az vector)
Now to setup an orbit just:
place planet object
must be massive enough and also set its position / velocity to what you want
place satellite
Initial position should be somewhere near planet. It should not be too massive. Init also speed vector with tangent direction to orbiting trajectory. If speed is too low it will collapse into planet and if speed is too high it will escape from planet otherwise will be orbiting (circle or ellipse)
timer
lower the interval better the simulation usually 10ms is OK but for massive and far objects is also 100ms and more OK. If you want particles or something then use 1ms (very dynamic sceene).
I strongly recommend to read this related QA:
Is it possible to make realistic n-body solar system simulation in matter of size and mass?
especially [edit3] about the integration precision and creating orbital data.
With two objects you are probably best using an ellipse which is the path the objects will follow about their common center of mass. Read Kepler's laws of planetary motion which gives the background.
If one object is a much greater mass than the other, i.e. a sun and a planet you can have one stationary and the other taking an elliptical path. The equation of the ellipse is given by
r = K e / ( 1 + e cos(theta))
K is a constant giving the size and e is the eccentricity. If you want an elliptical orbit have 0 < e < 1 the smaller it is the more circular the orbit. To get x, y coordinates from this use, x = r cos(theta), y = r sin(theta). The missing bit is time and how the angle is dependant on time. This is where the second and third laws come in. If a and b are the semi-major and semi-minor lengths of the ellipse, and P is the period then
0.5 * P * r^2 theta'= pi a b
theta' is the rate of change of angle with respect to time (d theta/d t). You can use this to get how much theta will change given a increase in time. First work out the current radius r0 given the current angle th0 if the time increment is δt then the angle increment δtheta is
δtheta = 2 pi * a * b / r^2 * δt
and the next angle is th0 + δtheta.
If the masses are of similar magnitude then see two body problem. Both objects will have elliptical orbits, there are two patterns which you can see in animations on that page. The ellipses will follow the same formula as above with the focus at the common center of mass.
If you have three object things get considerably harder and there are not generally neat solutions. See three body problem for this.

Accelerometer tilt error correction

I am using arduino and accelerometer MMA7341 to measure the acceleration in x direction of an oscillating metal table. But the mounting of the accelerometer is tilted by a small angle (say Q) . Is it affect the acceleration?. If it is affect the acceleration in x direction , how can correct it without changing the tilt of the acceleration sensor.
"Tilt" and "acceleration" are both the same, from the perspective of most sensors, since both measure a force, rather than an actual angle (tilt) or change in velocity (acceleration).
What you should do is make sure the object on which the sensor is mounted is "level", within the best of your ability to determine such a thing, and use the values from analogRead() or whatever else your device provides, as the "0" values.
For the MMA7341 you'll also need to calibrate your analog signals, or else use a high precision reference as input to the Aref pin, assuming you're Arduino exposes that pin.
I think this depends on what you are measuring. THe MMA7341 looks to be able to be used for acceleration as well as tilt. If you are measuring acceleration then the mounting position doesn't matter since acceleration is a change of velocity and the velocity delta will be constant regardless of orientation.
If you are measuring tilt then thats obviously different. You could theoretically measure the initial tilt and then compensate for that in your code if you wanted to of course.

2D Spaceship movement math

I'm trying to make a top-down spaceship game and I want the movement to somewhat realistic. 360 degrees with inertia, gravity, etc.
My problem is I can make the ship move 360° with inertia with no problem, but what I need to do is impose a limit for how fast the engines can go while not limiting other forces pushing/pulling the ship.
So, if the engines speed is a maximum of 500 and the ship is going 1000 from a gravity well, the ship is not going to go 1500 when it's engines are on, but if is pointing away from the angle is going then it could slow down.
For what it's worth, I'm using Construct, and all I need is the math of it.
Thanks for any help, I'm going bald from trying to figure this out.
Take a page from relative physics, where objects cannot exceed the speed of light:
(See below for my working C++ code snippet and running demo [Windows only].)
Set the constant c to the maximum speed an object can reach (the "speed of light" in your game).
If applying a force will increase the speed of the object, divide the acceleration (change in velocity) by the Lorentz factor. The if condition is not realistic in terms of special relativity, but it keeps the ship more "controllable" at high speeds.
Update: Normally, the ship will be hard to maneuver when going at speeds near c because changing direction requires an acceleration that pushes velocity past c (The Lorentz factor will end up scaling acceleration in the new direction to nearly nothing.) To regain maneuverability, use the direction that the velocity vector would have been without Lorentz scaling with the magnitude of the scaled velocity vector.
Explanation:
Definition of Lorentz factor, where v is velocity and c is the speed of light:
This works because the Lorentz factor approaches infinity as velocity increases. Objects would need an infinite amount of force applied to cross the speed of light. At lower velocities, the Lorentz factor is very close to 1, approximating classical Newtonian physics.
Graph of Lorentz factor as velocity increases:
Note: I previously tried to solve a similar problem in my asteroids game by playing with friction settings. I just came up with this solution as I read your question^^
Update: I tried implementing this and found one potential flaw: acceleration in all directions is limited as the speed of light c is approached, including deceleration! (Counter-intuitive, but does this happen with special relativity in the real world?) I guess this algorithm could be modified to account for the directions of the velocity and force vectors... The algorithm has been modified to account for directions of vectors so the ship does not "lose controllability" at high speeds.
Update: Here is a code snippet from my asteroids game, which uses the Lorentz factor to limit the speed of game objects. It works pretty well!
update:* added downloadable demo (Windows only; build from source code for other platforms) of this algorithm in action. I'm not sure if all the dependencies were included in the zip; please let me know if something's missing. And have fun^^
void CObject::applyForces()
{
// acceleration: change in velocity due to force f on object with mass m
vector2f dv = f/m;
// new velocity if acceleration dv applied
vector2f new_v = v + dv;
// only apply Lorentz factor if acceleration increases speed
if (new_v.length() > v.length())
{
// maximum speed objects may reach (the "speed of light")
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b <= 0) b = DBL_MIN;
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
}
// apply acceleration to object's velocity
v += dv;
// Update:
// Allow acceleration in the forward direction to change the direction
// of v by using the direction of new_v (without the Lorentz factor)
// with the magnitude of v (that applies the Lorentz factor).
if (v.length() > 0)
{
v = new_v.normalized() * v.length();
}
}
Well, lets consider the realistic problem first and see why this doesn't work and how we have to differ from it. In space as long as your engines are firing, you will be accelerating. Your speed is only limited by your fuel (and in fact you can accelerate faster once you've spent some fuel because your moving less mass).
To give this model an effective maximum speed, you can consider particles in space slowing you down and causing friction. The faster you go, the more particles you're hitting and the faster you're hitting them, so eventually at some fast enough speed, you will be hitting enough particles the amount of decelerating they do exactly cancels out the amount of accelerating your engine is doing.
This realistic model does NOT sound like what you want. The reason being: You have to introduce friction. This means if you cut your engines, you will automatically start to slow down. You can probably count this as one of the unintended forces you do not want.
This leaves us with reducing the effective force of your engine to 0 upon reaching a certain speed. Now keep in mind if your going max speed in the north direction, you still want force to be able to push you in the east direction, so your engines shouldn't be cut out by raw velocity alone, but instead based on the velocity your going in the direction your engines are pointing.
So, for the math:
You want to do a cross dot product between your engine pointing vector and your velocity vector to get the effective velocity in the direction your engines are pointing. Once you have this velocity, say, 125 mph (with a max speed of 150) you can then scale back the force of your engines is exerting to (150-125)/150*(Force of Engines).
This will drastically change the velocity graph of how long it will take you to accelerate to full speed. As you approach the full speed your engines become less and less powerful. Test this out and see if it is what you want. Another approach is to just say Force of Engines = 0 if the dot product is >=150, otherwise it is full force. This will allow you to accelerate linearly to your max speed, but no further.
Now that I think about it, this model isn't perfect, because you could accelerate to 150 mph in the north direction, and then turn east and accelerate to 150 mph going in that direction for a total of 212 mph in the north east direction, so not a perfect solution.
I really do like Wongsungi's answer (with the Lorentz factor), but I wanted to note that the code can be simplified to have fewer floating-point operations.
Instead of calculating the Lorentz factor (which itself is a reciprocal) and then dividing by it, like this:
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
simply multiply by the reciprocal of the Lorentz factor, like this:
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
This eliminates one floating-point operation from the code, and also eliminates the need to clamp b to DBL_MIN (it can now be clamped to 0 because we're not dividing anymore). Why divide by the reciprocal of x when you can just multiply by x?
Additionally, if you can guarantee that the magnitude of v will never exceed c, then you can eliminate the testing of b being less than zero.
Finally, you can eliminate two additional sqrt() operations by using length_squared() instead of length() in the outer if statement:
if (new_v.length_squared() > v.length_squared())
{
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b < 0) b = 0;
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
}
This may only make a 0.1% difference in speed, but I think the code is simpler this way.
You need to have three variables for your ship, which you update at each physics time step based on the forces that are acting on it. These will be mass, position, and velocity. (note that position and velocity are single numbers but vectors). At each physics time step you update the position based on the velocity, and the velocity based on the acceleration. you calculate the acceleration based on the forces acting on the ship (gravity, friction, engines)
Newton's equation for force is F = M*A We can rearrange that to A = F/M to get Acceleration. Basically you need to figure out how much the ship should accelerate, and in which direction (vector), then add that acceleration to the ship's velocity, and add the ship's velocity to its position.
Here is the code you should execute each physics time step (I hope you can fill in the blanks) please ask if this is not enough detail
gravity = //calculate force of gravity acting on ship from Newton's law of universal gravitation
friction = //ten percent of the ship's velocity vector, in the opposite direction
engines = 0
if (engines_are_firing)
engines = 500
forces = gravity + friction + engines
acceleration = forces / ship.mass
ship.velocity += acceleration
ship.position += velocity
redraw()
Your question is difficult for me to understand but it seems like you're not using real physics for this game. Have you considered using real physics equations such as velocity, acceleration, force, etc?
Edit:
After your edits, I think I have a better understanding. You are simply keeping track of the current velocity (or something similar) but you don't keep track of the force where that velocity comes from. The ship should not be storing any of that information (other than engine thrust) -- it should come from the environment the ship is in.
For instance, the environment has a gravity vector (directional force) so you would need to take that into account when calculating the directional force provided by the engine.
Your ship should be storing its own engine force, acceleration, and velocity.

Resources