Skip to content
Merged
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
2 changes: 1 addition & 1 deletion docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ parts:
- caption: Add to Graph 🕶️
chapters:
- file: buildgraph
- caption: Graph Solvers
- caption: Solving Graphs
chapters:
- file: solvers
- caption: Tutorials
Expand Down
22 changes: 10 additions & 12 deletions docs/blobs.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Data `BlobEntry=>Blob`

Many `BlobEntry`s from various location can all reference the same large and heavy binary data `Blob`. Furthermore, this system allows a distributed usage over a large networked system.
Many `BlobEntry`s from various nodes in the graph can reference the `Blob`. A blob is simply just binary data that is uniquely identified through a uuid. This approach allows for distributed usage over a large networked system including limited connectivity situations.

:::{tip}
`Blob`s are separate from `BlobEntry`s. Various nodes on the graph can have any number of `BlobEntry`s (including duplicates), but the user does not necessary have the need to pull the bandwidth heavy blobs across all parts of the system network.
`BlobEntry`s and `Blob`s are separate separate by related objects. Various nodes on the graph can have any number of `BlobEntry`s (except for duplicate `blobentry.labels`). A user more likely to work the `BlobEntry`s, and only pull bandwidth heavy binary `Blob`s to differemt parts of the system network when needed. Similarly, these data blobs can be readily cached across the network, since blobs are immutable.
:::

## What is a `BlobEntry`
## What is a `BlobEntry`

Additional (large) data attached to variables exist in a few different ways. The primary method for storing additional large data as a `Blob`, however, a blob just "barcoded" binary blob. we use `BlobEntry`s to organize, find, share, distribute, make available and useful across the divergent network how a `Blob` is associated with the graph.

A blob entry is small about of structed data that holds reference information to find an actual binary blob which is possibly a massive amount of data.
A blob entry is a small amount of structed data that holds reference information to find an actual binary blob which is possibly a massive amount of data. `BlobEntry`s are plentiful, lightweight, and allow users to more easily organize, find, share, distribute, the contextual information about a data blob over a divergent network how a `Blob` is associated with the graph. The primary method for storing additional large data as a `Blob`, however, a blob just "barcoded" binary blob of data with little context or meaning.

### Listing BlobEntries on a Node

Expand Down Expand Up @@ -46,7 +44,7 @@ The entry object is well structured

A binary `Blob` is basically just a "barcoded" piece of data that can be associated (via individual `BlobEntry`s) multiple times across multiple graph nodes, sessions, or robots.

Data blobs can be fetched via, e.g. using the unique `.blobId` as primary (or `.originId` as secondary) reference. Also note that the blob itself may also be replicated across any number of blob stores, depending on the application:
Data blobs can be fetched using the unique `.blobId` as primary (or `.originId` as secondary) reference. Also note that the blob itself may also be replicated across any number of blob stores, depending on the application:
```python
blob = getBlob(fgclient, entry.blobId]; checkhash=false) # legacy versions did not use .hash check
# blob = await getBlobAsync(fgclient, entry.blobId]; checkhash=false)
Expand All @@ -57,10 +55,6 @@ The blob contains binary information, for example this `mimeType = application/o
b'{"latitude":41.7325,"altitude":2.211,"header":{"stamp":{"secs":1670378554,"nsecs":000624417},"seq":91,"frame_id":"gps","_type":"ROS1/std_msgs/Header"},"status":{"status":0,"service":1},"position_covariance":[0.265225,0.0,0.0,0.0,0.265225,0.0,0.0,0.0,0.556516],"longitude":-49.946944,"_type":"ROS1/sensor_msgs/NavSatFix","position_covariance_type":2}'
```

:::{tip}
Depending on the blob store, it may also be possible to retrieve a blob using the `.originId` rather than `.blobId`.
:::

:::{tip}
A blob is owned by a `user` and only accessible by other users if allowed via approved roles or permissions.
:::
Expand All @@ -72,7 +66,7 @@ A blob is owned by a `user` and only accessible by other users if allowed via ap
## Adding BlobEntries

:::{warning}
Adding `Blob` or `BlobEntry`s from the Python SDK are under construction and expected to be part of the v0.6.1 release. This functionality has already been released with the JuliaLang SDK.
Adding `Blob` or `BlobEntry`s from the Python SDK are under construction and [expected to be part of the v0.6.1 release](https://github.com/NavAbility/NavAbilitySDK.py/milestone/6). This functionality has already been released with the JuliaLang SDK.
:::

Blobs can be linked to any variable (future node) in the graph. This is easily done by adding a BlobEntry:
Expand All @@ -83,6 +77,10 @@ res = addBlobEntry(fgclient, 'x12', entries[1].id, entries[1].label, len(blob),

## Adding New Blobs

:::{warning}
Adding `Blob` or `BlobEntry`s from the Python SDK are under construction and [expected to be part of the v0.6.1 release](https://github.com/NavAbility/NavAbilitySDK.py/milestone/6). This functionality has already been released with the JuliaLang SDK.
:::

It is also possible to push data blobs:
```python
client = NavAbilityHttpsClient()
Expand Down
78 changes: 42 additions & 36 deletions docs/buildgraph.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,67 @@ The NavAbilitySDK provides variables and factors useful to robotics. We start w

