Discussion:
rotating objects from an accelerometer output: python + pyserial + soya 3D + Arduino + ADXL330
Fabio Varesano
2010-08-21 15:11:26 UTC
Permalink
Hi there,

for a research project we are running at my University (unito.it), I'm
working on creating something like the following using Arduino +
ADXL330 accelerometer + Python + pyserial + Soya 3D:



This is were I'm at right now: http://pastebin.com/cGmSTpZX

I've been able to model a simple cuboid and then use both begin_round
or advance_time to implement fixed rotation increments: I hard coded a
fixed rotation angle (see commented code) and I'm able to see the cube
rotating nicely.

The situation become harder when instead of using hard coded rotations
I want to use angles coming from the accelerometer.

Basically the accelerometer is able to measure gravity acceleration
projected on its 3 axes (see http://www.starlino.com/imu_guide.html
for a more detailed description).. so in my python code I get these
values. Now, using some math (atan2 and other stuff) I should be able
to calculate rotations around x, y, z. Once I get these angles using
eg. rotate_x I should be able to rotate the cuboid to the same
position of the accelerometer.

However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.

This, to my understanding, could be a consequence of:
* me not correctly understanding how to rotate objects in Soya 3D
* the serial interface reading causing too much delay for the
rendering engine to display a smooth animation


What do you guys think about this?

Thanks for your help,

Fabio Varesano
David Bliss
2010-08-21 15:48:25 UTC
Permalink
I can't tell you about the right way to rotate objects in Soya. I can tell
you, however, that you should ensure the readline() call isn't halting your
program until it receives a complete line.

I'm in the middle of moving right now, but if I had two computers, this is
what I'd do to check: connect two computers via serial. Have one of them
read text in the exact same way, and just print it a line at a time. Use
other print statements liberally to be sure you know what's going on. The
other computer sends part of a line, waits for at least half a second, then
sends the rest of the line. If you don't have a null-modem cable, the second
computer can be substituted with an Arduino with a different program, but
the delay between starting the line and finishing it needs to be observable.

Hope this helps.

David Bliss
Percopo 232
1-616-284-1273
CM 1534


On Sat, Aug 21, 2010 at 11:11 AM, Fabio Varesano
Post by Fabio Varesano
Hi there,
for a research project we are running at my University (unito.it), I'm
working on creating something like the following using Arduino +
http://youtu.be/BJeohcZssBU
This is were I'm at right now: http://pastebin.com/cGmSTpZX
I've been able to model a simple cuboid and then use both begin_round
or advance_time to implement fixed rotation increments: I hard coded a
fixed rotation angle (see commented code) and I'm able to see the cube
rotating nicely.
The situation become harder when instead of using hard coded rotations
I want to use angles coming from the accelerometer.
Basically the accelerometer is able to measure gravity acceleration
projected on its 3 axes (see http://www.starlino.com/imu_guide.html
for a more detailed description).. so in my python code I get these
values. Now, using some math (atan2 and other stuff) I should be able
to calculate rotations around x, y, z. Once I get these angles using
eg. rotate_x I should be able to rotate the cuboid to the same
position of the accelerometer.
However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.
* me not correctly understanding how to rotate objects in Soya 3D
* the serial interface reading causing too much delay for the
rendering engine to display a smooth animation
What do you guys think about this?
Thanks for your help,
Fabio Varesano
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
Fabio Varesano
2010-08-21 16:54:35 UTC
Permalink
Hi David,

thanks for your input. Unfortunately I don't think that readline() is
the problem here.

