billiards-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Billiards-devel] Programming experiments with Billiards


From: Tadej Janež
Subject: Re: [Billiards-devel] Programming experiments with Billiards
Date: Thu, 14 Jan 2010 12:25:37 +0100

Hello Dimitris,

firstly, a big thank you for a quick and comprehensive reply!

On Tue, 2010-01-12 at 15:09 +0200, Dimitris Papavasiliou wrote:
> what you want to do makes sense and should be possible relatively
> easily.  In fact, it was what Billiards was designed for.  There will
> be some scripting involved though.  How much Lua do you know?

None at all, but I find it quite similar to Python (which I use almost
all the time) so I didn't have much difficulties reading and changing
your code. I could even say that I like it so far.

> The initial setting you describe would be a bit of a problem right
> now.  It's fairly easily done by hacking the internals of Billiards
> but not by just *adding* some code as it should be done.  During the
> development of  Billiards I needed to perform some experimentation in
> order to determine whether the physics simulator actually produced the
> correct results (to my surprise, it actually did without requiring any
> special tweaking).  So I created an experimentation mode which
> featured only one white ball on a Carom table.  You could then easily
> perform squirt experiments etc.  That's all I needed back then but it
> seems now that I'll have to expand experimentation mode so that you
> can somehow describe which balls you want at startup and where you
> want them placed.  I should be able to make the necessary changes soon
> so I'll send you a patch and instructions on how to do what you want
> then.  In the meantime, let's focus on the rest.  (You can start
> Billiards in experimentaion mode btw with the -Oexperiment flag).

In the mean time I set up Billiards as a CVS Project in Eclipse IDE and
started experimenting with your code. I followed the changes you made
for 'options.experiment' and created my own 'option.experiment2', which
creates the initial setting I want. It's a quick hack, so if you can
provide a better solution, I'm all for it.

> Now regarding the second point: sidespin, folllow and elevation should
> be easy to setup but "shot force" is not really.  The problem is that
> it's difficult to even define what this "shot force" would be.  During
> the short time that collision between the cue tip and ball takes place
> a force is exerted on the ball by the tip but as all impact forces
> it's hard to determine what it is and it's not constant anyway.  This
> is in the "simple" case where the tip or ball does not flex, which of
> course does happen.  So in short you can apply a force to the ball at
> a specific offset and elevation instead of actually whacking it with
> the cue but this would probably not produce the desired results.  If
> however all you need is to be able to perform a set of shots with the
> same force or with "more" or "less" force there are things you can
> do. 

Ok, I see, thanks for explaining that.

> Now if you want to change some of this, presumably the shot parameters
> the best way to go about it would be this:
> 
> local oldreset
> 
> oldreset = billiards.aiming.reset
> 
> billiards.aiming.reset = function ()
>    -- First call the old function to setup the default
>    -- behavior we don't want to change.
> 
>    oldreset()
> 
>    -- Now change what we don't like.
> 
>    bodies.cue.elevation = math.pi/4
>    bodies.cue.sidespin = billiards.ballradius * 0.3
>    bodies.cue.follow = -0.003
> 
>      end

Ok, perfect. This is what I needed.

Now, I tried setting observer's position with something like:
   bodies.observer.longitude = -1.42
   bodies.observer.latitude = -0.71
   bodies.observer.radius = 0.4
   bodies.observer.elevation = math.pi / 2 -
                   bodies.cue.elevation -
                   math.rad (5)

but it didn't work. Basically, I want to change observer's direction
like you do with holding down the left mouse in the looking mode.

> You may be wondering where to put that code but we'll get to that
> later.  Now setting up the shot is another matter.  The whole world in
> Billiards (actually as small as a room with no walls and a pool table)
> is set up of nodes connected in a graph, sort of like a tree.  The
> whole graph is traversed (several times actually per frame) and
> certain actions are performed by each node according to its nature.
> For example a node representing a physical body might perform
> collision detection and physical simulation for this frame, a node
> representing a visible surface (of a ball conveniently enough) might
> draw itself on the screen.  Now there also happens to be a node
> representing a "slider" that is a joint between two bodies which
> allows them to slide against each other along a certain axis.  This
> node actually links the cue stick with your hand (which is not drawn)
> and can also be powered, as if by a motor, which in the real world
> would be your right arm.  So this joint is called joints.arm and the
> parameters of its motor are set like so:
> 
> joints.arm.motor = {v, F_max}
> 
> 
> What this actually means is that you want the motor to power the
> bodies it's linked to in such a way that their relative velocity along
> the joint's axis becomes v and in order to do this it can exert a
> force on the bodies no larger than F_max.  In our case, since the hand
> is considered fixed, this means that your right arm can push the stick
> with no more than F_max newtons of force in order for the tip to reach
> and maintain a velocity of v m/s.  The stick needs to be accelerated
> to that velocity though so the larger the force the sooner it will
> speed up to v.  So if you use the same motor parameters and the same
> initial position for the stick relative to the ball (this latter comes
> into play because, if F_max is too low the stick might hit the ball
> before it has the time to reach the target velocity), if therefore
> both these conditions hold then the stick will contact the ball with
> the same velocity and provide identical (more or less, hopefully more
> more than less) results between shots.  Raising v and making F_max
> large enough to reach it should result in more energy being
> transferred between the balls and cue.  Incidentally there's a hook
> called billiards.cuecollision I believe which calls its functions
> right before the cue collides with a ball.  You can use that to
> measure the velocity of the cue stick at that moment to make sure it
> is what you want it to be.  The cue is described by the node
> bodies.cue and its velocity can be read at bodies.cue.velocity so you
> can write:
> 
> billiards.cuecollision.cuespeed = function()
>     print (math.length (bodies.cue.velocity))
> end

