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: 0 additions & 2 deletions _data/toc/v15.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ contents:
url: interpolation
- title: Track Movement
url: track-movement
- title: OpenFarm
url: openfarm
- title: Security Vulnerabilities
url: responsible-disclosure-of-security-vulnerabilities
- title: GitHub
Expand Down
5 changes: 0 additions & 5 deletions _redirects/openfarm.md

This file was deleted.

88 changes: 54 additions & 34 deletions v15/docs/farmbot-os/sidecar-hardware.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,31 @@ slug: "sidecar-hardware"
description: "Add additional specialized hardware to your FarmBot"
---

Although FarmBot OS supports plug-and-play USB webcams, it is not possible to install additional camera drivers on FarmBot OS. FarmBot OS only supports plug-and-play cameras, and it's very important to point out that although FarmBot OS is a Linux-powered Raspberry Pi, it is not intended to be used in the same manner as a Desktop machine where end users are free to add and remove the software components running on the machine. This means that FarmBot OS is not capable of directly running specialized cameras intended for scientific or specialized use (most consumer-grade USB webcams are fine, though). FarmBot OS has a read-only filesystem and does not use the same Raspberry Pi Linux distribution that desktop Linux users are used to.
While FarmBot OS supports plug-and-play USB webcams, it is not possible to install additional camera drivers or other software onto FarmBot OS that may be required by specialized cameras.

In situations where you need to install special drivers or Python modules, we recommend adding a "sidecar" hardware module to the FarmBot. The sidecar computer would be a second Raspberry Pi (or similar) that is completely under your control and which does not run FarmBot OS. You would install Raspberry Pi OS on the sidecar and follow the directions provided by most tutorials found online.
{%
include callout.html
type="info"
content="While FarmBot OS is a Linux-powered Raspberry Pi, it is not intended to be used in the same manner as a desktop computer where end users are free to add and remove the software components. FarmBot OS has a read-only filesystem and does not use the same Raspberry Pi Linux distribution that desktop Linux users are used to."
%}