As before, let's setup a new client-context to talk with the NavAbility platform:
```python
from navability.entities import DFGClient, VariableType, PriorPose2, FullNormal
from navability.services import addVariable, ls, addFactor, lsf
import uuid, random, string

userLabel = "guest@navability.io"
robotLabel = "TestRobot"
sessionLabel = "TestPy"

# also create a client connection
client = NavAbilityHttpsClient()

# create a client context user, robot, session
context = Client(
"guest@navability.io",
"ExampleRobot",
"SDKpy_"*(string(uuid4())[1:4]),
)
fgclient = DFGClient(userLabel, robotLabel, sessionLabel)
```

## First Pose
## Adding Variables

:::{warning}
SDK.py@v0.6.0 currently does not support creating new sessions from "guest", but variables and factors can be added to an existing session.
:::

The `addVariable` function with a label `"x0"` and type `:Pose2` adds that variable to to the factor graph.
Let's start with `addVariable`
```{eval-rst}
.. autofunction:: navability.services.addVariable
```

by adding a randomly named variable an existing graph. Here we call `addVariable` as type `VariableTypes.Pose2`. Pose2 here refers to position an orientation on a flat 2D plane -- i.e. the variable represents the estimation problem to find the state of variable with freedoms `[x,y,theta]`:
```python
result_v0 = await addVariable(client, context, "x0", VariableType.Pose2)
# generate a random variable label
vlabel = 'x_'+''.join(random.choices(string.ascii_letters + string.digits, k=4))

# add the variable to the existing session under guest
v = addVariable(fgclient, vlabel, VariableType.Pose2)
# result_v0 = await addVariable(fgclient, "x0", VariableType.Pose2)
```

Note that asynchronous tasks are used to increase the upload performance. Each of these events are queued on the server for processing. While the variable is being created, let's also add a prior factor.
:::{tip}
Note that asynchronous tasks could increase client side upload performance. Each of these events are queued on the server for processing. While the variable is being created.
:::

## Adding Factors

Next, we can also add a factor. Have a look at the `addFactor` function followed by how a user defines the factor measurement and observation model in the next section.

```{eval-rst}
.. autofunction:: navability.services.addVariable
.. autofunction:: navability.services.addFactor
```

### And Zero-Prior
### A Zero-Prior

We now have a factor graph with one variable, but to solve it we need some additional information. In this example, we need the estimated starting point of our robot.
Let's first add a Prior. Priors are absolute information about variables.
:::{tip}
NavAbility factor graph solutions at this time require a gauge to exist for the graph being solved, hence enough prior information must be included in the graph to constrain the solution (bundles/orbits/locii) to a single solution. **Note** that this does not imply solutions are necessarily unimodal (Gaussian).
:::

