Skip to content

Commit

Permalink
chore: updated nova interface and simplified examples
Browse files Browse the repository at this point in the history
  • Loading branch information
cbiering committed Dec 17, 2024
1 parent 50ef973 commit 4ff9562
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 143 deletions.
21 changes: 10 additions & 11 deletions examples/01_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ async def main():
cell = nova.cell()
controller = await cell.controller("ur")

async with controller:
motion_group = controller.motion_group()
motion_group = controller[0]

# Current motion group state
state = await motion_group.get_state("Flange")
print(state)
# Current motion group state
state = await motion_group.get_state("Flange")
print(state)

# Current joints positions
joints = await motion_group.joints("Flange")
print(joints)
# Current joints positions
joints = await motion_group.joints("Flange")
print(joints)

# Current TCP pose
tcp_pose = await motion_group.tcp_pose("Flange")
print(tcp_pose)
# Current TCP pose
tcp_pose = await motion_group.tcp_pose("Flange")
print(tcp_pose)


if __name__ == "__main__":
Expand Down
17 changes: 6 additions & 11 deletions examples/02_plan_and_execute.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from nova import Nova, ptp, jnt, Pose
from nova import Nova
from nova.actions import ptp, jnt
from nova.types import Pose
from math import pi
import asyncio

Expand All @@ -14,11 +16,9 @@ async def main():
home_joints = (0, -pi / 4, -pi / 4, -pi / 4, pi / 4, 0)

# Connect to the controller and activate motion groups
async with controller:
motion_group = controller.motion_group()

async with controller[0] as mg:
# Get current TCP pose and offset it slightly along the x-axis
current_pose = await motion_group.tcp_pose("Flange")
current_pose = await mg.tcp_pose("Flange")
target_pose = current_pose @ Pose((1, 0, 0, 0, 0, 0))

actions = [
Expand All @@ -33,14 +33,9 @@ async def main():
jnt(home_joints),
ptp(target_pose @ Pose((400, 0, 0, 0, 0, 0))),
jnt(home_joints),
ptp(target_pose),
jnt(home_joints),
]

# plan_response = await motion_group.plan(trajectory, tcp="Flange")
# print(plan_response)

await motion_group.run(actions, tcp="Flange", movement_controller=move_forward)
await mg.run(actions, tcp="Flange", movement_controller=move_forward)


if __name__ == "__main__":
Expand Down
9 changes: 5 additions & 4 deletions examples/03_move_and_set_ios.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from nova import Nova, Pose, ptp, jnt
from nova import Nova
from nova.types import Pose
from math import pi

# TODO: public interface
from nova.types.action import WriteAction
# TODO: update I/O interaction interface
from nova.actions import WriteAction, ptp, jnt
import asyncio


