-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
new Frame Transform interfaces + ovrdevice refactoring #1958
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments.
* @param ids the returned vector containing all frame ids | ||
* @return true/false | ||
*/ | ||
virtual std::unordered_set<std::string> getAllFrameIds(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this and other methods, the old interface was:
bool getAllFrameIds (std::vector< std::string > &ids) override
the old method permitted to get the the frameIds
and the similar quantities without any dynamic memory allocation, while the new signature does not permit this. I suggest to also reintroduce the old signature to not constrain any user of the interface to have a dynamic memory allocation when using the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the old method had also a dynamic memory allocation as the frame count where subject to change. also if your concern is the std containers reinitialized at every frame we can simply make these container class member and return const references to them. or, if you insist, we can also expose overloads of these methods, similar to the old ones.. but first think about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the old method had also a dynamic memory allocation as the frame count where subject to change
As long as the capacity of the passed container is always greater than the maximum size, there is no dynamic memory allocation.
we can simply make these container class member and return const references to them
How do you enforce proper mutual exclusion in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's no way for the user to know the size currently and for the mutual exclusion, perhaps we can making it thread-local. maybe in that case the problem is when you have multiple instances. i have to check this cause i don't remember if it implies the staticness
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after a quick search i found this article https://web.archive.org/web/20130930101140/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value
didn't read it completely but seems to definitly promote the pass by value practice for best performances and for some caveats it propose different solution from the classical output function argument way. i'll read it with attention asap.
A good idea for get rid of this question once for all would be to do some test. i think i will do it. A thing that we can try is also to move the implementation of these method in the header in order to move the compilation of these function on the user side, allowing for further optimization in case of inner-loops calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's no way for the user to know the size currently
In practice on a given closed system you can measure the maximum number of frames, and call .reserve
with a value greater than that. More practically, what typically happens is that the vector is resized a few time, but as the capacity is not change when the vector if shrinked, so there actually are dynamic memory allocation only when the number of frames increased (not always to be honest, as typically the strategy used in std::vector
on resize
to increase its buffer is always to double its capacity if a reallocation is needed, regardless of the actual size requested.
perhaps we can making it thread-local
Personal opinion: I do not think that forcing any implementation of the getAllFrameIds
method to have a thread local std::vector<std::string>
buffer (or even just the additional complexity of doing it once) just to avoid the signature with the out variable passed as a reference is worth it.
after a quick search i found this article https://web.archive.org/web/20130930101140/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value
didn't read it completely but seems to definitely promote the pass by value practice for best performances and for some caveats it propose different solution from the classical output function argument way. i'll read it with attention asap.
That article assumes that the in any case the std::vector<std::string>
needs to be created ex-novo every time by the caller, and it is just arguing that for non-virtual methods defined in the same compilation unit of caller the compiler is able to ensure that the std::vector<std::string>
is created only once. Our case is quite different: we are discussing virtual methods (so the compiler at compile time has no way of knowing which method will be actually called) and we are discussing how to avoid any kind of memory allocation, i.e. that the std::vector<std::string>
is created even only once.
A good idea for get rid of this question once for all would be to do some test. i think i will do it.
Are you discussing speed tests or dynamic memory allocation tests? I am actually arguing to have an interface that does not force dynamic memory allocation, the increased speed would be just a byproduct from my point of view.
A thing that we can try is also to move the implementation of these method in the header in order to move the compilation of these function on the user side, allowing for further optimization in case of inner-loops calls.
As this is a virtual call that the users will call by just having a pointer to IFrameSource
, no matter what, the method cannot be inlined by the compiler, because the compiler has no idea of which method is actually called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest I just realized that on an increase in the number of the frames there always be a dynamic memory allocation if the additional frame id does not fit in the sso buffer. However not having dynamic memory allocation if the frame numbers do not change seems already quite convenient to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personal opinion: I do not think that forcing any implementation of the getAllFrameIds method to have a thread local std::vectorstd::string buffer (or even just the additional complexity of doing it once) just to avoid the signature with the out variable passed as a reference is worth it.
i would personally get rid of this kind of signature cause it bothers me a lot. none of the framework i use has this kind of signature. this should mean something. anyway if we find a way to have the same behaviour with a signature semantically appropriate why don't use every c++11/14 construct to do it?
Our case is quite different: we are discussing virtual methods (so the compiler at compile time has no way of knowing which method will be actually called)
this is true.. as it is true that is not mandatory at all for those method to be virtual. i had this doubt also for other reasons. removing the "virtualness" of the method would make the IFrameSource not an interface anymore, but a simple partially virtual public superclass. i don't know, i have to think about it
Are you discussing speed tests or dynamic memory allocation tests? I am actually arguing to have an interface that does not force dynamic memory allocation, the increased speed would be just a byproduct from my point of view.
ok this was not clear for me, thank you for pointing it out. if we add the external reference to be valorized, the interface should do a check on the capacity of the vector and return fail if inappropriate right? in this case i should also add a method to know the frame count. but what to do with device such as the vicon, where new marker can pop in or out in any moment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anyway if we find a way to have the same behaviour with a signature semantically appropriate why don't use every c++11/14 construct to do it?
Not sure if I got what you mean here.
ok this was not clear for me, thank you for pointing it out. if we add the external reference to be valorized, the interface should do a check on the capacity of the vector and return fail if inappropriate right? in this case i should also add a method to know the frame count. but what to do with device such as the vicon, where new marker can pop in or out in any moment?
Consistently with the rest of YARP, I do not think we need to ensure there are no dynamic memory allocations at all, but I just think we should avoid to have an interface that forces the users to have a quite huge number of dynamic memory allocations.
Some additional comments:
then in
It may be just my ordinary fear of new stuff, but the new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more comments.
i totally agree.
it is for the next feature of the ovrdevice so it will end up there anyway. it will be visualized inside the oculus when in regulation mode. if you it bother you i can remove it and reinsert it in the next pr i'm working on. Or we can simply leave it there |
|
@traversaro, maybe the |
It is a bit difficult to discuss if it is ok or not to merge it or not if it is not used in the current PR. What happens if for example during the discussion for the new feature it turns out that adding the
Ack. Consider that here there is a trade-off between the additional work necessary for you, and the additional complexity and associated problems (and resulting work) that may affect any YARP's user. |
it's not mandatory that is a additional work for me. i can work and correct things outside of yarp and then maybe someone else have to reintegrate or integrate them into it. maybe they'll end up to not be integrated at all while being useful things just because no one have time/want to spend time doing it. i understand your point though and i suggest to discuss this f2f |
Sorry, I meant a trade-off between "additional work that of people that actually need and benefits from the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not a great insight in the iFrameTransform
interface and the respective client/server, so I can't review it in terms of functionality. I have only notes about the code cleaning/formatting but I think it will be changed and refactored a lot, I wiil review it later then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR is very large and touches multiple aspects, making it difficult to review.
Let's start from the functionalities. Could you provide one or more diagrams which describe the relationship between the classes you propose, justifying their usage in some application scenarios (with/without a device driver, with/without ROS etc) ?
See for example the diagram below, which depicts the current architecture:
I tend to agree with @randaz81. |
actually, from a user perspective it follows the usual yarp devices architecture. with an interface, a device driver and two network wrapper (server side and client side). |
classical yarp device architecture ps. the architeture has improved a lot (it includes ROS interoperation, distributed comunication via topics and an interface to set some tf from the user application and stream them through the network) and a new schema will be uploaded asap
@randaz81 |
a9f1c81
to
4a9a045
Compare
the pr has been closed due to some technical disagreement |
This pr do a lot of different things. unfortunately all of them are strictly related so it cannot be splitted in different pr (or it's very painful doing it). also, splitting it in different pr makes very unclear the sense of some modifications.the necessity of this pr emerged with the urge to treat devices that produces frames (poses in the 3D space), like ovrdevice and vicon device, in the standard yarp way (with the interface + wrapper + client combo, P2P paradigm).
Until now, a device that produces frames had to open a
frameTransformClient
inside and comunicate via theframeTransformServer
to other clients via a Client-Server-Client architecture, different from the usual P2P comunication pattern.while this has some advantages it also forces a network comunication via yarp ports even when it is not needed (so it is not possible to open the device locally and get his data via c++ calls). In order to solve this i developed two new interfaces that can be adapted to both paradigm.
IFrameSource
: this particular interface can seems unusual cause it does not have any pubblic pure virtual method. This is because all the beaviour and the math involved in chaining the Frames toghether can be reused among all the devices and it is already implemented. instead it have a sort of protected intra-class interface, to allow a correct comunication between the parent class and the derived calsses, enforcing a lot of stuff and robustifying the architecture. in particular this is useful to build up a callback mechanism that allow the user to trigger a function call on every update of the device (even remotely).pr modification list:
- introduces a dependency in yarp to a new library of robotology calledRobotologyTemplateLibrary
, which contains some utilities that should not stay in yarp but since the library is still an unstable stub, the dependency is coordinated by the new flagYARP_ENABLE_UNSTABLE
. we cannot wait for the library to be stable, cause the development of this new library is strictly related to his possible usage. and it is only used in this pr at the moment, and it will likely used fisrt in yarp. with @traversaro we agreed to flag the new library as stable within max 2 releases of yarp and from then continue to develop the library with the usual deprecation policies. moving the dependency outside theYARP_ENABLE_UNSTABLE
flag.the work on this became way too time expensive and some minor importance elements have been reduced
- definition of a new global flagYARP_EXPERIMENTAL
. useful to confine part of the code that uses the new library or that are in a experimental state.with a tool offered by the new library,two new interfaces has been developed. Actually they come from the IFrameTransform interface, splitted in two parts. one for devices which only produces frames, IFrameSource,and one that rappresent the version 2 of the, and one for set some tf via function call from the user application (IFrameSet.. i know the name i ugly and misleading. go on, propose a new one!).IFrameTransform
yarp::math::FrameTransform name issue. two new name to identify the frame structure has been added:
frameId
andparentFrame
. this should substitute the olddst_frame_id
andsrc_frame_id
which have been deprecated. the new implementation solve the [FrameTransformClient] getChainedTransform method gives undesired results #1775ovrdevice
has been adapted to the new paradigm, deriving fromiFrameSource
, eliminating both the inclusion of the FrameTransformClient and the yarp port to publish the headset pose.the new implementation is confined by. this allows to use it without the transform server, taking the data directly from him via c++ code or remotely in a p2p via the network wrappersYARP_EXPERIMENTAL
, otherwise the old implementation is activeFrameReceiver
the client side network wrapper.FrameBroadcaster
the produces side network wrapper.these last three devices support the new callback system. so it is possible to have a user application triggered and syncronized with the
ovrdevice
thread.26/03/2019 the network wrappers comunication is made via publisher and subscriber so the distribution over multiple subscriber of the tf data is guaranteed by the topic mechanism. also the ros comunication can be archieved via topics because the message used by the network wrapper is
yarp::rosmsg::tf2_msgs::TFMessage
.notes:
- i think in the future, the FrameTransformClient should implement the newat this point the FrameTransform client and server can be dismissed..IFrameManager
interface, which is Client-Server-client compliant. @randaz81 told me it is used a lot outside yarp so i leaved it untouched.- no ROS compatibility have been added in theROS compatibility addedFrameBroadcaster
for now. it can be done in a future pr as it to be quick and easy.~~- a lot of interoperations with the other paradigm (FrameTransformClient/Server) are possible, though none of them have been developed at the moment. ~~
no interoperation with the old paradigm is needed anymore.
- since there are probably 762 different ways to do the cmake parts, i probably picked the wrong one and i presume it have to be corrected. so if you have suggestions regarding the "cmake-shining-compliant" way to accomplish what i've done don't be afraid of fullfill my lack of experience with cmake.the cmake part is very small right now- if it isn't clear the relation between all the element of the pr is the following: RobotologyTemplateLibrarythe pr is much more simplerResult
type is used in the ----> new interfaces to manage Frames which have been developed to change the comunication paradigm of the ----->ovrdevice
and Others. viceversa the ovrdevice stands as an example of the new implementation.the method documentationwill be added/updated after the review process (i expect it to be long)@GiulioRomualdi @DanielePucci @drdanz @Nicogene @randaz81 @traversaro @barbalberto