allwpilib
allwpilib copied to clipboard
Mechanism2dRoot enhancements
Drawing:
- Helpers for creating shapes
- Add ligaments that aren't directly connected to the root
- The root is convenient because you can shift the position of a bunch of objects, so it feels really more like a group of items.
- In particular, I'd like to move the object around by moving its 'center'... but currently I'd have to compute that, or draw it carefully.
API goodness:
- Mechanism to iterate children
- auto-create names for ligaments
- Set defaults for created children when not specified (color, lineweight)
- If one creates a large number of ligaments that aren't really doing anything, it would be convenient if I only had to keep the root around instead of creating a list of children. In particular, SetColor/SetLineWeight would be nice.
Interaction:
- It would be convenient if I could click on something and register that somehow. (Eg, I click a button and the sim responds by making a ball appear)
... basically reinvent tkinter's canvas API :shipit:
Mechanism2d is designed for visualization of robot mechanisms: eg single/2-jointed arms, elevators, etc. It’s not designed to be a generic drawing canvas (although clearly it can be abused to do that). Also, its NT representation has several keys per element, so trying to do large numbers of elements is inefficient on the NT side.
Instead of trying to turn Mechanism2d into a generic canvas, maybe propose a new Canvas Sendable element with an appropriate API and NT representation for that use case?
I think it would be better (but similar) to define a Canvas sendable, and build the mechanism2d on top of it. The key is it would be good to be able to draw what you're simulating.
... I was going to post a gif of something I'm working on to illustrate what I'm trying to accomplish, but apparently recording OpenGL on Linux is annoying and doesn't seem to work.
FWIW, these are the helpers I'm using at the moment:
@dataclasses.dataclass
class Shape:
root: wpilib.MechanismRoot2d
items: typing.List[wpilib.MechanismLigament2d]
def setPosition(self, x: float, y: float):
self.root.setPosition(x, y)
def setColor(self, c: wpilib.Color8Bit):
for item in self.items:
item.setColor(c)
class Mechanism(wpilib.Mechanism2d):
def __init__(self, width: float, height: float) -> None:
super().__init__(width, height)
def make_point(self, name: str, cx: float, cy: float, sz: int = 10) -> Shape:
root = self.getRoot(name, cx, cy)
return self._make(root, 0.50, 0, 1, sz)
def make_triangle(
self, name: str, cx: float, cy: float, side: float, line_width=6
) -> Shape:
x = cx + side / 2
y = cy - side / 2
root = self.getRoot(name, x, y)
return self._make(root, side, 120, 3, line_width)
def make_hex(
self, name: str, x: float, y: float, side: float, line_width=6
) -> Shape:
# x, y are near bottom right corner
root = self.getRoot(name, x, y)
return self._make(root, side, 60, 6, line_width)
def _make(
self,
root: wpilib.MechanismRoot2d,
side: float,
angle: float,
n: int,
line_width,
) -> Shape:
item = root
items = []
for i in range(n):
item = item.appendLigament(f"{i}", side, angle, line_width)
items.append(item)
return Shape(root, items)

Finally got around to making a video of it: https://youtu.be/MHMJc4h1hnw