Ok, this works, but I modified it to:
billiards.cuecollision.cuespeed = function ()
    print (string.format ("Cue velocity: {%f, %f, %f}",
                                  bodies.cue.velocity[1],
                                  bodies.cue.velocity[2],
                                  bodies.cue.velocity[3]));
end

since I don't know that math.length function does.

I made an interesting observation about billiards.cuecollision.cuespeed.
It is almost always called 3 times and the first time it reports
unusually low numbers:
('f' pressed)
Cue velocity: {-0.000003, 0.000000, -0.000003}
Cue velocity: {-0.000003, 0.000000, -0.000003}
Cue velocity: {-0.000003, 0.000000, -0.000003}
('f' released)
('f' pressed)
Cue velocity: {-5.776280, 0.000000, -5.776280}
Cue velocity: {-5.776280, 0.000000, -5.776280}
Cue velocity: {-5.776280, 0.000000, -5.776280}
('f' released)
('f' pressed)
Cue velocity: {-4.332211, 0.000000, -4.332211}
Cue velocity: {-4.332211, 0.000000, -4.332211}
Cue velocity: {-4.332211, 0.000000, -4.332211}
('f' released)

> So what you would presumably want would be to be able to hit a key and
> have the stick launch to reach a certain speed before hitting the
> ball.  You need to bind some code to a key and you can use a node to
> do that.  There's a node called an event node.  When this is traversed
> it queries the windowing system for input events and fires hooks for
> each one.  So you need to define such a node and link it to the tree
> somewhere (where exactly is not important as long as you don't, by
> chance, overwrite one of my nodes).  Do it like this:
> 
> graph.launcher = frames.event {
>    keypress = function (self, key)
>       if key == 'f' then
>             -- Substitute suitable values here.
>             joints.arm.motor = {v, F_max}
>       end
>    end
> }

Ok, this works as you say.

However, running simulatins/experiments this way still requires manual
human input. Is it possible to somehow do this automatically?
For example: currently, I still have to click on the white ball to go
from looking mode to aiming mode and when I'm in the aiming mode, I have
to press 'f' to launch the stick.

I would like to do those 2 things from the code and be able to run 100s
of experiments without human input.

> Moving on to the third point.  You only want the final positions so
> you need to measure them once the shot is over.  There is no
> "finished" event and hook but there are "waiting" and "looking"
> events.  (You start waiting as soon as you strike the cue ball and
> when these come to a rest you start looking once more to decide upon
> your next shot).  You could use hooks for both these events to detect
> a transition between them or alternatively I could introduce a
> "finished" event which would be as simple.  But I suppose the best way
> to go would be to bind the logging to a key so that you have more
> control over it.  You can consult the lua manual to find out how to
> open a file and write to it.  I'll just provide some sample code to
> print it on the terminal:
> 
> graph.logger = frames.event {
>    keypress = function (self, key)
>       if key == 'l' then
>          for i, ball in bodies.balls do
>             print (string.format ("%d: {%f, %f, %f}\n", i,
>                                   ball.position[1],
>                                   ball.position[2],
>                                   ball.position[3]));
>          end
>       end
>    end
> }

Ok, perfect! Doing this automatically in the billiards.looking hook is
enough for me.


> As you can see bodies.balls is actually a table with all the ball
> nodes inside.  You traverse this and for each ball node you print it
> position vector.  Simple enough I believe.  After the shot is over and
> logged you need to reset the balls to their initial positions probably
> and this can be done by setting their postion in much the same way as
> you printed it:
> 
>          bodies.balls[1].position = {x_w, y_w, billiards.ballradius}
>          bodies.balls[2].position = {x_b, y_b, billiards.ballradius}
> 
> You can put this code right after the logging takes place if you want.
> This is more or less it for now. 

Ok, thanks.

One more thing, is there a hook which is triggered when the ball goes in
the hole?
I would like to use this to set up automatic logging to only log the
outcomes, where the non-cue ball goes in the hole.

> One thing that remains to be mentioned is where to put all this code.
> You can actually specify additional script files for Billiards (or
> rather Techne) to run with the -c switch.  So put all your code in a
> script file called, say experiment.lua and put this in say ~/foo.  You
> can then run it like this:
> 
> billiards -c ~/foo/experiment.lua

Ok, perfect.

> I should also say that all the code above has either been copied from
> Billiards' source or written on-the-fly and hasn't been  tested at
> all, as I can't run Billiards at work.  It might therefore not work as
> advertised and probably won't as I haven't done anything to Billiards
> for a while.  It should get you started nevertheless.  I advise you to
> look through Billiards' source as well.  Most of it will probably not
> make much sense but you should get a general idea of how it works and
> it's not that much anyway.  I'll try to implement my suggestions
> myself when I make the changes I mentioned earlier but this might take
> a few days.  Give it a shot on your own until then and let me know if
> you need further clarifications, explanations, help or whatever.

Thanks again for all your help!

Tadej

-- 
Tadej Janež <address@hidden>
Fakulteta za računalništvo in informatiko





reply via email to

[Prev in Thread] Current Thread [Next in Thread]