-
Notifications
You must be signed in to change notification settings - Fork 287
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
Eradicating memory leaks & making classes copy-safe and clonable #369
Conversation
…ead of SoftBodyNodes directly
The SDF Parsers have undergone a major overhaul. The public API is unchanged (except for providing shared_ptrs instead of raw pointers for Skeletons; we'll be doing the same for Worlds soon). Considering the extent of changes that have been made, if anyone has an SDF file that they like, I'd appreciate testing it with the new parser. The atlasSimbicon app appears to be working fine, but I'd like to know if there are any edge cases that clobber the changes I've made. |
You can find an example with the preprocessor definitions here as: #if defined(_MSC_VER) Edit: Regular const variable looks more close alternative to constexpr to me. |
I recently removed the call to Skeleton::init( I think it's very undesirable that adding a Skeleton to a world runs the risk of changing the indexing of the BodyNodes and generalized coordinates in the Skeleton, so I want to keep Skeleton::init( What does everyone else think? |
In my latest commits, I've created the dart::dynamics::Group class (which I had originally planned on naming I've also fixed the indexing issues that arose with the atlasSimbicon app and the bipedStand app. |
I've noticed something that might raise some red flags: The commit af95121 has altered the behavior of the softBodies app. In the past, the cylinder ends standing on its bottom, but ever since the change to the generalized coordinate differencing, it falls on its side. The cylinder is in an unstable state that crucial point in the simulation, so either end result is entirely plausible, and I don't know that there's an objective way of determining which result is "correct". I suspect that once you account for things like integration error and the simplifications inherent in our friction and collision handling dynamics, either result can be considered "correct". But it might be worth considering what about that particular commit could have resulted in this quantitative change, and whether the change was something good, bad, or neutral. |
worldClone->getFrame(current_parent->getName()); | ||
|
||
if(parent_candidate) | ||
worldClone->getFrame(i)->setParentFrame(parent_candidate.get()); |
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.
Any possibility if a SimpleFrame fails to find its parent in the cloned world? I think it shouldn't be.
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.
If the parent of the SimpleFrame is another SimpleFrame which has not been added to the original World, then it will not be found in the new World.
The motivation behind this is you can decide which SimpleFrames are tied to their World versus which that aren't. You can have some SimpleFrames which will be copied when their World is cloned while other SimpleFrames are used across all the World copies.
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.
It makes sense. So the parent frame of a SimpleFrame is able to be in a different World from the World the SimpleFrame belongs to.
Beside on this, I came up with some idea that might be useful or not. That is _master world_. Multiple worlds can have a master world like master slide of presentation tools. The difference from cloning is all the worlds share the skeletons and simple frames in the master world rather than actually creating the instances. This might be useful if we want to simulate with different parameters while having invariant things in the master world.
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.
So the parent frame of a SimpleFrame is able to be in a different World from the World of the SimpleFrame.
It's more like, a SimpleFrame isn't necessarily tied to a World at all. If you decide to tie a SimpleFrame to a World, then a copy of it will be made when the World is cloned. But if you don't tie a SimpleFrame to a World, then it won't get cloned automatically.
I'm not sure I'm following how the master world concept would work, although it might be related to something that I'm thinking about for the future: lazy copying. If we were to lazily copy BodyNodes and Skeletons, then we could make it so that the properties of a copied BodyNode are just references to the properties of the original BodyNode, until the user decides to change one of the properties. At that point, the copied BodyNode will instantiate whatever it needs to, instead of just referencing the original. The implementation would be somewhat challenging, but certainly doable. The big question would be whether changing a property in the original should also carry over to the existing clones of the original.
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.
It's more like, a SimpleFrame isn't necessarily tied to a World at all.
I understand it more clearly now. I exclusion the case a SimpleFrame isn't tied to a World.
lazy copying sounds interesting, and I agree with that the implementation would be somewhat challenging.
The big question would be whether changing a property in the original should also carry over to the existing clones of the original.
In my view, changing a property in the original shouldn't carry over to the clones, and they should be able to have different property values. It might be able to give a flag whether the property carry over to the clones, but keeping same property values in different world might be physically infeasible under certain circumstances. However, all the entities in the master world will always carry the same properties to all the dependent worlds. One use case I can imagine now is that we put entities for static environment to the master world and run different simulations in multiple worlds sharing the mast world. So whether carrying a property or not will be the differences between lazy copying and master world.
Edit: master world would be more meaningful if we form a set of world. WorldSet would have one master world and multiple worlds as many as user want to simulate at the same time. I guess simultaneous multiple simulation would be useful when user want to test his/her controller in the same environment but different parameters at the same time.
I decided to go with a directory named |
Could we change file name of Also, the copyright information should be updated, and I would like to add comment that shows the final smart pointer class names at least one per each macro. Here is possible revised version what I imagine: /*
* Copyright (c) 2015, Georgia Tech Research Corporation
* All rights reserved.
*
* Author(s): Michael X. Grey <mxgrey@gatech.edu>
*
* Georgia Tech Graphics Lab and Humanoid Robotics Lab
*
* Directed by Prof. C. Karen Liu and Prof. Mike Stilman
* <karenliu@cc.gatech.edu> <mstilman@cc.gatech.edu>
*
* This file is provided under the following "BSD-style" License:
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DART_DYNAMICS_PTR_H_
#define DART_DYNAMICS_PTR_H_
#include "dart/dynamics/detail/BodyNodePtr.h"
#include "dart/dynamics/detail/JointPtr.h"
#include "dart/dynamics/detail/DegreeOfFreedomPtr.h"
// This file is a lightweight means of providing the smart pointers which are
// commonly used within the dart::dynamics namespace. It is 'lightweight' in the
// sense that it does not depend on any types being fully defined, making this
// header suitable for inclusion in other headers which might only want access
// to the smart pointers without needing fully defined classes.
namespace dart {
namespace dynamics {
//==============================================================================
// -- Standard shared/weak pointers --
// Define a typedef for const and non-const version of shared_ptr and weak_ptr
// for the class X
#define DART_DYNAMICS_MAKE_SHARED_WEAK( X ) \
typedef std::shared_ptr< X > X ## Ptr; \
typedef std::shared_ptr< const X > Const ## X ## Ptr; \
typedef std::weak_ptr< X > Weak ## X ## Ptr; \
typedef std::weak_ptr< const X > WeakConst ## X ## Ptr;
// Skeleton smart pointers
class Skeleton;
DART_DYNAMICS_MAKE_SHARED_WEAK(Skeleton)
// These pointers will take the form of:
// std::shared_ptr<Skeleton> --> SkeletonPtr
// std::shared_ptr<const Skeleton> --> ConstSkeletonPtr
// std::weak_ptr<Skeleton> --> WeakSkeletonPtr
// std::weak_ptr<const Skeleton> --> WeakConstSkeletonPtr
// MetaSkeleton smart pointers
class MetaSkeleton;
DART_DYNAMICS_MAKE_SHARED_WEAK(MetaSkeleton)
// ReferentialSkeleton smart pointers
class ReferentialSkeleton;
DART_DYNAMICS_MAKE_SHARED_WEAK(ReferentialSkeleton)
class Group;
DART_DYNAMICS_MAKE_SHARED_WEAK(Group)
class Linkage;
DART_DYNAMICS_MAKE_SHARED_WEAK(Linkage)
class Branch;
DART_DYNAMICS_MAKE_SHARED_WEAK(Branch)
class Chain;
DART_DYNAMICS_MAKE_SHARED_WEAK(Chain)
// Shape smart pointers
class Shape;
DART_DYNAMICS_MAKE_SHARED_WEAK(Shape)
//==============================================================================
// -- Custom BodyNode smart pointers --
#define DART_DYNAMICS_MAKE_BODYNODEPTR( X ) \
typedef TemplateBodyNodePtr< X > X ## Ptr; \
typedef TemplateBodyNodePtr< const X > Const ## X ## Ptr; \
typedef TemplateWeakBodyNodePtr< X > Weak ## X ## Ptr; \
typedef TemplateWeakBodyNodePtr< const X > WeakConst ## X ## Ptr;
// BodyNode smart pointers
class BodyNode;
DART_DYNAMICS_MAKE_BODYNODEPTR(BodyNode)
// These pointers will take the form of:
// TemplateBodyNodePtr<BodyNode> --> BodyNodePtr
// TemplateBodyNodePtr<const BodyNode> --> ConstBodyNodePtr
// TemplateWeakBodyNodePtr<BodyNode> --> WeakBodyNodePtr
// TemplateWeakBodyNodePtr<const BodyNode> --> WeakConstBodyNodePtr
// SoftBodyNode smart pointers
class SoftBodyNode;
DART_DYNAMICS_MAKE_BODYNODEPTR(SoftBodyNode)
//==============================================================================
// -- BodyNode dependent smart pointers --
#define DART_DYNAMICS_MAKE_BN_DEPENDENT_PTR( X ) \
typedef Template ## X ## Ptr < X , BodyNode > X ## Ptr; \
typedef Template ## X ## Ptr < const X , const BodyNode > Const ## X ## Ptr; \
typedef TemplateWeak ## X ## Ptr < X , BodyNode > Weak ## X ## Ptr; \
typedef TemplateWeak ## X ## Ptr < const X , const BodyNode > WeakConst ## X ## Ptr;
// Joint smart pointers
class Joint;
DART_DYNAMICS_MAKE_BN_DEPENDENT_PTR(Joint)
// These pointers will take the form of:
// TemplateJointPtr<Joint> --> JointPtr
// TemplateJointPtr<const Joint> --> ConstJointPtr
// TemplateWeakJointPtr<Joint> --> WeakJointPtr
// TemplateWeakJointPtr<const Joint> --> WeakConstJointPtr
// DegreeOfFreedom smart pointers
class DegreeOfFreedom;
DART_DYNAMICS_MAKE_BN_DEPENDENT_PTR(DegreeOfFreedom)
} // namespace dynamics
} // namespace dart
#endif // DART_DYNAMICS_PTR_H_
|
Beside on There are still few issues but let's make them as separate issues or pull requests. I think the main purpose of this PR is already fulfilled. |
std::cout << skel->getBodyNode(j)->getSpatialInertia() << "\n" << std::endl; | ||
} | ||
} | ||
|
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.
Is this for debug?
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.
Hahah, I would guess so. Probably from when I created the Spatial Inertia class. I'll remove 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.
Thanks. I do this a lot. :)
Eradicating memory leaks & making classes copy-safe and clonable
This is a premature pull request for review and discussion purposes, not ready to be merged yetThis pull request is ready for review
This branch and pull request are dedicated to removing memory leaks from DART as well introducing the ability to copy properties and create clones of objects. Spawning clones will be useful for making efficient multithreaded applications.
The changes being made here are pervasive, and some will require breaking the API, specifically the adoption of std::shared_ptr for the Shape and Skeleton classes.
Here is a brief list of the conceptual changes:
To be determined:
It would also be good to have a concept of a "State" to complement the "Properties" concept. I am still hashing out the details for how a State class would work, so suggestions are welcome. At the moment, I think the State should belong to the Skeleton, but it's not clear to me exactly how much information it should contain. It could either be just Generalized Position, Velocity, Acceleration, and Force vectors, or it could also include information like external forces.