In this example, we'll use the estimated starting point of our robot.
We use unary factors called priors to represent absolute information to be introduced. In this case we use `PriorPose2`, as our variable type is also `Pose2`.
Since factors represent a probabilistic interaction between variables, we need to specify the distribution our factor will represent. Here we use `FullNormal` which is a [multivariate normal distribution](https://en.wikipedia.org/wiki/Multivariate_normal_distribution).

Let's create a `PriorPose2` unary factor with zero mean and a covariance matrix of (`diagm([0.05,0.05,0.01].^2)`):
```python
prior_distribution = FullNormal(mu=np.zeros(3), cov=np.power(np.diag([0.1, 0.1, 0.1]),2))
result_f0 = await addFactor(client, context, ["x0"], PriorPose2(Z=prior_distribution))
```

After adding a batch of variables and factors, we can wait on the upload status to ensure the new graph elements have been processed:
```python
# Wait for variable and factor to be loaded to be loaded.
await waitForCompletion(client, [result_v0, result_f0])
```

As before, we can use the NavAbility App to visualize the factor graph
```python
# Click on the generated URL or graphic to open the NavAbility App Graph visualization page for this session
GraphVizApp(context, variableStartsWith="")
```

<!-- ```{eval-rst}
.. automodule:: navability.services
:members: addVariable
``` -->
```{eval-rst}
.. autofunction:: navability.services.addFactor
result_f0 = addFactor(fgclient, ["x0"], PriorPose2(Z=prior_distribution))
result_f0 = await addFactorAsync(fgclient, ["x0"], PriorPose2(Z=prior_distribution))
```

## Odometry Factor
Expand Down
39 changes: 21 additions & 18 deletions docs/factors.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,35 @@ Factors represent the interaction between particular variables. Factors define t

All factors in a graph can be listed via:
```python
flbls = await listFactors(client, context)
flbls = listFactors(fgclient)
# flbls = await listFactorsAsync(fgclient)
# ["x0f_8ebc", ...]
```

Note the factor labels are autogenerated based on the variables and a random sequence. For example a prior factor might have the label `x0f_8ebc`, while factor between three variables might be `x7x49l4f_654t`.
```{eval-rst}
.. autofunction:: navability.services.listFactors

**Note** the factor labels are autogenerated based on the variables and a random sequence. For example a prior factor might have the label `x0f_8ebc`, while factor between three variables might be `x7x49l4f_654t`.

A specific factor can be retrieved using the label:
```python
f = await getFactor(client, context, 'x0f_8ebc')
# Dict{String, Any} with 8 entries:
# "label" => "x0f_8ebc"
# "_variableOrderSymbols" => Any["x0"]
# "data" => "eyJlbGltaW5hdGVkIjpmYWxzZSwicG90ZW50aWFsdXNlZCI6Z…
# "tags" => Any["FACTOR"]
# "timestamp" => "2023-02-11T22:36:49.171Z"
# "_version" => "0.18.6"
# "fnctype" => "PriorPose2"
# "solvable" => 1
f = getFactor(fgclient, 'x7942x7943f_c2c6')
# f = await getFactorAsync(fgclient, 'x7942x7943f_c2c6')

# <Factor(label=x7942x7943f_c2c6,variables=['x7942', 'x7943'])>
```

<!-- ```@docs
listFactors
getFactor
``` -->
```{eval-rst}
.. autofunction:: navability.services.getFactor
```

The `Factor` object consists of the following

```{eval-rst}
.. autoclass:: navability.entities.Factor
```

## App Graph Visualization
<!-- ## App Graph Visualization

The NavAbilityApp can also visualize a specific factor graph session, and a convenient link generator can be used to simplify the session filtering criteria:
```python
Expand All @@ -53,7 +56,7 @@ The NavAbilityApp Graph visualization page can also be found in the hamburger me

<!-- ```@docs
GraphVizApp
``` -->
``` --> -->

## SDK Supported Factors

Expand Down
4 changes: 2 additions & 2 deletions docs/nvatutorials.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# NavAbility Tutorials

These Tutorials can be read as static pages or be run live via Binder. Either of the options below should work.
## Run Via NavAbility App
<!-- ## Run Via NavAbility App

A free tier access to NavAbility servers is provided through the user `guest@navability.io`. To learn more about using the guest user, consider trying the [NavAbility Tutorials](https://app.navability.io/get-started/tutorials).

<a href="https://app.navability.io/get-started/tutorials"><p align="center">
<img src="https://user-images.githubusercontent.com/6412556/218645925-4fa31c70-8c93-49d8-a43d-f18ffde5e28f.png" width="480px" border="0" />
</p></a>

Including SDK.jl version of Tutorial 5 not yet available in JupyterBook links below.
Including SDK.jl version of Tutorial 5 not yet available in JupyterBook links below. -->

## Run Via Jupyter Book

Expand Down
2 changes: 1 addition & 1 deletion docs/solvers.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Non parametric solving can support a much wider range of measurement probability
- as well as multihypothesis features per factor -- i.e. `Categorical`.

Many more probability types are natively supported by the solver and yet directly exposed through the SDK, including
- Manifold Kernel Densities,
- `ManifoldKernelDensities`,
- Heatmaps or Intensity maps,
- Levelsets,
- Most common parametric probability models.
Expand Down
4 changes: 4 additions & 0 deletions docs/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ Returns `["l1","x0","x1","x2","x3","x4","x5","x6"]`. The `await ... Async` vers
.. autofunction:: navability.services.listVariablesAsync
```

:::{tip}
There is a handy alias familiar to Linux, `ls = listVariables`, e.g. `ls(fgclient)` returns all the variables in the graph.
:::

### Getting a Variable

The main purpose of using a factor graph is not only as data index but also to deeply connect with the mapping and localization problem. Variables in the factor graph represent the states to be estimated from the relevant measurement data. The numerical values for each variable are computed by any number of solver operations. The numerical results are primarily stored in a variables `solverData` field, such that either parametric or non-parametric inference results can be used:
Expand Down