I’m beginning with poppy, and there is something I do not really understand… How does a primitive work ? I mean, I know how to write and to use one, but I do not fully understand how it is managed by Pypot.
The first point is : I guess when a primitive is executed by the main (i.e. poppy.primitiveName.start() ), it is executed at the same time as the main (like in real time). That means that the main can execute some instructions while the primitive is working. Am I wright ? ( I did some tests with some print and time.sleep() to check this point but I’m still not sure due to some behaviors I’ve seen)
The second point is : in the main, when poppy.primitiveName.stop() is executed, does it stop the primitive execution ? Or what is the function of .stop() ? Because when I do something like :
> print ‘lets go primitive!’
> Poppy.primitiveName.start()
> time.sleep(1)
> print ‘stop primitive’
> Poppy.primitiveName.stop()
where primitiveName lasts more than 1 second (time.sleep(2) integrated at the beginning at the primitive), all the instructions of the primitive are executed.
And if you think that some other stuffs are useful about primitives, I’m listening
Cool to see that someone is trying to use primitives! Clearly this is not the part of pypot which is the most intuitive
Yes exactly. If you are familiar with parallelism paradigm, a primitive is mainly a thread. It runs in background, while your main program keeps running. Some primitives can run for a fixed amount of time, other will run as long as your main program runs.
That’s actually a bit tricky. If you look at the source code you will see that basically the only thing that this method is doing is setting the running signal to False. Indeed, in Python there is not really any (at least clean) way to stop a thread. The only thing you can do is letting the thread knows that it should stop (the running signal) but it’s up to the user to actually handle this signal.
You can have a look on LoopPrimitive for instance. You will see that it basically call an update function at a predefined frequency and that at each loop iteration we check wether we should stop: i.e. break from our loop and return form the run method.
""" Makes a run loop which calls an update function at a predefined frequency. """
while not thread.should_stop():
if thread.should_pause():
thread.wait_to_resume()
start = time.time()
update_func()
end = time.time()
dt = thread.period - (end - start)
if dt > 0:
time.sleep(dt)
Actually, I’m kind of familiar with real-time, but not with linux/unix. However, I do now understand how a primitive works ! (thanks to your answer and openclassroom (french), a tutorial on threads ).
In any case, without parallelism paradigm, I did not see any reason to use primitive (except making the code more readable and shorter), but actually, it can be really useful, when correctly implemented !
Cool to see that someone is trying to use primitives! Clearly this is not the part of pypot which is the most intuitive
Do you mean that (almost) nobody is working with primitives on Poppy ? Cause I was planning to create some to record moves or positions in json files, to then play moves directly or by combining them. (MoveRecorder and MovePlayer do not exactly correspond to my expectations)
If I have time to work on it, I would like to reduce to default recorder frequency, and locally encode trajectory into splines to smooth the resulted movement, which can be jerky if there noise (with bad wires for example).
By now, I was working in position using json files. I’m not using trajectory yet.
My expectations are the following (for now, brainstorming phase) :
As I said, I want 2 primitives :
To save positions
scanning Poppy (motors positions)
saving the positions in a json file (a beautiful and organised one !)
integrating a kind of ID/name for each position
To play a move (maybe this one will call another primitive)
read one or more json file(s) (to do a simple or complex/concatenated move)
do a smoothy move (no jerk) [I find that the move is jerkier when a lot of motors are activated at the same time…]
Concerning the json files, I want to have full control on them so that not only these 2 primitives can use them. (expected future uses [not defined yet] ).
As you can see, it’s not so far from moveRecorder and movePlayer, but it will allows me (and all the users) to have more control, realize smoother moves, but especially to have json files which are reusable for other primitives/projects.
@Theo Why not, but I’m not expecting yet to work on trajectories, but only with positions for now. But it might be the next step. So let me know if you are interested in this (little) project, especially to smooth the resulted movement (I think it would be the part I’ll deal with, with the most difficulties) ! ^^
If you talk about the fact that the dictionary of timestamp is not ordered, you can make a pull request, it’s not a big change !
I’m not sure to understand, if you want to add a name to each positions, you would like to record each position by hand, one by one ?
I’m totally in favor to add an high level processing toolbox on the MovePlayer (or maybe with another name, separated for the player). I would be also useful to add a cleaner to detect and delete begins and end of file when the robot is not moving.
If you are interested in position recording, I suggest you to look at FIRE, the software made by @Thot for the choregraphy of School of the moon spectacle (and more) ; there is lot of good ideas to take.
If find that recording positions one by one (like keyframes in animation) are painful and not very intuitive vs recording trajectories ; but it is more easy to edit. A middle way could be to automatically create keypoints with a dynamic frequency to follow a trajectory ; but it could be heavy for CPU.
To recap, I’m in favor to allow more control in the way that move are recorded and play, and making them more generic.
As I said, I’m still in the brainstorming phase (even I’ve begun programming, it’s just to observe and know how Poppy moves and works). Several possibilities exist for the json file :
only 1 position/file (not really a good solution, but I was testing with this)
several positions/file with an ID (timestamp ? counter ? coded ID ?..) for a complete movement. The IDs would permit to decompose the complete movement in sequences of movement (specific movements)
several positions/file with an ID (timestamp ? counter ? coded ID ?..) for a specific movement (stand up, right arm goes up, rotation of the head…). The specific movement will have a name. [I’m thinking about this solution]
combined to the last solution, another file (?) with a list of specific movements to make a global movement (like a dance)
So I have to think about it (ID ? no ID ? timestamp ? architecture of the json file ?..). At the end, i want that the user can record a complete movement thanks to 2 solutions minimum :
moving Poppy
combining specific movements and/or modifying the values (that’s why I need to know perfectly the architecture of the json file)
I think I won’t use MovePlayer, except if we can save a rearranged json file ? (like you said with a pull request ? Or is it only to pull the data ?)
Also, I was thinking as a “start moving detector” and a “stop moving detector” function to start and stop recording. Is it what you are saying with the cleaner ?
I was thinking about something like this to make the relationship between the position and the trajectory. Well, I’ll have to check if it is possible or not…
Well, I think i’ll do that for the next hours (days ?), while continuing brainstorming and studying Poppy’s solutions.
In any case, i’m glad that my project looks interesting ! I’ll let you know what sounds like the best solution to me, at the end of the brainstorming phase !
Yes, you can save a json file with the same structure ordered by timestamp without breaking anything.
To do that, you have to refactor (or rewrite) the KDTreeDict to extend OrderedDict.
More or less, I was thinking of a post processor, which is more secure (avoir to loose data) ; moreover I think the “stop moving detector” is impossible to do well (a pause in a movement can be voluntary).