Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: Changelog check
uses: Zomzog/changelog-checker@v1.1.0
uses: Zomzog/changelog-checker@v1.3.0
with:
fileName: CHANGELOG.md
checkNotification: Simple
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Requires `compas_robots >= 1.1`.

### Added

* Made `Waypoints` (`FrameWaypoints` and `PointAxisWaypoints`) behave like a list.
* The `Tool From Mesh` Grasshopper component gained a `base_plane` input: where the robot's flange takes hold of the geometry, expressed in the coordinates the mesh was modelled in. Its Z axis points away from the robot, so a tool drawn reaching along world Z needs none, and a tool drawn along another axis is mounted by wiring a plane instead of redrawing the geometry. Backed by the new `base_frame` argument of `compas_robots.ToolModel`; nothing is baked into the mesh, so the plane can be re-wired at any time. The component also surfaces a remark when the TCP does not sit roughly on the tool's +Z, since that means the tool will point sideways once attached — the direction from the mount to the TCP is only a hint (it says nothing about roll), so it is reported rather than applied.

### Changed
Expand Down
33 changes: 33 additions & 0 deletions src/compas_fab/robots/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,39 @@ class Waypoints(Target):
def __init__(self, target_mode: TargetMode = None, native_scale: float = 1.0, name: str = "Generic Waypoints"):
super(Waypoints, self).__init__(target_mode=target_mode, native_scale=native_scale, name=name)

@property
def waypoints(self):
if hasattr(self, "target_frames"):
return self.target_frames
elif hasattr(self, "target_points_and_axes"):
return self.target_points_and_axes
else:
raise NotImplementedError

def __len__(self):
return len(self.waypoints)

def __getitem__(self, item):
return self.waypoints[item]

def __setitem__(self, key, value):
self.waypoints[key] = value

def __delitem__(self, key):
del self.waypoints[key]

def __iter__(self):
return iter(self.waypoints)

def append(self, item):
self.waypoints.append(item)

def extend(self, items):
self.waypoints.extend(items)

def insert(self, i, item):
self.waypoints.insert(i, item)


class FrameWaypoints(Waypoints):
"""Represents a sequence of fully constrained pose target for the robot's end-effector using a [`Frame`][compas.geometry.Frame].
Expand Down
21 changes: 21 additions & 0 deletions tests/robots/test_waypoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest
from compas.geometry import Frame, Point, Vector
from compas_fab.robots import FrameWaypoints, PointAxisWaypoints, TargetMode

def test_frame_waypoints_list_behavior():
fw = FrameWaypoints([Frame.worldXY()], TargetMode.ROBOT)
assert len(fw) == 1
fw.append(Frame.worldZX())
assert len(fw) == 2

# Test iteration
frames = [f for f in fw]
assert len(frames) == 2
assert frames[0] == Frame.worldXY()
assert frames[1] == Frame.worldZX()

def test_point_axis_waypoints_list_behavior():
pw = PointAxisWaypoints([(Point(0,0,0), Vector(1,0,0))], TargetMode.ROBOT)
assert len(pw) == 1
pw.append((Point(1,1,1), Vector(0,1,0)))
assert len(pw) == 2
Loading