> For the complete documentation index, see [llms.txt](https://marrow.skeletonarmyftc.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://marrow.skeletonarmyftc.com/automations/weaver.md).

# Weaver

package com.skeletonarmy.marrow\.weaver

## Overview

`Weaver` is a path generation tool that builds a smooth path from a start pose to specified targets while avoiding obstacles.

This allows:

* **Vision-Based Navigation:** Automatically intake game elements detected by your camera.
* **TeleOp Automation:** Instantly drive to preset positions on the field during TeleOp with a single button press, such as a parking zone.

<figure><img src="https://4096955457-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fgfjbmar2vXl8Hq4p5TUG%2Fuploads%2F1RrPxWL25eWyPZj9jyBn%2FWeaver.gif?alt=media&amp;token=d3e9afe1-5c4c-4388-ac1f-9da8ee2bcdec" alt="An example path generated by Weaver" width="563"><figcaption><p>An example path generated by Weaver</p></figcaption></figure>

***

## Usage

### Setup

Configure `Weaver` once at the start of the OpMode with `setConfig(PathConfig)`:

```java
Weaver.setConfig(new PathConfig()
        .intakeWidth(8.0)
        .robotWidth(16.0)
        .robotHeight(16.0));
```

Call `resetToDefaults()` to restore the stock configuration. `getConfig()` returns the current one.

#### PathConfig

<table data-search="false"><thead><tr><th>Option</th><th>Type</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>intakeWidth</code></td><td><code>double</code></td><td><code>0.0</code></td><td>Intake width. <code>0</code> stops on the target; a real width sweeps elements</td></tr><tr><td><code>robotWidth</code></td><td><code>double</code></td><td><code>18.0</code></td><td>Robot footprint along the forward axis</td></tr><tr><td><code>robotHeight</code></td><td><code>double</code></td><td><code>18.0</code></td><td>Robot footprint across the forward axis</td></tr><tr><td><code>clearance</code></td><td><code>double</code></td><td><code>4.0</code></td><td>Extra distance kept from obstacles</td></tr><tr><td><code>excludeBlockedTargets</code></td><td><code>boolean</code></td><td><code>true</code></td><td>Drop targets an obstacle makes unreachable</td></tr><tr><td><code>smoothing</code></td><td><code>boolean</code></td><td><code>true</code></td><td>Round corners for smoother motion</td></tr><tr><td><code>turnCostWeight</code></td><td><code>double</code></td><td><code>10.0</code></td><td>How strongly to avoid turns when ordering targets</td></tr><tr><td><code>bruteForceOrderLimit</code></td><td><code>int</code></td><td><code>8</code></td><td>Maximum number of targets ordered exactly</td></tr></tbody></table>

### Generating a Path

Build a path with `Weaver.builder()`, then call `build()` to get a `PathResult`:

```java
PathResult result = Weaver.builder()
        .start(new Point(72, 72, 0))
        .addTarget(new Point(100, 72))
        .build();
```

{% hint style="warning" %}
At minimum you must call `start(...)` **and** supply either targets or a destination, otherwise `build()` throws an `IllegalStateException`. If both are set, the targets are used.
{% endhint %}

{% hint style="info" %}
A `Point` is an `(x, y)` position that also accepts a heading in radians. You do not have to pass a heading; when it is omitted, the weaver picks it from the direction of travel.
{% endhint %}

### Targets

Add a target with `addTarget(...)`, or add multiple targets with `targets(...)`.

By default, `Weaver` reorders them to find the shortest route; use `ordered()` to keep your own order instead. You can also combine targets with [obstacles](#obstacles) to route around them.

```java
PathResult result = Weaver.builder()
        .start(new Point(72, 72, 0))
        .targets(
                new Point(96, 72),
                new Point(116, 67),
                new Point(116, 77)
        )
        .addObstacle(new CircleZone(new Point(96, 60), 6))
        .ordered()
        .build();
```

`targets(...)` and `addTargets(...)` also accept an `Iterable` plus a mapping function, which is handy when your targets come from another object (e.g. camera detections):

```java
PathResult result = Weaver.builder()
        .start(new Point(72, 72, 0))
        .targets(vision.getGameElements(), e -> new Point(e.getX(), e.getY()))
        .build();
```

#### Intake Width

The `intakeWidth` of the `PathConfig` controls how wide the robot's intake is. Targets that line up laterally can be collected in one pass.

Set `intakeWidth` to half your physical intake width (e.g., set to 8" for a 16" intake). Using the exact physical width creates zero margin for error, causing the robot to sometimes miss off-center targets.

Set `intakeWidth(0)` to stop with the robot center on each target individually.

```java
Weaver.setConfig(new PathConfig().intakeWidth(8.0));
```

#### Target Limit

By default, Weaver visits every target you give it. Use `maxTargets(n)` to visit only the best `n` targets:

```java
PathResult result = Weaver.builder()
        .start(new Point(72, 72, 0))
        .targets(
                new Point(96, 72),
                new Point(116, 67),
                new Point(116, 77),
                new Point(130, 60),
                new Point(140, 84),
                new Point(150, 72)
        )
        .maxTargets(4)
        .build();
```

This is handy when you need to intake a few game elements: if you need to intake 4 but your camera detects 6, give it all 6 and it visits the 4 that make the fastest path.

#### Blocked Targets

When `excludeBlockedTargets` is on (the default), if a target is unreachable because of an obstacle, it is skipped.

`PathResult.getUnvisitedTargets()` lists the targets that were not visited - either blocked by an obstacle or beyond the target limit. Use `getVisitedTargets()` for the ones that were.

### Obstacles

Add obstacles with `addObstacle(...)` or `obstacles(...)` and the path routes around them, whether you set targets or a final destination with `end(Point)`. Obstacles are any [`Zone`](/automations/zones.md), including [`CircleZone`](/automations/zones/circlezone.md), [`PolygonZone`](/automations/zones/polygonzone.md), and [`CompositeZone`](/automations/zones/compositezone.md).

```java
PathResult result = Weaver.builder()
        .start(new Point(10, 10, 0))
        .end(new Point(90, 10))
        .addObstacle(new CircleZone(new Point(50, 10), 8))
        .build();
```

***

## Results

`build()` returns a `PathResult` holding the route and additional execution metadata:

<table data-search="false"><thead><tr><th>Method</th><th>Description</th></tr></thead><tbody><tr><td><code>getPath()</code></td><td>The generated <code>PathRoute</code></td></tr><tr><td><code>getSegments()</code></td><td>The route's <code>PathCurve</code> segments</td></tr><tr><td><code>getControlPoints(int)</code></td><td>Control points of one segment</td></tr><tr><td><code>getSegmentEndHeadingsRad()</code></td><td>Heading to hold at each segment end, in radians</td></tr><tr><td><code>getSkippedTargets()</code></td><td>Number of targets dropped as unreachable</td></tr><tr><td><code>getVisitedTargets()</code></td><td>The chosen targets (in order)</td></tr><tr><td><code>getUnvisitedTargets</code></td><td>Targets that were blocked or over the limit</td></tr></tbody></table>

A `PathRoute` can be sampled, evaluated at a parameter, and measured:

```java
Point midpoint = result.getPath().getNormalized(0.5);
double length = result.getPath().approxLength(100);
List<Point> points = result.getPath().sample(50);
```

***

## Running the Path

### Pedro Pathing

If you are using Pedro Pathing, you can use the built-in `PedroPathingConverter` to turn the result into a Pedro Pathing v3 path. Pass it to a `Follower`:

```java
follower.follow(PedroPathingConverter.toPath(result));
```

If a start, target, or destination comes from a Pedro `Pose` (for example the&#x20;robot's current pose), you can convert it with `toPoint(Pose)` before handing it to the builder:

```java
Point current = PedroPathingConverter.toPoint(follower.getPose());
```

### Other Libraries

A generated path is library-agnostic. Get its control points with `getControlPoints(int)` or its segments with `getSegments()`, then feed them to whatever your follower uses:

```java
List<Point> controlPoints = result.getControlPoints(0);
List<PathCurve> segments = result.getSegments();
```

***

## Example Usage

This example uses Pedro Pathing to intake game elements detected by a vision subsystem.

```java
public class MyAuto extends OpMode {
    private Follower follower;
    private Vision vision;

    @Override
    public void init() {
        vision = new Vision(hardwareMap);

        follower = Constants.create(hardwareMap);
        follower.setPose(new Pose(72, 72, 0));

        Weaver.setConfig(new PathConfig()
                .intakeWidth(8.0)
                .robotWidth(16.0)
                .robotHeight(16.0));

        PathResult result = Weaver.builder()
                .start(new Point(72, 72, 0))
                .addObstacle(new CircleZone(new Point(90, 60), 6))
                .targets(vision.getGameElements(), e -> new Point(e.getX(), e.getY()))
                .maxTargets(4)
                .build();

        follower.follow(PedroPathingConverter.toPath(result));
    }

    @Override
    public void loop() {
        follower.update();
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://marrow.skeletonarmyftc.com/automations/weaver.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `build a script that syncs our docs to a CMS` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