Expand All @@ -23,7 +24,7 @@ async def main():
target_pose = current_pose @ Pose((100, 0, 0, 0, 0, 0))
actions = [
jnt(home_joints),
# controller.write_on_path("digital_out[0]", value=False),
# TODO: controller.write_on_path("digital_out[0]", value=False),
WriteAction(device_id="ur", key="digital_out[0]", value=False),
ptp(target_pose),
jnt(home_joints),
Expand Down
13 changes: 5 additions & 8 deletions examples/04_move_multiple_robots.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
from nova import Nova, ptp, jnt, Controller, speed_up_movement_controller
from nova import Nova, Controller, speed_up_movement_controller
from nova.actions import ptp, jnt
from math import pi
import asyncio


async def move_robot(controller: Controller):
home_joints = (0, -pi / 4, -pi / 4, -pi / 4, pi / 4, 0)

async with controller:
motion_group = controller.motion_group()

current_pose = await motion_group.tcp_pose("Flange")
async with controller[0] as mg:
current_pose = await mg.tcp_pose("Flange")
target_pose = current_pose @ (100, 0, 0, 0, 0, 0)
actions = [jnt(home_joints), ptp(target_pose), jnt(home_joints)]

await motion_group.run(
actions, tcp="Flange", movement_controller=speed_up_movement_controller
)
await mg.run(actions, tcp="Flange", movement_controller=speed_up_movement_controller)


async def main():
Expand Down
4 changes: 3 additions & 1 deletion examples/05_selection_motion_group_activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"""

from math import pi
from nova import Nova, ptp, MotionGroup, Pose
from nova import Nova, MotionGroup
from nova.types import Pose
from nova.actions import ptp
import asyncio


Expand Down
16 changes: 8 additions & 8 deletions nova/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
from nova.core.nova import Nova, Cell
from nova.core.motion_group import MotionGroup
from nova.core.controller import Controller
from nova.types.pose import Pose
from nova.types.action import Action, lin, ptp, jnt, cir
from nova import types
from nova import actions
from nova.core.movement_controller import speed_up as speed_up_movement_controller

# Provide autogenerated NOVA API client
import wandelbots_api_client as api

__all__ = [
"Nova",
"Cell",
"MotionGroup",
"Controller",
"lin",
"ptp",
"jnt",
"cir",
"Action",
"Pose",
"speed_up_movement_controller",
"api",
"types",
"actions",
]
39 changes: 38 additions & 1 deletion nova/types/action.py → nova/actions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pydantic
from typing import Annotated, Literal, Any, Union
from typing import Annotated, Literal, Any, Union, AsyncGenerator, Callable
from nova.types.pose import Pose
from nova.types.collision_scene import CollisionScene
import wandelbots_api_client as wb
from abc import ABC, abstractmethod

Expand Down Expand Up @@ -101,6 +102,29 @@ def is_cartesian(self):
return isinstance(self.target, Pose)


class UnresolvedMotion(Motion, ABC):
@abstractmethod
async def resolve(
self,
initial_joints: tuple[float, ...],
collision_scene: CollisionScene | None,
configuration: dict,
moving_robot_identifier: str,
) -> tuple[list[Motion], tuple[float, ...]] | None:
"""Convert the motion to a list of motion primitives
Args:
initial_joints: Joint positions at start of motion
collision_scene: The collision scene used to check collisions
configuration: E.g. data of physical setup of robot system, cell, etc.
moving_robot_identifier: The identifier of the robot that is moving in the scene
Returns:
Tuple of resolved motions and the joint position at the end of the motions. None, if the motion can't be resolved
"""


class Linear(Motion):
"""A linear motion
Expand Down Expand Up @@ -462,3 +486,16 @@ def to_set_io(self) -> list[wb.models.SetIO]:
)
for action in self.actions
]


class MovementControllerContext(pydantic.BaseModel):
combined_actions: CombinedActions
motion_id: str


ExecuteTrajectoryRequestStream = AsyncGenerator[wb.models.ExecuteTrajectoryRequest, None]
ExecuteTrajectoryResponseStream = AsyncGenerator[wb.models.ExecuteTrajectoryResponse, None]
MovementControllerFunction = Callable[
[ExecuteTrajectoryResponseStream], ExecuteTrajectoryRequestStream
]
MovementController = Callable[[MovementControllerContext], MovementControllerFunction]
11 changes: 3 additions & 8 deletions nova/core/motion_group.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
from nova.core.exceptions import PlanTrajectoryFailed, LoadPlanFailed
from nova.gateway import ApiGateway
from nova.types.action import Action, CombinedActions
from nova.actions import Action, CombinedActions, MovementController, MovementControllerContext
from nova.types.pose import Pose
from nova.types import (
MovementController,
LoadPlanResponse,
InitialMovementStream,
InitialMovementConsumer,
)
from nova.types import LoadPlanResponse, InitialMovementStream, InitialMovementConsumer
from loguru import logger
import wandelbots_api_client as wb

from nova.core.movement_controller import move_forward, MovementControllerContext
from nova.core.movement_controller import move_forward

