Skip to content
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

Object dynamic state #234

Open
wants to merge 49 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c23e502
[SaveWorldState] Corrected the save state functionality and added the…
mohammadkhoshnazarr Oct 10, 2024
b712e8a
[SaveState] Corrected arguments order in save simulator state.
AbdelrhmanBassiouny Oct 11, 2024
75723b3
[MultiverseContact] (WIP) Adding support for multiple contact points.
AbdelrhmanBassiouny Oct 15, 2024
1cb23fb
[MultiverseContact] Multiple contact points with normals now working.
AbdelrhmanBassiouny Oct 16, 2024
8a67ac7
[euROBIN] Added ur5e description and a demo for using it in eurobin.
AbdelrhmanBassiouny Oct 17, 2024
e25d055
[euROBIN] new process_module for gripper, accept grippers as separate…
AbdelrhmanBassiouny Oct 18, 2024
86b714c
[GiskardandRobokudo] Ignore virtual joints when setting joint goal in…
AbdelrhmanBassiouny Nov 5, 2024
8de923d
[MultiverseFallschoolDemo] (WIP) Need to figure out why giskard state…
AbdelrhmanBassiouny Nov 7, 2024
2adf2ba
[MultiverseFallschoolDemo] (WIP) Need to fix multiverse contact, and …
AbdelrhmanBassiouny Nov 8, 2024
217e174
[NavigateAction] Add an option that asks if the joint states should b…
AbdelrhmanBassiouny Nov 11, 2024
aea9593
[ActionDesignator] better prepose and approach technique for picking …
AbdelrhmanBassiouny Nov 12, 2024
aafcf49
[MultiverseFallschoolDemo] The demo works.
AbdelrhmanBassiouny Nov 12, 2024
f9dd053
[MultiverseFallschoolDemo] try and redo actions
AbdelrhmanBassiouny Nov 13, 2024
5bf6ece
[FixORM] added new paramters to orm classes to match actions/motions.
AbdelrhmanBassiouny Nov 20, 2024
e04a49b
[PhysicalObject] Added a physical object class.
AbdelrhmanBassiouny Nov 20, 2024
e734b00
[PhysicalObject] remove contacts, object state has a physical body st…
AbdelrhmanBassiouny Nov 20, 2024
0918965
[PhysicalBody] (WIP) refactoring bullet world to conform with new/cha…
AbdelrhmanBassiouny Nov 21, 2024
26a74b7
[PhysicalBody] (WIP) most tests are passing, there's a problem with t…
AbdelrhmanBassiouny Nov 22, 2024
4a3a731
[PhysicalBody] (WIP) fixed issue with high position tolerance.
AbdelrhmanBassiouny Nov 22, 2024
bd5c87c
[JupyterTests] (WIP) cram_plan_tutorial has problems.
AbdelrhmanBassiouny Nov 27, 2024
93a3072
[MultiverseGetImages] Made use of target pose to adjust camera pose.
AbdelrhmanBassiouny Nov 28, 2024
36733a9
[MultiverseFallschoolDemo] Merged with dev.
AbdelrhmanBassiouny Nov 29, 2024
8097842
[MultiversePycrap] used pycrap in multiverse.
AbdelrhmanBassiouny Nov 30, 2024
e9982a9
[NavigateAction] Add an option that asks if the joint states should b…
AbdelrhmanBassiouny Nov 11, 2024
ef9129c
[PhysicalObject] Added a physical object class.
AbdelrhmanBassiouny Nov 20, 2024
e9401c1
[PhysicalBody] (WIP) refactoring bullet world to conform with new/cha…
AbdelrhmanBassiouny Nov 21, 2024
34e2de0
[PhysicalBody] (WIP) most tests are passing, there's a problem with t…
AbdelrhmanBassiouny Nov 22, 2024
0853f02
[World] rename argument to is_prospection
AbdelrhmanBassiouny Nov 24, 2024
263235e
[VirtualJoint] no need for object.
AbdelrhmanBassiouny Nov 24, 2024
8d39764
[Link] Implement name property as it exists in two parents.
AbdelrhmanBassiouny Nov 24, 2024
0828ef0
[WorldObject] make color None by default instead of white.
AbdelrhmanBassiouny Nov 24, 2024
cff62f1
[LocalTransformer] solved bug where world objects were used instead o…
AbdelrhmanBassiouny Nov 24, 2024
a1a7db8
[Logging] added set log level.
AbdelrhmanBassiouny Nov 24, 2024
aef6fe0
[PhysicalBody] (WIP) Contact points return bodies not links.
AbdelrhmanBassiouny Nov 26, 2024
08e8b38
[PhysicalBody] Everything is a WorldEntity, and they all have parent …
AbdelrhmanBassiouny Nov 27, 2024
e29b493
[PhysicalBody] used pycrap in physical body instead of object.
AbdelrhmanBassiouny Dec 2, 2024
9a3cef6
[Giskard] removed duplicate set_joint_goal.
AbdelrhmanBassiouny Dec 2, 2024
9c37d26
[PhysicalBody] fixed some multiverse bugs.
AbdelrhmanBassiouny Dec 4, 2024
2333eda
[MultiverseFallSchoolDemo] added optional argument grasps to CostmapL…
AbdelrhmanBassiouny Dec 5, 2024
9403bcd
[PhysicalObject] corrections after rebasing on dev.
AbdelrhmanBassiouny Dec 11, 2024
17301e5
[Multiverse] Removed extra lock release in clients.
AbdelrhmanBassiouny Dec 13, 2024
5068e12
[HasConcept] added the has concept as parent to PhysicalBody
AbdelrhmanBassiouny Dec 13, 2024
b7c951a
[MultiverseFallSchoolDemo] merged changes from dev.
AbdelrhmanBassiouny Dec 13, 2024
89c162d
[Multiverse] removed unused dataclasses.
AbdelrhmanBassiouny Dec 13, 2024
497ad03
[Giskard] removed unused import.
AbdelrhmanBassiouny Dec 13, 2024
3f1ee35
[PR2ProcessModules] removed dublicate import.
AbdelrhmanBassiouny Dec 13, 2024
898a42c
[PhysicalBody] removed duplicate method, added a normal property for …
AbdelrhmanBassiouny Dec 15, 2024
3277e0c
[PhysicalBody] Added Supporter type in pycrap.
AbdelrhmanBassiouny Dec 16, 2024
5da450f
[PhysicalBody] minor review changes.
AbdelrhmanBassiouny Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/world_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class WorldConfig:
and the world synchronization.
"""

position_tolerance: float = 1e-2
position_tolerance: float = 1e-3
orientation_tolerance: float = 10 * math.pi / 180
prismatic_joint_position_tolerance: float = 1e-2
revolute_joint_position_tolerance: float = 5 * math.pi / 180
Expand Down
51 changes: 51 additions & 0 deletions demos/pycram_multiverse_demo/demo_euROBIN_industrial_robotics.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,54 @@


world.exit()
import logging
import os

from rospkg import RosPack

from pycram.datastructures.enums import ObjectType, GripperState, Arms
from pycram.process_module import simulated_robot, real_robot
from pycram.world_concepts.world_object import Object
from pycram.datastructures.pose import Pose
from pycram.ros_utils.force_torque_sensor import ForceTorqueSensor
from pycram.ros_utils.joint_state_publisher import JointStatePublisher
from pycram.worlds.multiverse import Multiverse
from pycram.designators.action_designator import SetGripperAction

SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
PYCRAM_DIR = os.path.join(SCRIPT_DIR, os.pardir, os.pardir)
RESOURCE_DIR = os.path.join(PYCRAM_DIR, "resources")

SPAWNING_POSES = {
"robot": Pose([0, 0, 0], [0.0, 0.0, 0.0, 1.0]), # x,y,z,qx,qy,qz,qw
"cereal": Pose([0.5, 0.5, 2.0], [0.0, 0.0, 0.0, 1.0])
}


def spawn_ur5e_with_gripper():
robot = Object("ur5e", ObjectType.ROBOT, "universal_robot/ur5e/urdf/ur5e.urdf")
gripper = Object("gripper-2F-85", ObjectType.GRIPPER, "robotiq/gripper-2F-85/gripper-2F-85.urdf")
wrist_3_tf_frame = robot.get_link_tf_frame("wrist_3_link")
gripper.set_pose(Pose([0, 0.1, 0], [1.0, 0.0, 0.0, -1.0], frame=wrist_3_tf_frame))
robot.attach(gripper, parent_link="wrist_3_link")
return robot, gripper


if __name__ == '__main__':
root = logging.getLogger()
root.setLevel(logging.INFO)

world = Multiverse(simulation_name="ur5e_with_task_board")

# Load environment, robot and objects
rospack = RosPack()
AbdelrhmanBassiouny marked this conversation as resolved.
Show resolved Hide resolved

robot, gripper = spawn_ur5e_with_gripper()

jsp = JointStatePublisher()
# fts = ForceTorqueSensor("ee_fixed_joint")
robot_arms = [chain.arm_type for chain in robot.robot_description.get_manipulator_chains()]
with real_robot:
SetGripperAction(robot_arms, [GripperState.CLOSE]).resolve().perform()

world.simulate(1)
1 change: 1 addition & 0 deletions examples/cram_plan_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def get_n_random_positions(pose_list, n=4, dist=0.5, random=True):
```

```python
import pycrap
from tf.transformations import quaternion_from_euler
import pycrap
from pycram.costmaps import SemanticCostmap
Expand Down
168 changes: 131 additions & 37 deletions src/pycram/datastructures/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..description import Link
from ..world_concepts.world_object import Object
from ..world_concepts.constraints import Attachment
from .world_entity import PhysicalBody


def get_point_as_list(point: Point) -> List[float]:
Expand Down Expand Up @@ -478,15 +479,78 @@ class State(ABC):
pass


@dataclass
class PhysicalBodyState(State):
"""
Dataclass for storing the state of a physical body.
"""
pose: Pose
is_translating: bool
is_rotating: bool
velocity: List[float]
acceptable_pose_error: Tuple[float, float] = (0.001, 0.001)
acceptable_velocity_error: Tuple[float, float] = (0.001, 0.001)

def __eq__(self, other: 'PhysicalBodyState'):
AbdelrhmanBassiouny marked this conversation as resolved.
Show resolved Hide resolved
return (self.pose_is_almost_equal(other)
and self.is_translating == other.is_translating
and self.is_rotating == other.is_rotating
and self.velocity_is_almost_equal(other)
)

def pose_is_almost_equal(self, other: 'PhysicalBodyState') -> bool:
AbdelrhmanBassiouny marked this conversation as resolved.
Show resolved Hide resolved
"""
Check if the pose of the object is almost equal to the pose of another object.