In situations where you need to install special drivers or Python modules, we recommend using **sidecar hardware**. Sidecar hardware is a second computer, typically a Raspberry Pi (or similar), that is completely under your control and which does not run FarmBot OS. You would install [Raspberry Pi OS](https://www.raspberrypi.com/software/operating-systems/) on the sidecar and follow the directions provided by tutorials found online to run your custom software and hardware. A sidecar may also be another Arduino, a cloud-based server, or even your laptop.

Once the sidecar is configured, there are a number of ways you can support interaction between the FarmBot's CPU and the sidecar:

* **[Library control](#library-control)**: If the device has a reasonably reliable internet connection, you can have the sidecar talk to FBOS via [Python](../../python/intro.md) or [FarmBotJS](../farmbot-js.md). This is the easiest option.
* **[Python library control](#python-library-control)**: If the device has a reasonably reliable internet connection, you can have the sidecar talk to FBOS via [Python](../../python/intro.md) or [FarmBotJS](../farmbot-js.md). This is the easiest option.
* **[Lua UART](#lua-uart)**: You can run a serial line from the FarmBot to the sidecar and use the Lua [UART helpers](../../lua/functions/uart.md) to send messages between the devices.
* **[GPIO pin binding](#gpio-pin-binding)**: The sidecar can trigger a "pin binding" which activates a sequence on FBOS whenever the sidecar pulls a GPIO line high.
* **[GPIO pin binding](#gpio-pin-binding)**: The sidecar can trigger a [pin binding](https://software.farm.bot/docs/pin-bindings) which activates a sequence on FBOS whenever the sidecar pulls a GPIO line high.
* **[Lua HTTP](#lua-http)**: You could create an HTTP server that resides on the sidecar module and [make HTTP calls from Lua code in a sequence](../../lua/functions/api.md#httpparams).

The sidecar module could then upload the photos to the FarmBot API, or you could store them on a completely different server that has higher storage limits than what the Web App provides. You could also perform image manipulation tasks directly on the sidecar.

Other methods may be possible.

# Examples
In the case of using a 3rd party camera system, the sidecar could be triggered to take a photo by the FarmBot, and then the sidecar could upload the photos to the FarmBot API, or you could store them on a completely different server that has higher storage limits than what the Web App provides. You could also perform image manipulation tasks directly on the sidecar.

`random()` is used here as a placeholder for the custom code you may run on your sidecar hardware.
# Python library control

## Library control
In this example your Python code could be run from another Raspberry Pi, a laptop, or even a cloud-based server and it will communicate with the FarmBot over the Internet.

### Python
_On sidecar hardware (Python):_

_on sidecar hardware (Python):_
```python
from farmbot import Farmbot
from random import randint
Expand All @@ -43,52 +44,66 @@ fb.wait(seconds * 1000) # Wait for a random number of seconds
fb.off(7) # Turn OFF pin 7 (LED strip)
```

_on FarmBot:_
_On FarmBot:_

The lighting peripheral is controlled.

See the [FarmBotPy library docs](../../python/intro.md) for additional usage instructions.
{%
include callout.html
type="info"
content="See the [FarmBotPy library docs](../../python/intro.md) for additional usage instructions."
%}

# Lua UART

In this example you would connect an Arduino or other UART device to a spare USB port on the FarmBot's Raspberry Pi. Make sure to use [uart.list()](../../lua/functions/uart.md#uartlist) first to check which device is your sidecar.

## Lua UART
_On sidecar hardware (Arduino):_

_on sidecar hardware (Arduino):_
```c
void setup() {
Serial.begin(115200);
}

void loop() {
int randNum = random(1, 11);
Serial.println(randNum);
Serial.println("Hello from the sidecar!");
delay(1000);
}
```

_on FarmBot (Lua sequence step):_
_On FarmBot (Lua sequence step):_

```lua
my_uart, error = uart.open("ttyUSB0", 115200)

if error then
toast(inspect(error), "error")
toast(error, "error")
return
end

if my_uart then
string, error2 = my_uart.read(15000)
if error2 then
toast(inspect(error2), "error")
toast(error2, "error")
else
toast(inspect(string))
toast(string)
end
my_uart.close()
end
```

See the [Lua UART docs](../../lua/functions/uart.md) for additional usage instructions.
{%
include callout.html
type="info"
content="See the [Lua UART docs](../../lua/functions/uart.md) for additional usage instructions."
%}

# GPIO pin binding

## GPIO pin binding
In this example, you must connect a physical wire between an output pin on your sidecar and one of FarmBot's GPIO pins. You must then configure a [pin binding](https://software.farm.bot/docs/pin-bindings) to execute a sequence or action when triggered.

_On sidecar hardware (Arduino):_

_on sidecar hardware (Arduino):_
```c
int i = 0;
int randNum;
Expand All @@ -110,15 +125,16 @@ void loop() {
}
```

_on FarmBot:_
_On FarmBot:_

The pin binding for the pin connected to the sidecar hardware is triggered and the assigned sequence or action is executed.

The pin binding for the pin connected to the sidecar hardware is triggered.
# Lua HTTP

See the [Pin Binding docs](https://software.farm.bot/docs/pin-bindings) for additional usage instructions.
In this example your Python code could be run from another Raspberry Pi or your laptop on the same network as the FarmBot.

## Lua HTTP
_On sidecar hardware (Python):_

_on sidecar hardware (Python):_
```python
from flask import Flask
import cv2
Expand All @@ -139,15 +155,15 @@ def capture_and_return_value():

# process image and return result
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
value = int(np.mean(gray) + random())
value = int(np.mean(gray))
return str(value)


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
```

_on FarmBot (Lua sequence step):_
_On FarmBot (Lua sequence step):_

Where `192.168.0.100` is the local network IP address of the sidecar hardware.

Expand All @@ -159,4 +175,8 @@ local value = tonumber(response.body)
toast("processing complete. result: " .. value)
```

See the [Lua HTTP docs](../../lua/functions/api.md) for additional usage instructions.
{%
include callout.html
type="info"
content="See the [Lua HTTP docs](../../lua/functions/api.md) for additional usage instructions."
%}
115 changes: 90 additions & 25 deletions v15/lua/functions/coordinates.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: "List of coordinate Lua functions in FarmBot OS"

```lua
coordinate(1.0, 20, 30)
-- Returns {x = 1.0, y = 20, z = 30}
-- Returns {x = 1.0, y = 20, z = 30}
```

# check_position(coordinate, tolerance)
Expand Down Expand Up @@ -45,6 +45,91 @@ toast("Width: " .. size.y .. "mm")
toast("Height: " .. size.z .. "mm")
```

# get_generic_points({filters})

Returns a table of **generic points**, filtered by the optional parameters. Available filters include: `min_radius`, `max_radius`, `min_age`, `max_age`, `color`, and `at_soil_level`.

```lua
points = get_generic_points()
toast("Total number of generic points: " .. #points)

points = get_generic_points({at_soil_level="true"})
toast("Points at soil level: " .. #points)

points = get_generic_points({color="blue", min_radius=10})
toast("Blue points with minimum radius of 10: " .. #points)

points = get_generic_points({max_age=2})
toast("Points younger than 2 days: " .. #points)
```

# get_plants({filters})

Returns a table of **planted plants**, filtered by the optional parameters. Available filters include: `min_radius`, `max_radius`, `min_age`, `max_age`, `plant_stage`, and `openfarm_slug`.

{%
include callout.html
type="info"
content='By default, a `plant_stage="planted"` filter is applied.'
%}

```lua
plants = get_plants()
toast("Total number of planted plants: " .. #plants)

plants = get_plants({plant_stage="sprouted"})
toast("Sprouted plants: " .. #plants)

plants = get_plants({min_radius=10, max_age=5})
toast("Planted plants with minimum radius of 10 and maximum age of 5: " .. #plants)

plants = get_plants({openfarm_slug="broccoli"})
toast("Planted Broccoli plants: " .. #plants)
```

# get_weeds({filters})

Returns a table of **active weeds**, filtered by the optional parameters. Available filters include: `min_radius`, `max_radius`, `min_age`, `max_age`, `plant_stage`, and `color`.

{%
include callout.html
type="info"
content='By default, a `plant_stage="active"` filter is applied.'
%}

```lua
weeds = get_weeds()
toast("Total number of active weeds: " .. #weeds)

weeds = get_weeds({plant_stage="pending"})
toast("Pending weeds: " .. #weeds)

weeds = get_weeds({min_radius=10, max_age=5})
toast("Active weeds with minimum radius of 10 and maximum age of 5: " .. #weeds)
```

# get_group(id|name)

Returns a table of **current group members**, sorted by the group's **SORT BY** method. You may get a group by name or id.

```lua
group_members = get_group("All plants")
for _, plant in pairs(group_members) do
move{x=plant.x, y=plant.y, z=0}
end
```

```lua
group_members = get_group(1234)
toast(#group_members)
```

{%
include callout.html
type="info"
content="Find a group's ID by navigating to the group in the web app and copying the number at the end of the URL."
%}

# get_seed_tray_cell(tray, cell)

Calculates the **coordinates of a seed tray cell**, such as `B3`, based on the cell label and the coordinates of the center of the seed tray. See the [Pick from Seed Tray featured sequence](https://my.farm.bot/app/shared/sequence/32) for an example.
Expand Down Expand Up @@ -121,27 +206,6 @@ title="Each iteration runs in its own execution context"
content="Variables declared outside the `grid.each` iterator function will not be accessible within the function. Furthermore, variables within the iterator function will not persist across iterations or be available outside the function scope. To store and retrieve persistent variables that can be accessed both inside and outside the iterator function, use [env()](../functions/configuration.md#envkey-value--envkey)."
%}

# group(id)

Returns a table of **current group member IDs**, sorted by the group's **SORT BY** method.

```lua
group_members = group(1234)
for i,member in ipairs(group_members) do
plant = api({
method = "get",
url = "/api/points/" .. member
})
move_absolute(plant.x, plant.y, 0)
end
```

{%
include callout.html
type="info"
content="Find a group's ID by navigating to the group in the web app and copying the number at the end of the URL."
%}

# safe_z()

Returns the value of the **[SAFE HEIGHT](https://my.farm.bot/app/designer/settings?highlight=safe_height)** setting.
Expand Down Expand Up @@ -180,12 +244,13 @@ content="This function requires at least 3 soil height measurements. When there

# sort(points, method)

**Sorts** the given table of points using the chosen **sorting method**.
**Sorts** the given table of point objects using the chosen **sorting method**.

```lua
points = group(1234)
points = get_group(1234)
sorted_points = sort(points, "xy_alternating")
toast("Second point ID is: " .. sorted_points[2])
poi = sorted_points[2]
toast("Second point is at (" .. poi.x .. ", " .. poi.y .. ")")
```

The following sorting methods are available. See [point group sorting](../../other/how-it-works/point-group-sorting.md) for additional details.
Expand Down
18 changes: 0 additions & 18 deletions v15/lua/functions/jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ wait(2000)
complete_job(job_name)
```

# set_job_progress()

{%
include callout.html
type="warning"
title="Deprecated"
content="This is a low-level function that has been superseded by [set_job()](#set_jobname-params)."
%}

# get_job(name)

**Gets a job** by name.
Expand All @@ -69,15 +60,6 @@ toast("Job progress: " .. job.percent .. "%")
complete_job(job_name)
```

# get_job_progress()

{%
include callout.html
type="warning"
title="Deprecated"
content="This is a low-level function that has been superseded by [get_job()](#get_jobname)."
%}

# complete_job(name)

**Completes a job** by name, where complete means a `percent` of `100` and a `status` of `Complete`.
Expand Down
9 changes: 0 additions & 9 deletions v15/other/openfarm.md

This file was deleted.

Loading