Of course, readline() is blocking until it gets a '\n' but I'm sending
something like 200/300 lines/seconds with Arduino (each line contains
an ending '\n' see Arduino code at http://arduino.pastebin.com/KNAmnScS).

This is actually confirmed if I uncomment the print x_rot statement:
this would result in lot of prints in the Python stdout meaning that
the read has been successful and fast.

FV
Post by David Bliss
I can't tell you about the right way to rotate objects in Soya. I can
tell you, however, that you should ensure the readline() call isn't
halting your program until it receives a complete line.
I'm in the middle of moving right now, but if I had two computers,
this is what I'd do to check: connect two computers via serial. Have
one of them read text in the exact same way, and just print it a line
at a time. Use other print statements liberally to be sure you know
what's going on. The other computer sends part of a line, waits for at
least half a second, then sends the rest of the line. If you don't
have a null-modem cable, the second computer can be substituted with
an Arduino with a different program, but the delay between starting
the line and finishing it needs to be observable.
Hope this helps.
David Bliss
Percopo 232
1-616-284-1273
CM 1534
On Sat, Aug 21, 2010 at 11:11 AM, Fabio Varesano
Hi there,
for a research project we are running at my University (unito.it
<http://unito.it>), I'm
working on creating something like the following using Arduino +
http://youtu.be/BJeohcZssBU
This is were I'm at right now: http://pastebin.com/cGmSTpZX
I've been able to model a simple cuboid and then use both begin_round
or advance_time to implement fixed rotation increments: I hard coded a
fixed rotation angle (see commented code) and I'm able to see the cube
rotating nicely.
The situation become harder when instead of using hard coded rotations
I want to use angles coming from the accelerometer.
Basically the accelerometer is able to measure gravity acceleration
projected on its 3 axes (see http://www.starlino.com/imu_guide.html
for a more detailed description).. so in my python code I get these
values. Now, using some math (atan2 and other stuff) I should be able
to calculate rotations around x, y, z. Once I get these angles using
eg. rotate_x I should be able to rotate the cuboid to the same
position of the accelerometer.
However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.
* me not correctly understanding how to rotate objects in Soya 3D
* the serial interface reading causing too much delay for the
rendering engine to display a smooth animation
What do you guys think about this?
Thanks for your help,
Fabio Varesano
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
deavid
2010-08-21 19:30:19 UTC
Permalink
Post by Fabio Varesano
Hi David,
thanks for your input. Unfortunately I don't think that readline() is
the problem here.
Of course, readline() is blocking until it gets a '\n' but I'm sending
something like 200/300 lines/seconds with Arduino (each line contains
an ending '\n' see Arduino code at http://arduino.pastebin.com/KNAmnScS).
this would result in lot of prints in the Python stdout meaning that
the read has been successful and fast.
FV
you are rotating inside begin_round, which is wrong.

You should do the following: in one side (probably a thread), you
should read the data from the serial port and accumulate it.
In the other side (soya's main thread), inside the begin_round
function you should read the accumulated data and put it inside some
object variables (like rot_inertia_x and so). Then,
advance_time(proportion) function will get called several times, each
one with a proportion value. Always, between begin_round and end_round
are N advance_time calls and the sum of proportion argument for those
calls will be 1.
So you should rotate there, in advance_time, but multiplied per proportion.

If really the code used to read the data from serial takes less than
1ms, you can put it in begin_round directly (so no threading is
required), but i prefer to do threading.

Take in account that in a 3D app, each funciton gets called over 50
times per second (or more), a small amount of time spent inside of
them counts a lot.
Fabio Varesano
2010-08-22 16:19:54 UTC
Permalink
Thanks all for your help.

I'm now able to read the accelerometer data without blocking the 3d
rendering: the threads idea made it. Thanks deavid.

Unfortunately though, I'm still not able to create what I'd like to
do. Basically mimic the movement of the pysical cube containing the
accelerometer on the virtual cube from Soya. Something similar to
http://youtu.be/BJeohcZssBU

In this video you see what my current code does:
http://www.varesano.net/temp/accelerometer_soya3d_help.ogv

The code is available at http://pastebin.com/mYiB9dWh

So, using turn_x I rotate the cube of X degrees but this happens at
each call of begin_round.. What I'd like to do is to rotate the cube
only if the current angle is different from the one read from the
accelerometer.

Somehow turn_x() has memory: if I rotated 20° in round one, 10° in
round two and then 30° then the cube has actually rotated 60°.

Instead I need it to only place it so that the rotation is only the
last one.

How can I do that?

Thanks,

Fabio Varesano
Post by deavid
Post by Fabio Varesano
Hi David,
thanks for your input. Unfortunately I don't think that readline() is
the problem here.
Of course, readline() is blocking until it gets a '\n' but I'm sending
something like 200/300 lines/seconds with Arduino (each line contains
an ending '\n' see Arduino code at http://arduino.pastebin.com/KNAmnScS).
this would result in lot of prints in the Python stdout meaning that
the read has been successful and fast.
FV
you are rotating inside begin_round, which is wrong.
You should do the following: in one side (probably a thread), you
should read the data from the serial port and accumulate it.
In the other side (soya's main thread), inside the begin_round
function you should read the accumulated data and put it inside some
object variables (like rot_inertia_x and so). Then,
advance_time(proportion) function will get called several times, each
one with a proportion value. Always, between begin_round and end_round
are N advance_time calls and the sum of proportion argument for those
calls will be 1.
So you should rotate there, in advance_time, but multiplied per proportion.
If really the code used to read the data from serial takes less than
1ms, you can put it in begin_round directly (so no threading is
required), but i prefer to do threading.
Take in account that in a 3D app, each funciton gets called over 50
times per second (or more), a small amount of time spent inside of
them counts a lot.
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
Jiba
2010-08-21 18:00:58 UTC
Permalink
Post by Fabio Varesano
Basically the accelerometer is able to measure gravity acceleration
projected on its 3 axes (see http://www.starlino.com/imu_guide.html
for a more detailed description).. so in my python code I get these
values. Now, using some math (atan2 and other stuff) I should be able
to calculate rotations around x, y, z. Once I get these angles using
eg. rotate_x I should be able to rotate the cuboid to the same
position of the accelerometer.
However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.
I think that the problem is "what are x, y and z axis ?". When you calculate rotations around x, y, z, is it x, y and z of the rotated object ? or x, y and z of its "parent" (e.g. the room ?) ?

In soya, rotate_x() is relative to the parent's coordinate system, and turn_x is relative to the object own coord syst. Other rotation could be performed using more complex rotations functions.

Jiba
Greg Ewing
2010-08-22 23:23:44 UTC
Permalink
Post by Fabio Varesano
However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.
If I understand your code correctly, you're reading one
sample from the accelerometer for each animation round.
But if the accelerometer is producing data faster than
the frame rate of your animation, this isn't going to
work.

For example, if your animation is running at 60fps and
the accelerometer is producing 300 readings/sec (as you
indicated in one of your posts), then your animation is
only using accelerometer data at one-fifth of the rate
needed to keep up, so it will lag further and further
behind.

What you need to do is, for each frame, take all the
accelerometer data that has come in since the last
frame, accumulate all their rotations and apply them
to the model, before rendering the frame. You may
want to use a separate thread to read the accelerometer
samples and put them in a queue for the animation
thread to process.
--
Greg
David Bliss
2010-08-22 23:53:26 UTC
Permalink
I think you're looking at an old version of the code, Greg; I just looked at
http://pastebin.com/mYiB9dWh, and saw a thread that was used an infinite
loop to poll the serial port.

Fabio, the easiest route would probably be keeping the previous rotation
value around, finding the difference between the current and previous
rotation values, and using that with turn_x(). I haven't seen APIs to
support anything else (reset-then-turn, set-rotation), but if they're there
(particularly set-rotation-relative-to-original-local-axis), that would be
more straightforward.

David Bliss
Percopo 232
1-616-284-1273
CM 1534
Post by Greg Ewing
Post by Fabio Varesano
However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.
If I understand your code correctly, you're reading one
sample from the accelerometer for each animation round.
But if the accelerometer is producing data faster than
the frame rate of your animation, this isn't going to
work.
For example, if your animation is running at 60fps and
the accelerometer is producing 300 readings/sec (as you
indicated in one of your posts), then your animation is
only using accelerometer data at one-fifth of the rate
needed to keep up, so it will lag further and further
behind.
What you need to do is, for each frame, take all the
accelerometer data that has come in since the last
frame, accumulate all their rotations and apply them
to the model, before rendering the frame. You may
want to use a separate thread to read the accelerometer
samples and put them in a queue for the animation
thread to process.
--
Greg
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
deavid
2010-08-23 14:18:49 UTC
Permalink
Yes, the problem here is that your accelerometer is reporting absoulte
rotation, and turn_* and rotate_* functions require relative
(differential) rotation.

The simplest idea is calculate the difference between the actual
orientation and the prior one (in the previous round). And that will
give you the "inertial rotation" for the object in that round.

But, beware, that will never be exact. I'm sure you will get the
effect you want to, but after several minutes of playing with it you
will get (probably) a difference between the object orientation on
soya and what orientation says your accelerometer. That will be
because you are "replaying" all the movements again, so you are losing
precision frame by frame.

If you get that problem, the solution is:
In begin_round you extract the object orientation from the
accelerometer and create a Coordinate System with this orientation.
and make a copy of the object corrdinate system in a variable.
In that way, you have 2 known states: a) where is actually your soya's
object b) where you want to put it at the end of the round.
Coordinate Systems (and also bodies) have a function called
"interpolate" which recieves 3 arguments: initial_state , final_state,
factor. And with that function you can get a nice and smooth movement
without losing precision.

But that has also another problem: you got the accelerometer data at
the begin of the round, and your object has moved to it at the end of
the round. So you will have one round of delay, which generally is
1/25 seconds (40ms). Generally that isn't a problem.

Also, you can directly remove all the delay by directly putting the
object in the desired orientation in advance_time function. To do
that, i generally create a 4x4 matrix with the final orientation
(you'll fill it with the accelerometre data captured on the same frame
being rendered) and replace the object matrix with yours. Take in
account that in that matrix there is position, rotation and scale. So
replacing it will replace position and scale too.
Post by David Bliss
I think you're looking at an old version of the code, Greg; I just looked at
http://pastebin.com/mYiB9dWh, and saw a thread that was used an infinite
loop to poll the serial port.
Fabio, the easiest route would probably be keeping the previous rotation
value around, finding the difference between the current and previous
rotation values, and using that with turn_x(). I haven't seen APIs to
support anything else (reset-then-turn, set-rotation), but if they're there
(particularly set-rotation-relative-to-original-local-axis), that would be
more straightforward.
David Bliss
Percopo 232
1-616-284-1273
CM 1534
Post by Greg Ewing
Post by Fabio Varesano
However, I'm stuck on how to rotate my cuboid according to the angles
calculated from the accelerometer. If I use the code posted above the
animation become really slow and sloppy till almost not working.
If I understand your code correctly, you're reading one
sample from the accelerometer for each animation round.
But if the accelerometer is producing data faster than
the frame rate of your animation, this isn't going to
work.
For example, if your animation is running at 60fps and
the accelerometer is producing 300 readings/sec (as you
indicated in one of your posts), then your animation is
only using accelerometer data at one-fifth of the rate
needed to keep up, so it will lag further and further
behind.
What you need to do is, for each frame, take all the
accelerometer data that has come in since the last
frame, accumulate all their rotations and apply them
to the model, before rendering the frame. You may
want to use a separate thread to read the accelerometer
samples and put them in a queue for the animation
thread to process.
--
Greg
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
_______________________________________________
Soya-user mailing list
https://mail.gna.org/listinfo/soya-user
Loading...