:param other: The state of the other object.
:return: True if the poses are almost equal, False otherwise.
"""
return self.pose.almost_equal(other.pose, other.acceptable_pose_error[0], other.acceptable_pose_error[1])

def velocity_is_almost_equal(self, other: 'PhysicalBodyState') -> bool:
"""
Check if the velocity of the object is almost equal to the velocity of another object.

:param other: The state of the other object.
:return: True if the velocities are almost equal, False otherwise.
"""
if self.velocity is None or other.velocity is None:
return self.velocity == other.velocity
return (self.vector_is_almost_equal(self.velocity[:3], other.velocity[:3], self.acceptable_velocity_error[0])
and self.vector_is_almost_equal(self.velocity[3:], other.velocity[3:], self.acceptable_velocity_error[1]))

@staticmethod
def vector_is_almost_equal(vector1: List[float], vector2: List[float], acceptable_error: float) -> bool:
"""
Check if the vector is almost equal to another vector.

:param vector1: The first vector.
:param vector2: The second vector.
:param acceptable_error: The acceptable error.
:return: True if the vectors are almost equal, False otherwise.
"""
return np.all(np.array(vector1) - np.array(vector2) <= acceptable_error)

def __copy__(self):
return PhysicalBodyState(pose=self.pose.copy(),
is_translating=self.is_translating, is_rotating=self.is_rotating,
velocity=self.velocity.copy(),
acceptable_pose_error=deepcopy(self.acceptable_pose_error),
acceptable_velocity_error=deepcopy(self.acceptable_velocity_error))


@dataclass
class LinkState(State):
"""
Dataclass for storing the state of a link.
"""
body_state: PhysicalBodyState
constraint_ids: Dict[Link, int]

def __eq__(self, other: 'LinkState'):
return self.all_constraints_exist(other) and self.all_constraints_are_equal(other)
return (self.body_state == other.body_state
and self.all_constraints_exist(other)
and self.all_constraints_are_equal(other))

def all_constraints_exist(self, other: 'LinkState') -> bool:
"""
Expand All @@ -509,7 +573,7 @@ def all_constraints_are_equal(self, other: 'LinkState') -> bool:
other.constraint_ids.values())])