MAX_JOINT_VELOCITY_PREPARE_MOVE = 0.2
START_LOCATION_OF_MOTION = 0.0
Expand Down
4 changes: 2 additions & 2 deletions nova/core/movement_controller.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from nova.core.exceptions import InitMovementFailed
from nova.types.movement_controller_context import MovementControllerContext
from nova.types import (
from nova.actions import (
MovementControllerFunction,
ExecuteTrajectoryResponseStream,
ExecuteTrajectoryRequestStream,
MovementControllerContext,
)
import wandelbots_api_client as wb
from loguru import logger
Expand Down
24 changes: 2 additions & 22 deletions nova/types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,22 @@
from wandelbots_api_client.models import * # noqa: F401, F403
from nova.types.pose import Pose
from nova.types.vector3d import Vector3d
from nova.types.action import Action, Motion, MotionSettings, lin, spl, ptp, cir, jnt
from nova.types.collision_scene import CollisionScene


# This is the stream of requests that is send to execute trajectory websocket
from typing import AsyncGenerator, Callable
import wandelbots_api_client as wb

from nova.types.movement_controller_context import MovementControllerContext

ExecuteTrajectoryRequestStream = AsyncGenerator[wb.models.ExecuteTrajectoryRequest, None]
ExecuteTrajectoryResponseStream = AsyncGenerator[wb.models.ExecuteTrajectoryResponse, None]
MovementControllerFunction = Callable[
[ExecuteTrajectoryResponseStream], ExecuteTrajectoryRequestStream
]
LoadPlanResponse = wb.models.PlanSuccessfulResponse
InitialMovementStream = AsyncGenerator[wb.models.StreamMoveResponse, None]
InitialMovementConsumer = Callable[[wb.models.StreamMoveResponse], None]
MovementController = Callable[[MovementControllerContext], MovementControllerFunction]


__all__ = [
"Vector3d",
"Pose",
"Motion",
"MotionSettings",
"lin",
"spl",
"ptp",
"cir",
"jnt",
"Action",
"ExecuteTrajectoryRequestStream",
"ExecuteTrajectoryResponseStream",
"MovementControllerFunction",
"CollisionScene",
"LoadPlanResponse",
"InitialMovementStream",
"InitialMovementConsumer",
"MovementController",
]
27 changes: 0 additions & 27 deletions nova/types/collision_scene.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from abc import ABC, abstractmethod
from typing import Literal

import pydantic
import wandelbots_api_client as wb
from nova.types.pose import Pose
from nova.types.action import Motion


class DhParameter(pydantic.BaseModel):
Expand Down Expand Up @@ -130,30 +128,6 @@ def add_static_collider(self, identifier: str, collider: Collider):
add_static_collider(scene, "box", Box(size_x=1, size_y=1, size_z=1), Pose.from_tuple([0, 0, 0, 0, 0, 0]))
"""


class UnresolvedMotion(Motion, ABC):
@abstractmethod
async def resolve(
self,
initial_joints: tuple[float, ...],
collision_scene: CollisionScene | None,
configuration: dict,
moving_robot_identifier: str,
) -> tuple[list[Motion], tuple[float, ...]] | None:
"""Convert the motion to a list of motion primitives
Args:
initial_joints: Joint positions at start of motion
collision_scene: The collision scene used to check collisions
configuration: E.g. data of physical setup of robot system, cell, etc.
moving_robot_identifier: The identifier of the robot that is moving in the scene
Returns:
Tuple of resolved motions and the joint position at the end of the motions. None, if the motion can't be resolved
"""


__all__ = [
"Box",
"Capsule",
Expand All @@ -167,5 +141,4 @@ async def resolve(
"Rectangle",
"RectangularCapsule",
"Sphere",
"UnresolvedMotion",
]
8 changes: 0 additions & 8 deletions nova/types/movement_controller_context.py

This file was deleted.

Loading

0 comments on commit 4ff9562

Please sign in to comment.