def __copy__(self):
return LinkState(constraint_ids=copy(self.constraint_ids))
return LinkState(copy(self.body_state), constraint_ids=copy(self.constraint_ids))


@dataclass
Expand All @@ -533,26 +597,20 @@ class ObjectState(State):
"""
Dataclass for storing the state of an object.
"""
pose: Pose
body_state: PhysicalBodyState
attachments: Dict[Object, Attachment]
link_states: Dict[int, LinkState]
joint_states: Dict[int, JointState]
acceptable_pose_error: Tuple[float, float]

def __eq__(self, other: 'ObjectState'):
return (self.pose_is_almost_equal(other)
return (self.body_state == other.body_state
and self.all_attachments_exist(other) and self.all_attachments_are_equal(other)
and self.link_states == other.link_states
and self.joint_states == other.joint_states)

def pose_is_almost_equal(self, other: 'ObjectState') -> bool:
"""
Check if the pose of the object is almost equal to the pose of another object.

:param other: The state of the other object.
:return: True if the poses are almost equal, False otherwise.
"""
return self.pose.almost_equal(other.pose, other.acceptable_pose_error[0], other.acceptable_pose_error[1])
@property
def pose(self) -> Pose:
return self.body_state.pose

def all_attachments_exist(self, other: 'ObjectState') -> bool:
"""
Expand Down Expand Up @@ -640,20 +698,24 @@ class LateralFriction:
@dataclass
class ContactPoint:
"""
Dataclass for storing the information of a contact point between two objects.
Dataclass for storing the information of a contact point between two bodies.
"""
link_a: Link
link_b: Link
position_on_object_a: Optional[List[float]] = None
position_on_object_b: Optional[List[float]] = None
normal_on_b: Optional[List[float]] = None # the contact normal vector on object b pointing towards object a
body_a: PhysicalBody
body_b: PhysicalBody
position_on_body_a: Optional[List[float]] = None
position_on_body_b: Optional[List[float]] = None
normal_on_body_b: Optional[List[float]] = None # the contact normal vector on object b pointing towards object a
distance: Optional[float] = None # distance between the two objects (+ve for separation, -ve for penetration)
normal_force: Optional[List[float]] = None # normal force applied during last step simulation
lateral_friction_1: Optional[LateralFriction] = None
lateral_friction_2: Optional[LateralFriction] = None

@property
def normal(self) -> List[float]:
return self.normal_on_body_b

def __str__(self):
return f"ContactPoint: {self.link_a.object.name} - {self.link_b.object.name}"
return f"ContactPoint: {self.body_a.name} - {self.body_b.name}"

def __repr__(self):
return self.__str__()
Expand All @@ -670,24 +732,24 @@ class ContactPointsList(list):
A list of contact points.
"""

def get_links_that_got_removed(self, previous_points: 'ContactPointsList') -> List[Link]:
def get_bodies_that_got_removed(self, previous_points: 'ContactPointsList') -> List[Link]:
"""
Return the links that are not in the current points list but were in the initial points list.
Return the bodies that are not in the current points list but were in the initial points list.

:param previous_points: The initial points list.
:return: A list of Link instances that represent the links that got removed.
:return: A list of bodies that got removed.
"""
initial_links_in_contact = previous_points.get_links_in_contact()
current_links_in_contact = self.get_links_in_contact()
return [link for link in initial_links_in_contact if link not in current_links_in_contact]
initial_bodies_in_contact = previous_points.get_bodies_in_contact()
current_bodies_in_contact = self.get_bodies_in_contact()
return [body for body in initial_bodies_in_contact if body not in current_bodies_in_contact]

def get_links_in_contact(self) -> List[Link]:
def get_bodies_in_contact(self) -> List[PhysicalBody]:
"""
Get the links in contact.
Get the bodies in contact.

:return: A list of Link instances that represent the links in contact.
:return: A list of bodies that are in contact.
"""
return [point.link_b for point in self]
return [point.body_b for point in self]

def check_if_two_objects_are_in_contact(self, obj_a: Object, obj_b: Object) -> bool:
"""
Expand All @@ -697,8 +759,21 @@ def check_if_two_objects_are_in_contact(self, obj_a: Object, obj_b: Object) -> b
:param obj_b: An instance of the Object class that represents the second object.
:return: True if the objects are in contact, False otherwise.
"""
return (any([point.link_b.object == obj_b and point.link_a.object == obj_a for point in self]) or
any([point.link_a.object == obj_b and point.link_b.object == obj_a for point in self]))
return (any([self.is_body_in_object(point.body_b, obj_b)
and self.is_body_in_object(point.body_a, obj_a) for point in self]) or
any([self.is_body_in_object(point.body_a, obj_b)
and self.is_body_in_object(point.body_b, obj_a) for point in self]))

@staticmethod
def is_body_in_object(body: PhysicalBody, obj: Object) -> bool:
"""
Check if the body belongs to the object.

:param body: The body.
:param obj: The object.
:return: True if the body belongs to the object, False otherwise.
"""
return body in list(obj.links.values()) or body == obj

def get_normals_of_object(self, obj: Object) -> List[List[float]]:
"""
Expand All @@ -715,16 +790,16 @@ def get_normals(self) -> List[List[float]]:

:return: A list of float vectors that represent the normals of the contact points.
"""
return [point.normal_on_b for point in self]
return [point.normal_on_body_b for point in self]

def get_links_in_contact_of_object(self, obj: Object) -> List[Link]:
def get_links_in_contact_of_object(self, obj: Object) -> List[PhysicalBody]:
"""
Get the links in contact of the object.

:param obj: An instance of the Object class that represents the object.
:return: A list of Link instances that represent the links in contact of the object.
"""
return [point.link_b for point in self if point.link_b.object == obj]
return [point.body_b for point in self if point.body_b.parent_entity == obj]

def get_points_of_object(self, obj: Object) -> 'ContactPointsList':
"""
Expand All @@ -733,7 +808,25 @@ def get_points_of_object(self, obj: Object) -> 'ContactPointsList':
:param obj: An instance of the Object class that represents the object that the points are related to.
:return: A ContactPointsList instance that represents the contact points of the object.
"""
return ContactPointsList([point for point in self if point.link_b.object == obj])
return ContactPointsList([point for point in self if self.is_body_in_object(point.body_b, obj)])

def get_points_of_link(self, link: Link) -> 'ContactPointsList':
"""
Get the points of the link.

:param link: An instance of the Link class that represents the link that the points are related to.
:return: A ContactPointsList instance that represents the contact points of the link.
"""
return self.get_points_of_body(link)

def get_points_of_body(self, body: PhysicalBody) -> 'ContactPointsList':
"""
Get the points of the body.

:param body: An instance of the PhysicalBody class that represents the body that the points are related to.
:return: A ContactPointsList instance that represents the contact points of the body.
"""
return ContactPointsList([point for point in self if body == point.body_b])

def get_objects_that_got_removed(self, previous_points: 'ContactPointsList') -> List[Object]:
"""
Expand Down Expand Up @@ -780,7 +873,7 @@ def get_objects_that_have_points(self) -> List[Object]:

:return: A list of Object instances that represent the objects that have points in the list.
"""
return list({point.link_b.object for point in self})
return list({point.body_b.parent_entity for point in self})

def __str__(self):
return f"ContactPointsList: {', '.join([point.__str__() for point in self])}"
Expand Down Expand Up @@ -833,6 +926,7 @@ class VirtualMobileBaseJoints:
"""
Dataclass for storing the names, types and axes of the virtual mobile base joints of a mobile robot.
"""

translation_x: Optional[VirtualJoint] = VirtualJoint(VirtualMobileBaseJointName.LINEAR_X.value,
JointType.PRISMATIC,
Point(1, 0, 0))
Expand Down
2 changes: 1 addition & 1 deletion src/pycram/datastructures/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ class HasConcept:
"""

def __init__(self):
self.ontology_individual = self.ontology_concept()
self.ontology_individual = self.ontology_concept()
Loading