- Viam integrates with hardware and software on any device. Use AI, machine learning, and more to make any machine smarter—for one machine to thousands.
-
-
-## Program any device
-
-To get started, install Viam on any device and create a configuration that describes connected hardware as {{< glossary_tooltip term_id="component" text="components" >}}. Then you can control your device and any attached physical hardware securely **from anywhere in the world**. Or from local networks.
-
-{{< tabs class="horizontalheaders program" navheader="Examples">}}
-{{% tab name="Drive a base" %}}
-
-
-
-You can use any robotic base with Viam. Configure it as a base component. Then you can drive it using the base API.
-
-[Drive a base →](/how-tos/drive-rover/)
-
-
-
-{{< tabs >}}
-{{% tab name="Python" %}}
-
-```python
-async def spin_motor(motor):
- # Turn the motor at 35% power forwards
- await motor.set_power(power=0.35)
- # Let the motor spin for 3 seconds
- time.sleep(3)
- # Stop the motor
- await motor.stop()
-```
-
-{{% /tab %}}
-{{% tab name="Go" %}}
-
-```go
-func spinMotor(ctx context.Context, motor motor.Motor, logger logging.Logger) {
- // Turn the motor at 35% power forwards
- err = motor.SetPower(context.Background(), 0.35, nil)
- // Let the motor spin for 3 seconds
- time.Sleep(3 * time.Second)
- // Stop the motor
- err = motor.Stop(context.Background(), nil)
-}
-```
-
-{{% /tab %}}
-{{% tab name="TypeScript" %}}
-
-```ts
-async function spinMotor(motorClient: VIAM.MotorClient) {
- // Turn the motor at 35% power forwards
- await motorClient.setPower(0.35);
- // Let the motor spin for 3 seconds
- const sleep = (ms: number) =>
- new Promise((resolve) => setTimeout(resolve, ms));
- await sleep(3000);
- // Stop the motor
- await motorClient.stop();
-}
-```
-
-{{% /tab %}}
-{{% tab name="Flutter" %}}
-
-```dart
-Future spinMotor() async {
- // Turn the motor at 35% power forwards
- await motorClient.setPower(0.35);
- // Let the motor spin for 3 seconds
- await Future.delayed(Duration(seconds: 3));
- // Stop the motor
- await motorClient.stop();
-}
-```
-
-{{% /tab %}}
-{{% tab name="C++" %}}
-
-```cpp
-void spin_motor(std::shared_ptr motor) {
- // Turn the motor at 35% power forwards
- motor->set_power(0.35);
- // Let the motor spin for 3 seconds
- sleep(3);
- // Stop the motor
- motor->stop();
-}
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-You can use any motor with Viam. Configure it as a motor component. Then you can operate it using the motor API.
-
-[Control a motor →](/how-tos/control-motor/)
-
-
-
-{{< tabs >}}
-{{% tab name="Python" %}}
-
-```python
-# Get the readings provided by the sensor.
-co_2_monitor = Sensor.from_robot(machine, "co2-monitor")
-co_2_monitor_return_value = await co_2_monitor.get_readings()
-print(f"co2-monitor get_readings return value: {co_2_monitor_return_value}")
-```
-
-{{% /tab %}}
-{{% tab name="Go" %}}
-
-```go
-// Get the readings provided by the sensor.
-co2Monitor, err := sensor.FromRobot(machine, "co2-monitor")
-co2MonitorReturnValue, err := co2Monitor.Readings(
- context.Background(), map[string]interface{}{})
-logger.Infof("co2-monitor return value: %+v", co2MonitorReturnValue)
-```
-
-{{% /tab %}}
-{{% tab name="TypeScript" %}}
-
-```ts
-// Get the readings provided by the sensor.
-const co2MonitorClient = new VIAM.SensorClient(machine, "co2-monitor");
-const co2MonitorReturnValue = await co2MonitorClient.getReadings();
-console.log("co2-monitor return value:", co2MonitorReturnValue);
-```
-
-{{% /tab %}}
-{{% tab name="Flutter" %}}
-
-```dart
-// Get the readings provided by the sensor.
-final co2Monitor = Sensor.fromRobot(client, "co2-monitor");
-var readings = await co2Monitor.readings();
-print(readings);
-```
-
-{{% /tab %}}
-{{% tab name="C++" %}}
-
-```cpp
-// Get the readings provided by the sensor.
-auto co2monitor = machine->resource_by_name("co2-monitor");
-auto co2monitor_get_readings_return_value = co2monitor->get_readings();
-std::cout << "co2-monitor get_readings return value " << co2monitor_get_readings_return_value << "\n";
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-You can use any physical sensor or anything else that provides measurements with Viam. Configure it as a sensor component. Then you can get sensor readings using the sensor API.
-
-[Collect sensor data →](/how-tos/collect-sensor-data/)
-
-
-
-
-{{% /tab %}}
-{{% tab name="Move an arm" %}}
-
-
-{{< tabs >}}
-{{% tab name="Python" %}}
-
-```python
-# Command a joint position move: move the forearm of the arm slightly up
-cmd_joint_positions = JointPositions(values=[0, 0, -30.0, 0, 0, 0])
-await my_arm_component.move_to_joint_positions(
- positions=cmd_joint_positions)
-
-# Generate a simple pose move +100mm in the +Z direction of the arm
-cmd_arm_pose = await my_arm_component.get_end_position()
-cmd_arm_pose.z += 100.0
-await my_arm_component.move_to_position(pose=cmd_arm_pose)
-```
-
-{{% /tab %}}
-{{% tab name="Go" %}}
-
-```go
-// Command a joint position move: move the forearm of the arm slightly up
-cmdJointPositions := &armapi.JointPositions{Values: []float64{0.0, 0.0, -30.0, 0.0, 0.0, 0.0}}
-err = myArmComponent.MoveToJointPositions(context.Background(), cmdJointPositions, nil)
-
-// Generate a simple pose move +100mm in the +Z direction of the arm
-currentArmPose, err := myArmComponent.EndPosition(context.Background(), nil)
-adjustedArmPoint := currentArmPose.Point()
-adjustedArmPoint.Z += 100.0
-cmdArmPose := spatialmath.NewPose(adjustedArmPoint, currentArmPose.Orientation())
-
-err = myArmComponent.MoveToPosition(context.Background(), cmdArmPose, nil)
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-You can use any robotic arm with Viam.
-Configure it as an arm component. Then you can move it using the arm API.
-
-[Move a robotic arm →](/how-tos/move-robot-arm/)
-
-
-
-Using the Viam Registry you can create _{{< glossary_tooltip term_id="resource" text="resources" >}}_ for additional hardware types or models and then deploy them to your machines.
-You can use an existing component or service type or create generic resources.
-
-[Create a module →](/how-tos/hello-world-module/)
-
-
-
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-
-## Make your devices better and smarter
-
-
- Pick and choose from additional services. Make your devices understand their environment, interact with it, collect data, and more:
-
-
-{{< tabs >}}
-{{% tab name="Python" %}}
-
-```python
-# Get image from camera stream on construction site
-cam = Camera.from_robot(machine, "construction-site-cam")
-img = await cam.get_image()
-
-# Use machine learning model to gather information from the image
-hardhat_detector = VisionClient.from_robot(machine, "hardhat_detector")
-detections = await hardhat_detector.get_detections(img)
-
-# Check whether a person is detected not wearing a hardhat
-for d in detections:
- if d.confidence > 0.8 and d.class_name == "NO-Hardhat":
- print("Violation detected.")
-```
-
-{{% /tab %}}
-{{% tab name="Go" %}}
-
-```go
-// Get image from camera stream on construction site
-myCamera, err := camera.FromRobot(machine, "construction-site-cam")
-camStream, err := myCamera.Stream(context.Background())
-img, release, err := camStream.Next(context.Background())
-defer release()
-
-// Use machine learning model to gather information from the image
-visService, err := vision.FromRobot(machine, "hardhat_detector")
-detections, err := visService.Detections(context.Background(), img, nil)
-
-// Check whether a person is detected not wearing a hardhat
-for i := 0; i < len(detections); i++ {
- if (detection[i].confidence > 0.8) && (detection[i].class_name == "NO-Hardhat") {
- logger.Info("Violation detected.")
- }
-}
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-Computer vision enables your machine to use connected cameras to interpret the world around it.
-With inferences about a machine's surroundings, you can program machines to act based on this input.
-
-[Try the vision service →](/tutorials/projects/helmet/)
-
-
-
-Sync sensor data, images, and any other binary or timeseries data from all your machines to the cloud. There, you can query and visualize it.
-
-Intermittent internet connectivity? Your data will sync whenever internet is available.
-
-[Learn about Data Management →](/services/data/)
-
-
-
-The motion service enables your machine to plan and move relative to itself, other machines, and the world.
-
-[Try the motion service →](/tutorials/services/plan-motion-with-arm-gripper/)
-
-
-
-
-{{}}
-
-
-
-
-{{% /tab %}}
-{{% tab name="Navigation" %}}
-
-
-{{< tabs >}}
-{{% tab name="Python" %}}
-
-```python
-my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")
-
-# Create a new waypoint at the specified latitude and longitude
-location = GeoPoint(latitude=40.76275, longitude=-73.96)
-
-# Add waypoint to the service's data storage
-await my_nav.add_waypoint(point=location)
-
-my_nav = NavigationClient.from_robot(robot=robot, name="my_nav_service")
-
-# Set the service to operate in waypoint mode and begin navigation
-await my_nav.set_mode(Mode.ValueType.MODE_WAYPOINT)
-```
-
-{{% /tab %}}
-{{% tab name="Go" %}}
-
-```go
-myNav, err := navigation.FromRobot(robot, "my_nav_service")
-
-// Create a new waypoint at the specified latitude and longitude
-location = geo.NewPoint(40.76275, -73.96)
-
-// Add waypoint to the service's data storage
-err := myNav.AddWaypoint(context.Background(), location, nil)
-
-myNav, err := navigation.FromRobot(robot, "my_nav_service")
-
-// Set the service to operate in waypoint mode and begin navigation
-mode, err := myNav.SetMode(context.Background(), Mode.MODE_WAYPOINT, nil)
-```
-
-{{% /tab %}}
-{{% tab name="Viam app" %}}
-
-{{< imgproc src="/services/navigation/navigation-control-card.png" alt="An example control interface for a navigation service in the Viam app Control Tab." resize="1200x" class="imgzoom aligncenter" >}}
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-Use the navigation service to autonomously navigate a machine to defined waypoints.
-
-[Try the navigation service →](/tutorials/services/navigate-with-rover-base/)
-
-
-
-
-{{% /tab %}}
-{{% tab name="Custom Logic" %}}
-
-
-{{< tabs >}}
-{{% tab name="Python" %}}
-
-```python
-my_twilio_svc = Generic.from_robot(robot=machine, name="my_twilio_svc")
-
-# Use a custom command to send a text message with Twilio
-command = {"to": "+1 234 567 8901", "body": "Hello world!"}
-result = await my_twilio_svc.do_command(command)
-```
-
-{{% /tab %}}
-{{% tab name="Go" %}}
-
-```go
-myTwilioSvc, err := generic.FromRobot(machine, "my_twilio_svc")
-
-// Use a custom command to send a text message with Twilio
-command := map[string]interface{}{"to": "+1 234 567 8901", "body": "Hello world!"}
-result, err := myTwilioSvc.DoCommand(context.Background(), command)
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-Using the Viam Registry you can turn services and your own custom business logic into _{{< glossary_tooltip term_id="module" text="modules" >}}_. You can then deploy your modules to your machines.
-
-[Create a module →](/how-tos/create-module/)
-
-
-
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-
-## Go from one machine to thousands
-
-
- When you connect machines to the cloud you get fleet management tools that let you scale. Go from one prototype to thousands of machines you can manage and operate from one place using the Viam Cloud.
-
-
-Manage hardware and software for multiple machines using a built-in tool called _{{< glossary_tooltip term_id="fragment" text="fragments" >}}_.
-You can make changes to some or all of your machines in one go.
-
-[Deploy packages across devices →](/how-tos/deploy-packages/)
-
-
-
-{{< tabs >}}
-{{% tab name="Shell" %}}
-
-```sh {class="command-line" data-prompt="$" data-output="3-5,6,7"}
-# Create configuration for provisioning machines with a fragment
-echo "{
- "manufacturer": "Company",
- "model": "SmartRover",
- "fragment_id": "11d1059b-eaed-4ad8-9fd8-d60ad7386aa2"
-}" >> viam-provisioning.json
-
-# Get and run the script to install viam on a board.
-wget https://storage.googleapis.com/packages.viam.com/apps/viam-agent/preinstall.sh
-chmod 755 preinstall.sh
-sudo ./preinstall.sh
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-Provisioning allows you to complete part of the machine setup during the manufacturing process. The rest of the first-time setup happens once the machine is taken into operation.
-This way, machines automatically get the latest updates.
-
-[Learn about provisioning →](/fleet/provision/)
-
-
-
-{{< tabs >}}
-{{% tab name="Viam app" %}}
-
-{{< imgproc src="/tutorials/data-management/train-model.png" alt="The data tab showing the train a model pane" resize="1200x" class="imgzoom" >}}
-
-{{% /tab %}}
-{{% tab name="Python" %}}
-
-```python
-# Start a training job to create a classification model based on the dataset
-job_id = await ml_training_client.submit_training_job(
- org_id="abbc1c1c-d2e3-5f67-ab8c-de912345f678",
- dataset_id="12ab3cd4e56f7abc89de1fa2",
- model_name="recognize_gestures",
- model_version="1",
- model_type=ModelType.MODEL_TYPE_MULTI_LABEL_CLASSIFICATION,
- tags=["follow", "stop"]
-)
-
-# Get status information for training job
-job_metadata = await ml_training_client.get_training_job(
- id=job_id)
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-Build machine learning models based on your machines' data. You can pick from different training algorithms or create your own.
-
-[Train and deploy ML models →](/how-tos/train-deploy-ml/)
-
-
-
-{{< tabs >}}
-{{% tab name="Viam app" %}}
-
-{{}}
-
-{{% /tab %}}
-{{% tab name="Python" %}}
-
-```python
-# Create a new machine
-new_machine_id = await cloud.new_robot(
- name="new-machine", location_id="abcde1fghi")
-
-# Get organization associated with authenticated user / API key
-org_list = await cloud.list_organizations()
-
-# Create a new API key with owner access for the new machine
-auth = APIKeyAuthorization(
- role="owner",
- resource_type="robot",
- resource_id=new_machine_id
-)
-api_key, api_key_id = await cloud.create_key(
- org_list[0].id, [auth], "key_for_new_machine")
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-
-
-Viam allows you to organize and manage any number of machines. When collaborating with others, you can assign permissions using Role-Based Access Control (RBAC).
-
-[Learn about access control →](/cloud/rbac/)
-
-
-
-
-
-{{% /tab %}}
-{{< /tabs >}}
diff --git a/docs/appendix/_index.md b/docs/appendix/_index.md
deleted file mode 100644
index 37f744a50b..0000000000
--- a/docs/appendix/_index.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: "Appendix"
-linkTitle: "Appendix"
-weight: 900
-empty_node: true
-layout: "empty"
-notoc: true
-type: "docs"
-description: "Reference and Background Material"
-canonical: "/appendix/changelog/"
----
diff --git a/docs/appendix/apis/_index.md b/docs/appendix/apis/_index.md
deleted file mode 100644
index b02f0167d5..0000000000
--- a/docs/appendix/apis/_index.md
+++ /dev/null
@@ -1,88 +0,0 @@
----
-title: "Viam's Client APIs"
-linkTitle: "APIs"
-weight: 20
-type: "docs"
-description: "Access and control your machine or fleet with the SDKs' client libraries for the resource and robot APIs."
-icon: true
-images: ["/services/icons/sdk.svg"]
-tags: ["client", "sdk", "viam-server", "networking", "apis", "robot api"]
-aliases:
- - /program/sdks/
- - /program/apis/
- - /build/program/apis/
-no_list: true
-date: "2024-10-01"
-# updated: "" # When the content was last entirely checked
----
-
-Every Viam {{< glossary_tooltip term_id="resource" text="resource" >}} exposes an [application programming interface (API)](https://en.wikipedia.org/wiki/API) described through [protocol buffers](https://developers.google.com/protocol-buffers).
-
-The API methods provided by the SDKs for each of these resource APIs wrap gRPC client requests to the machine when you execute your program, providing you a convenient interface for accessing information about and controlling the {{< glossary_tooltip term_id="resource" text="resources" >}} you have [configured](/configure/) on your machine.
-
-## Platform APIs
-
-{{< cards >}}
-{{% manualcard link="/appendix/apis/fleet/" title="Fleet Management API" %}}
-
-Create and manage organizations, locations, and machines, get logs from individual machines, and manage fragments and permissions.
-
-{{% /manualcard %}}
-{{% manualcard link="/appendix/apis/data-client/" title="Data Client API" %}}
-
-Upload, download, filter, tag or perform other tasks on data like images or sensor readings.
-
-{{% /manualcard %}}
-{{% manualcard link="/appendix/apis/robot/" title="Machine Management API" %}}
-
-Manage your machines: connect to your machine, retrieve status information, and send commands remotely.
-
-{{% /manualcard %}}
-{{% manualcard link="/appendix/apis/ml-training-client/" title="ML Training Client API" %}}
-
-Submit and manage ML training jobs running on the Viam app.
-
-{{% /manualcard %}}
-{{% manualcard link="/appendix/apis/billing-client/" title="Billing Client API" %}}
-
-Retrieve billing information from the Viam app.
-
-{{% /manualcard %}}
-
-{{< /cards >}}
-
-## Component APIs
-
-These APIs provide interfaces for controlling and getting information from the {{< glossary_tooltip term_id="component" text="components" >}} of a machine:
-
-{{< cards >}}
-{{< card link="/appendix/apis/components/arm/" customTitle="Arm API" noimage="True" >}}
-{{< card link="/appendix/apis/components/base/" customTitle="Base API" noimage="True" >}}
-{{< card link="/appendix/apis/components/board/" customTitle="Board API" noimage="True" >}}
-{{< card link="/appendix/apis/components/camera/" customTitle="Camera API" noimage="True" >}}
-{{< card link="/appendix/apis/components/encoder/" customTitle="Encoder API" noimage="True" >}}
-{{< card link="/appendix/apis/components/gantry/" customTitle="Gantry API" noimage="True" >}}
-{{< card link="/appendix/apis/components/generic/" customTitle="Generic API" noimage="True" >}}
-{{< card link="/appendix/apis/components/gripper/" customTitle="Gripper API" noimage="True" >}}
-{{< card link="/appendix/apis/components/input-controller/" customTitle="Input controller API" noimage="True" >}}
-{{< card link="/appendix/apis/components/motor/" customTitle="Motor API" noimage="True" >}}
-{{< card link="/appendix/apis/components/movement-sensor/" customTitle="Movement sensor API" noimage="True" >}}
-{{< card link="/appendix/apis/components/power-sensor/" customTitle="Power sensor API" noimage="True" >}}
-{{< card link="/appendix/apis/components/sensor/" customTitle="Sensor API" noimage="True" >}}
-{{< card link="/appendix/apis/components/servo/" customTitle="Servo API" noimage="True" >}}
-{{< /cards >}}
-
-## Service APIs
-
-These APIs provide interfaces for controlling and getting information from the services you configured on a machine.
-
-{{< cards >}}
-{{% card link="/appendix/apis/services/data/" customTitle="Data management service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/vision/" customTitle="Vision service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/ml/" customTitle="ML model service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/motion/" customTitle="Motion service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/navigation/" customTitle="Navigation service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/generic/" customTitle="Generic service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/slam/" customTitle="SLAM service API" noimage="True" %}}
-{{% card link="/appendix/apis/services/base-rc/" customTitle="Base Remote Control service API" noimage="True" %}}
-{{< /cards >}}
diff --git a/docs/appendix/learning-resources.md b/docs/appendix/learning-resources.md
deleted file mode 100644
index 91aa005e23..0000000000
--- a/docs/appendix/learning-resources.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: "Learning Resources"
-linkTitle: "Learning Resources"
-description: "A collection of links to external sources discussing robotics topics and basic information that we believe users may find helpful."
-type: "docs"
-draft: true
----
-
-## Overview
-
-The following sections contain links that we think you will find useful during your journey into robotics.
-
-## Basic electronics
-
-### Hobby servos
-
-Hobby servos are a type of actuator comprising a small motor with built-in closed-loop control.
-They are useful for precise positioning, usually limited to a 180 degree range of angles.
-Continuous rotation servos are also available that maintain a speed rather than a position.
-
-#### Mechanism
-
-Hobby servos contain a small electric motor, a series of gears, and a potentiometer attached to the shaft to act as an encoder.
-It also contains a closed-loop position control circuit that takes a [Pulse Width Modulation (PWM)](https://en.wikipedia.org/wiki/Pulse-width_modulation) signal input and holds the shaft at a certain angle based on that input.
-
-A typical servo will take PWM pulses ranging from 1ms to 2ms long, and map this range to a 180 degree range of possible positions.
-A 1.5ms signal will hold the servo in the middle or "neutral" position, 1ms will move it to 90 degrees from there in one direction, and 2ms will move it 90 degrees from neutral in the opposite direction.
-Note that some servos have a different PWM range, mapping to a different set of angles.
-
-#### Hardware requirements
-
-Unlike [motors](/components/motor/), servos do not require a motor driver chip.
-
-A typical servo control setup comprises the following:
-
-- A Raspberry Pi (or other [board](/components/board/))
-- A servo
-- An appropriate power supply
- - If the servo will not be under any significant load and thus won’t draw much current, you may be able to get away with powering it off 5V (if that’s its required voltage) from the Pi pins.
- However it is advisable to power it directly from a power supply that can meet its peak current needs so as not to inadvertently power cycle the Pi or other components.
-
-#### Wiring
-
-{{% alert title="Caution" color="caution" %}}
-Always disconnect devices from power before plugging, unplugging or moving wires or otherwise modifying electrical circuits.
-{{% /alert %}}
-
-Here's an example of how a servo might be wired to a Raspberry Pi:
-
-![A diagram showing the signal wire of a servo connected to pin 16 on a Raspberry Pi. The servo's power wires are connected to a 4.8V power supply.](/components/servo/servo-wiring.png)
-
-### Resistors
-
-[Online Resistor Color Code Calculator](https://goodcalculators.com/resistor-color-code-calculator/) - Enter the desired resistor value in Ohms, kOhms, or MOhms, and press enter and this site displays the color bands for that resistor value.
-
-#### Resistor value chart
-
-![Chart of standard colors to values for electronic components. An example resistor with green, red, and orange bands is shown. The value is 52 times 10 to the third power, or 52,000 Ohms.](/internals/vector/resistor.png)
-
-You can easily learn resistor color markings without referring to a chart by remembering this jingle:
-
-"Badly Burnt Resistors On Your Ground Bus Void General Warranty."
-
-Now, equate the jingle to the colors in this order:
-Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Gray, White
-
-And their values on a resistor:
-0, 1, 2, 3, 4, 5, 6, 7, 8, 9
-
-- The bands 1 and 2 indicate the first two significant digits on a resistor.
-- Band 3 is a multiplier on four-band resistors.
- For example, a resistor with brown, green, orange bands representing, 1, 5, and 3, respectively, which equates to 15 times ten to the third, or 15,000 Ohms, or 15 kOhms.
-- On resistors with four bands, the band 4 indicates tolerance, with gold being +/- 5% and silver being +/- 10%.
-- On five-band resistors, band 3 becomes an additional significant digit, band 4 becomes the multiplier, and band 5 becomes the tolerance band.
-- Six-band resistors are read identically to five-band resistors, their difference being that the sixth band indicates the resistor's temperature coefficient.
-
-### LEDs (light-emitting diodes)
-
-Light-emitting diodes come in a variety of form factors:
-![Image of various Light Emitting Diode form factors.](/internals/vector/verschiedene-leds.jpg)
-LEDs commonly have two leads, although specialty LEDs are available that are capable of simultaneously displaying two colors or of displaying a blended shade. These specialty LEDs have 4-6 leads and 2-4 LED junctions.
-
-LEDs work by applying a voltage with a positive and negative polarity to the leads in such a manner that the positive voltage is attached to the anode of the LED and the negative voltage lead is attached to the LED's cathode. On a two-pin LED, the longer pin is the anode and the short pin is the cathode.
-
-LEDs require current-limiting resistors to avoid destroying the LED junction during an over-current situation. Always include a current-limiting resistor in basic LED circuits. The following schematic illustrates this circuit:
-
-![This image displays a schematic showing the arrangement of a DC voltage source with the positive lead to the LED's anode, the LED's cathode connected to a one end of a current-limiting resistor and the other end of the voltage drop resistor connected to the negative lead of the voltage source, completing the circuit.](/internals/vector/led-circuit2.png)
diff --git a/docs/appendix/try-viam/_index.md b/docs/appendix/try-viam/_index.md
deleted file mode 100644
index ca20ff5140..0000000000
--- a/docs/appendix/try-viam/_index.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: "Try Viam"
-linkTitle: "Try Viam"
-childTitleEndOverwrite: "Try Viam"
-weight: 85
-type: "docs"
-description: "Try Viam by taking over a Viam Rover in our robotics lab."
-videos: ["/appendix/try-viam/rover.webm", "/appendix/try-viam/rover.mp4"]
-videoAlt: "Rover reservation management page"
-images: ["/appendix/try-viam/rover.gif"]
-no_list: true
-aliases:
- - "/getting-started/try-viam/"
- - "/tutorials/viam-rover/"
- - /get-started/try-viam/tutorials/
- - "/appendix/try-viam/tutorials/"
- - "/try-viam/"
- - "/get-started/try-viam/"
- - "/appendix/try-viam-faq/"
- - "/try-viam/faq/"
- - "get-started/try-viam/faq/"
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-Viam is a general {{< glossary_tooltip term_id="smart-machine" text="smart machine">}} platform that can run on any hardware.
-The easiest way to try Viam is to [rent and remotely configure and control a Viam Rover](https://app.viam.com/try) located on-site at Viam in New York:
-
-
-
-
{{}}
- 1. Click on TRY in Viam
-
Log into the Viam app and go to the TRY tab. Don’t have a Viam account? Follow the instructions to sign up for an account.
-
-
-
-
{{}}
- 2. Reserve your slot
-
If no one’s using a Viam Rover, you’ll take over immediately.
-Otherwise, you’ll see an estimated time for the next slot, and we’ll send you an email when it’s your turn.
-See detailed instructions.
-
-
-
-
{{}}
- 3. Get started with Viam
-
Try a Viam Rover in our robotics lab. Drive or program the rover to see how you can build a machine with Viam. You can also try services like computer vision.
-
-
-
-
-## Next steps
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{% card link="/appendix/try-viam/rover-resources/" %}}
-{{< /cards >}}
diff --git a/docs/appendix/try-viam/reserve-a-rover.md b/docs/appendix/try-viam/reserve-a-rover.md
deleted file mode 100644
index cc81f78360..0000000000
--- a/docs/appendix/try-viam/reserve-a-rover.md
+++ /dev/null
@@ -1,144 +0,0 @@
----
-title: "Reserve a Viam Rover"
-linkTitle: "Reserve a Viam Rover"
-weight: 10
-type: "docs"
-description: "Reserve a Viam Rover located on-site at Viam in NYC."
-images: ["/appendix/try-viam/try-viam-reserve-preview.png"]
-imageAlt: "Rover reservation page"
-tags: ["try viam", "app"]
-aliases:
- - "/try-viam/reserve-a-rover/"
- - "/get-started/try-viam/reserve-a-rover/"
-toc_hide: true
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-_Try Viam_ is a way to try out the Viam platform without setting up any hardware yourself.
-You can take over a Viam Rover in our robotics lab to play around!
-
-Watch this tutorial video for a walkthrough of Try Viam, including [how to reserve a Viam Rover](#using-the-reservation-system), [navigate the Viam platform](/fleet/), and [drive the rover](/components/base/wheeled/#test-the-base):
-
-{{}}
-
-## Using the reservation system
-
-### Create a reservation
-
-{{< readfile "/static/include/try-viam/create-a-reservation.md" >}}
-
-### Access your rover rental
-
-Once your reservation starts and the system has configured your rover, click **TRY MY ROVER** from the [**TRY VIAM** page](https://app.viam.com/try) or, if you were queuing, click **Take Me to My Rover** in the confirmation email.
-
-{{}}
-
-{{}}
-
-### Limitations
-
-When using a rented Viam rover, adding [modules](/registry/) is disabled for security purposes.
-
-### Extend your reservation
-
-{{< readfile "/static/include/try-viam/extend-a-reservation.md" >}}
-
-### Cancel my reservation
-
-{{< readfile "/static/include/try-viam/cancel-a-reservation.md" >}}
-
-## Next steps
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{< /cards >}}
-
-## FAQ
-
-Try Viam allows you to try the Viam platform without setting up any hardware yourself.
-You can take over and play around with a Viam Rover in our robotics lab from anywhere in the world!
-
-### How do I make a reservation to take over a Viam Rover?
-
-{{< readfile "/static/include/try-viam/create-a-reservation.md" >}}
-
-### My machine had an error, a system crash, or is physically stuck
-
-1. Please notify Viam support on [our Community Discord](https://discord.gg/viam).
-2. Use the **Add Viam Support** button on your machine's Location page to give Viam Support access to your _location_.
- Refer to [Managing Locations and sub-locations](/cloud/locations/).
-
-### Can I extend my time?
-
-Sure!
-
-{{< readfile "/static/include/try-viam/extend-a-reservation.md" >}}
-
-### Can I cancel my reservation/session?
-
-Yes.
-
-{{< readfile "/static/include/try-viam/cancel-a-reservation.md" >}}
-
-### How can I reuse my borrowed rover?
-
-After using Try Viam, your machine config stays in your Viam account.
-You can access your machine page, write code to control it, and modify its config after your reservation time ends.
-
-When you next borrow a rover you can choose to configure it with a previous rover configuration from your account or create a new rover with the standard starting config.
-
-{{< alert title="Tip" color="tip" >}}
-You can also reuse your code for the rover for other machines that you configure with Viam in the future.
-{{< /alert >}}
-
-### What happens to my borrowed rover after the rental session?
-
-1. On session expiration, Viam removes the "live" status from the machine.
-2. Viam then removes your config from the physical machine in preparation for its next rental.
-3. The Rover Rental Location and the final config of all previous rental rovers remain visible to your organization.
- You can continue modifying the configurations as desired.
-
-### I accidentally deleted my machine
-
-Unfortunately, there is no recovery path for a deleted machine.
-If you delete your machine and have a current reservation, click **Cancel Reservation** and then request a new reservation.
-
-### Can I rename my machine or change the location?
-
-You can rename your machine or change the location.
-If you change the location, you must refresh the page.
-
-### Which organization does this machine e belong to?
-
-Your machine belongs to the [organization](/cloud/organizations/) you were in when you made the request.
-
-### Can I share this Location with a friend to work on the machine together?
-
-Sure, you can [invite other users to your organization](/cloud/locations/) to collaborate on your machine.
-As members of your organization, those users have full control of your machine.
-Another collaboration option is to use screen sharing in a Zoom or Webex session.
-
-### How many active rentals can I have?
-
-You can only borrow one rover at a time.
-You cannot join the queue for another reservation while you have an active rental session.
-If you would like to, you can [extend your reservation](/appendix/try-viam/reserve-a-rover/#can-i-extend-my-time).
-
-### I loved my experience - can I play around more?
-
-Yes! You can borrow the rover as many times as you’d like.
-Here are some tutorials which you can follow:
-
-- [Drive with the Viam SDK](/how-tos/drive-rover/)
-- [Detect a Color](/how-tos/detect-color/)
-
-If you want to get your own Viam Rover, [you can](https://viam.com/resources/rover).
-
-### Why can't I use the rover's microphone?
-
-For security reasons, Viam has disabled the microphone on rover rentals.
-The microphone on [Viam Rovers shipped to you](/appendix/try-viam/rover-resources/) functions normally.
-
-{{< snippet "social.md" >}}
diff --git a/docs/appendix/try-viam/rover-resources/_index.md b/docs/appendix/try-viam/rover-resources/_index.md
deleted file mode 100644
index ab27d19ee1..0000000000
--- a/docs/appendix/try-viam/rover-resources/_index.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: "Your own Viam Rover"
-linkTitle: "Your own Viam Rover"
-weight: 80
-simple_list: true
-type: docs
-tags: ["rover", "viam rover"]
-images: ["/appendix/try-viam/rover-resources/viam-rover/box-contents.jpg"]
-imageAlt: "A Viam Rover in a box"
-aliases:
- - "/viam-rover-resources/"
- - "/rover-resources/"
- - "/try-viam/rover-resources/"
- - "/get-started/try-viam/rover-resources/"
-description: If you want a convenient mobile base for robotics projects, order a Viam rover and set it up.
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-{{< alert title="Tip" color="tip" >}}
-If you want a convenient mobile {{% glossary_tooltip term_id="base" text="base"%}} for a variety of robotics projects, you can now [order your own Viam rover](https://www.viam.com/resources/rover).
-{{< /alert >}}
-
-
- The Viam Rover 2 arrives preassembled with two encoded motors with suspension, a webcam with a microphone unit, a 6 axis IMU, power management and more.
- It is primarily designed for use with a Raspberry Pi 4.
- Featuring an anodized aluminum chassis with expandable mounting features, the rover can comfortably navigate indoor environments with a 20 lb payload.
- You can customize your rover by mounting sensors, LiDAR, and arms.
-
-
-
-
-
-{{< alert title="Important" color="note" >}}
-You must purchase the following hardware separately:
-
-- A Raspberry Pi 4
-- Four 18650 batteries or RC-type battery (with charger)
-- A MicroSD card and an adapter/reader
-
-{{< /alert >}}
-
-### Next steps
diff --git a/docs/appendix/try-viam/rover-resources/rover-tutorial-1.md b/docs/appendix/try-viam/rover-resources/rover-tutorial-1.md
deleted file mode 100644
index 1a00e5d575..0000000000
--- a/docs/appendix/try-viam/rover-resources/rover-tutorial-1.md
+++ /dev/null
@@ -1,296 +0,0 @@
----
-title: "Unbox and Set Up your Viam Rover 1"
-linkTitle: "Unbox and Set Up your Viam Rover 1"
-weight: 15
-type: "docs"
-tags: ["rover", "tutorial"]
-images: ["/appendix/try-viam/rover-resources/viam-rover/box-contents.jpg"]
-imageAlt: "A Viam Rover 1 in a box"
-description: "A list of the contents of the Viam Rover 1 kit, instructions for wiring your rover, and links for additional hardware."
-aliases:
- - "/rover-resources/rover-tutorial/"
- - "/try-viam/rover-resources/rover-tutorial/"
- - "/get-started/try-viam/rover-resources/rover-tutorial/"
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-{{% alert title="Tip" color="tip" %}}
-A new version of the Viam Rover is now available, the [Viam Rover 2](https://www.viam.com/resources/rover).
-If you have purchased a Viam Rover 2, follow [these instructions](/appendix/try-viam/rover-resources/rover-tutorial/) instead.
-{{% /alert %}}
-
-The [Viam Rover 1](https://www.viam.com/resources/rover) arrives preassembled with two encoded motors with suspension, a webcam with a microphone unit, and a 3D accelerometer module.
-
-{{< alert title="Important" color="note" >}}
-You must purchase the following hardware separately:
-
-- A Raspberry Pi 4
-- Four 18650 batteries (with charger)
-- A MicroSD card and an adapter/reader
- {{< /alert >}}
-
-{{}}
-
-This guide covers what's inside the kit, describes each component, provides instructions for wiring your rover, and includes links for additional hardware.
-
-## What's inside the kit
-
-1. One assembled Viam Rover 1.
-
- {{}}
-
-1. Four M2.5 screws for mounting your Raspberry Pi.
-
- {{}}
-
-1. Two spare stiffer suspension springs.
- You can swap them out with the springs that come with the rover if you need stiffer suspension for higher payload applications.
-
- {{}}
-
-1. Three different Allen wrenches (1.5 mm, 2 mm, and 2.5 mm) to unscrew the top and mount the Raspberry Pi.
-
- {{}}
-
-1. Ten female-to-female jumper wires.
- All of the wires' colors correspond to the included wiring diagram.
- Six are for the motor controller and four are for the accelerometer.
-
- {{}}
-
-All together, your kit looks like this:
-
-{{}}
-
-## Rover components
-
-### Dual drive motors with suspension and integrated motor encoders
-
-{{}}
-
-The motors come with integrated encoders.
-For information on encoders, see [Encoder Component](/components/encoder/).
-For more information on encoded DC motors, see [Encoded Motors](/components/motor/encoded-motor/).
-
-The kit also includes stiffer suspension springs that you can substitute for the ones on the rover.
-Generally, a stiff suspension helps with precise steering control.
-In contrast, a soft suspension allows the wheels to move up and down to absorb small bumps on the rover's path.
-
-### Motor driver
-
-{{}}
-
-The kit comes with an L298N driver dual H-Bridge DC motor driver.
-L298 is a high voltage and high current motor drive chip, and H-Bridge is typically used to control the rotating direction and speed of DC motors.
-
-### 720p webcam, with integrated microphone
-
-{{}}
-
-The webcam that comes with the kit is a standard USB camera device and the rover has a custom camera mount for it.
-For more information, see [Camera Component](/components/camera/).
-
-### 3D accelerometer
-
-{{}}
-
-The [ADXL345](https://github.com/viam-modules/analog-devices/) sensor manufactured by Analog Devices is a digital 3-axis accelerometer that can read acceleration up to ±16g for high-resolution (13-bit) measurements.
-You can access it with a SPI (3-wire or 4-wire) or I2C digital interface.
-
-In Viam, you can configure it as a [movement sensor component](/components/movement-sensor/).
-
-### Buck converter
-
-{{}}
-
-A buck converter is a DC-to-DC power converter and you use it to step down voltage from its input to its output.
-The 5A mini560 step-down module has high conversion efficiency and low heat generation.
-
-### Toggle switch
-
-{{}}
-
-The toggle switch comes wired to the rover and you use it to turn the power on and off.
-
-### Battery pack
-
-{{}}
-
-The rover comes with a battery holder.
-You must purchase four 18650 batteries (and a charger) separately.
-The battery holder also has a female jack for an external DC power supply.
-
-#### Four 18650 batteries with a charger
-
-An 18650 battery is a lithium-ion rechargeable battery.
-We recommend the button-top type, though either button or flat top can work.
-We have used batteries approximately 67.5mm in length, but the battery housing includes a spring to accommodate most batteries of that approximate length.
-Any brand is suitable as long as you comply with the battery safety requirements.
-
-Check the [safety](#safety) section for more information.
-
-## Safety
-
-Read all instructions fully before using this product.
-
-This product is not a toy and is not suitable for children under 12.
-
-Switch the rover off when not in use.
-
-{{< alert title="Warning" color="warning" >}}
-Lithium-ion batteries may pose a flammable hazard.
-This product requires four 18650 lithium-ion batteries.
-Refer to the battery manufacturer’s operating instructions to ensure safe operation of the Viam Rover 1.
-Dispose of lithium-ion batteries per manufacturer instructions.
-{{< /alert >}}
-
-{{< alert title="Caution" color="caution" >}}
-Damage may occur to the Raspberry Pi and/or Viam Rover 1 if wired incorrectly.
-Refer to the manufacturer’s instructions for correct wiring.
-{{< /alert >}}
-
-Disclaimer: This product is preliminary and experimental in nature, and is provided "AS IS" without any representation or warranty of any kind.
-Viam does not make any promise or warranty that the product will meet your requirements or be error free.
-Some states do not allow the exclusion or disclaimer of implied warranties, so the above exclusions may not apply to you.
-
-## Setup
-
-This is the recommended order to assemble your rover:
-
-1. [Install Raspberry Pi OS on the microSD card.](#install-raspberry-pi-os)
-2. [Unscrew the top of the rover and screw the Pi to the base.](#attach-the-raspberry-pi-to-the-rover)
-3. [Connect the components.](#connect-the-wires)
-4. [Screw the top of the rover back on and turn the rover on.](#turn-the-rover-on)
-5. [Install `viam-server` and connect to the Viam app.](#connect-to-the-viam-app)
-
-### Install Raspberry Pi OS
-
-Install a 64-bit Raspberry Pi OS onto your Pi following our [Raspberry Pi installation guide](/installation/prepare/rpi-setup/). Follow all steps as listed, including the final step, [Enable communication protocols](/installation/prepare/rpi-setup/#enable-communication-protocols), which is required to enable the accelerometer on your rover.
-
-### Attach the Raspberry Pi to the Rover
-
-Once you have installed Raspberry Pi OS and `viam-server`, put your SD card in the slot on your Pi.
-To be able to attach the Raspberry Pi, unscrew the top of the rover with the biggest Allen key.
-Then use the smallest Allen key and the provided M2.5 screws to attach the Raspberry Pi to your rover in the designated spots.
-The following image shows the four mounting holes for the Pi, circled in red:
-
-{{}}
-
-{{< alert title="Tip" color="tip" >}}
-The rover's design allows you to reach the SD card slot at all times, so you can remove or reinsert the SD card without removing the top of the rover.
-{{< /alert >}}
-
-### Connect the wires
-
-{{< alert title="Tip" color="tip" >}}
-To make it easier for you to see which pin is which, you can print out this [Raspberry Pi Leaf](/appendix/try-viam/viam-raspberry-leaf-8.5x11.pdf) which has labels for the pins and carefully push it onto the pins or fold or cut it so you can hold it up to the Raspberry Pi pins.
-If you use A4 paper, use this [Raspberry Pi Leaf](/appendix/try-viam/viam-raspberry-leaf-A4.pdf) instead.
-
-If you are having trouble punching the pins through, you can pre-punch the pin holes with a pen.
-Only attach the paper when the Pi is unplugged.
-To make attaching the paper easier, use a credit card or a small screwdriver.
-{{< /alert >}}
-
-Wire your Pi to the buck converter, the acceleration tilt module, and the DC motor driver:
-
-![Closeup of the wiring diagram, showcasing the Pi, motor driver, accelerometer, and buck converter, wired according to the table below.](/appendix/try-viam/rover-resources/viam-rover/rover-wiring-diagram.png)
-
-The following pinout corresponds to the diagram:
-
-
-| Component | Component Pin | Raspberry Pi Pin | Wire Color |
-| --------- | --- | ---------------- | ---------- |
-| Buck Converter | GND | 39 | black |
-| Buck Converter | 5V | 4 | red |
-| Acceleration Tilt Module | GND | 34 | black |
-| Acceleration Tilt Module | 3.3V power | 17 | red |
-| Acceleration Tilt Module | SDA | 3 | maroon |
-| Acceleration Tilt Module | SCL | 5 | pink |
-| DC Motor Driver | En B | 22 | gray |
-| DC Motor Driver | In 4 | 18 | yellow |
-| DC Motor Driver | In 3 | 16 | white |
-| DC Motor Driver | In 2 | 13 | green |
-| DC Motor Driver | In 1 | 11 | blue |
-| DC Motor Driver | En A | 15 | purple |
-| DC Motor Driver | GND | 6 | black |
-| DC Motor Driver | Encoder Left | 35 | yellow |
-| DC Motor Driver | 3.3V power | 1 | red |
-| DC Motor Driver | Encoder Right | 37 | white |
-
-{{< alert title="Tip" color="tip" >}}
-En A and En B pins have little plastic jumpers that you need to remove before wiring.
-
-The motor driver on the Viam Rover 1 has 8 pins and 6 wires.
-You must wire it with the outside row pins:
-
-{{}}
-{{< /alert >}}
-
-Then connect the camera's USB cable to the Pi.
-
-![Wiring diagram showcasing the Pi, motors, driver, camera, and all other rover components.](/appendix/try-viam/rover-resources/viam-rover/rover-wiring-diagram-full.png)
-
-![the Pi, motors, driver, and all other rover components](/appendix/try-viam/rover-resources/viam-rover/rover-with-pi.jpg)
-
-### Turn the rover on
-
-Once you have wired up all the components, reattach the top of the rover and fasten the screws.
-Insert the batteries and turn the rover on.
-If the Pi has power, the lights on the Raspberry Pi will light up.
-
-### Connect to the Viam app
-
-While the Pi boots, go to the [Viam app](https://app.viam.com/robots) and add a new machine.
-Navigate to the **CONFIGURE** tab and find your machine's card.
-An alert will be present directing you to **Set up your machine part**.
-Click **View setup instructions** to open the setup instructions.
-Follow the instructions to install `viam-server` on **Linux / Aarch64**.
-
-{{< glossary_tooltip term_id="RDK" text="RDK" >}} type.
-`ssh` into your Pi and follow the setup instructions to install and run `viam-server` on the machine.
-
-To configure your rover so you can start driving it, [add the Viam Fragment to your Machine](/appendix/try-viam/rover-resources/rover-tutorial-fragments/).
-
-## Next steps
-
-Before you can use your Viam rover with the Viam platform you need to configure your rover:
-
-{{< cards >}}
-{{% card link="/appendix/try-viam/rover-resources/rover-tutorial-fragments/" %}}
-{{< /cards >}}
-
-After you have configured your rover, follow one of these tutorials:
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{% card link="/tutorials/services/navigate-with-rover-base/" %}}
-{{< /cards >}}
-
-### Rover build
-
-If you want to learn more about the rover, you can find the CAD files and bill-of-materials (BOM) on [GitHub](https://github.com/viamrobotics/Rover-VR1).
-
-### Extensibility
-
-Due to the aluminum chassis and its expandable mounting features, you can extend the Viam Rover 1.
-With it, you can customize your rover by mounting additional sensors, lidar, robot arms, or other components.
-The following are just a few ideas, but you can expand or modify the rover kit with any components you want:
-
-- For GPS navigation, we support NMEA (using serial and I2C) and RTK.
- Make and model don't make a difference as long as you use these protocols.
- See [Movement Sensor Component](/components/movement-sensor/) for more information.
-- For [LiDAR laser range scanning](/services/slam/cartographer/), we recommend RPlidar (including A1, which is a sub-$100 LIDAR).
-- For robot arms, we tried the [Yahboom DOFBOT robotics arm](https://category.yahboom.net/products/dofbot-jetson_nano) with success.
-
-### Mount an RPlidar to the rover
-
-If you are mounting an RPlidar to your rover, be sure to position the RPlidar so that it faces forward in the direction of travel, facing in the same direction as the included webcam.
-For example, if you are using the [RPlidar A1](https://www.slamtec.com/en/Lidar/A1) model, mount it to the Rover so that the pointed end of the RPlidar mount housing points in the direction of the front of the Rover.
-This ensures that the generated {{< glossary_tooltip term_id="slam" text="SLAM" >}} map is oriented in the expected direction relative to the Rover, with the top of the generated map corresponding to the direction the RPlidar is facing when you initiate mapping.
-
-If you need a mount plate for your RPlidar A1 or A3 model, you can 3D print an adapter plate using the following:
-
-- [RPlidar A1 adapter STL](https://github.com/viamrobotics/Rover-VR1/blob/master/CAD/RPIidarA1_adapter.STL)
-- [RPlidar A3 adapter STL](https://github.com/viamrobotics/Rover-VR1/blob/master/CAD/RPIidarA3_adapter.STL)
diff --git a/docs/appendix/try-viam/rover-resources/rover-tutorial-fragments.md b/docs/appendix/try-viam/rover-resources/rover-tutorial-fragments.md
deleted file mode 100644
index 29b51f3d83..0000000000
--- a/docs/appendix/try-viam/rover-resources/rover-tutorial-fragments.md
+++ /dev/null
@@ -1,213 +0,0 @@
----
-title: "Configure your Viam Rover with a Fragment"
-linkTitle: "Configure your Viam Rover"
-weight: 20
-type: "docs"
-tags: ["rover", "tutorial"]
-description: "Configure your rover by adding the Viam-provided configuration fragment to your rover."
-aliases:
- - "/try-viam/rover-resources/rover-tutorial-fragments/"
- - "/get-started/try-viam/rover-resources/rover-tutorial-fragments/"
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-To be able to drive your rover, you need to configure it.
-Viam provides reusable {{% glossary_tooltip term_id="fragment" text="*fragments*" %}} for [Viam rovers](https://www.viam.com/resources/rover).
-
-## Prerequisites
-
-- An assembled Viam Rover.
- For assembly instructions, see [Unbox and Set Up your Viam Rover](../rover-tutorial/)
-- The board is connected to the [Viam app](https://app.viam.com).
- To add your Pi to the Viam app, refer to [the rover setup guide](/appendix/try-viam/rover-resources/rover-tutorial/#control-your-rover-on-the-viam-app).
-
-## Add the fragment
-
-Follow the appropriate instructions for the model of rover and board you have:
-
-{{< tabs >}}
-{{% tab name="Viam Rover 2 (RPi 5)" %}}
-
-Navigate to your machine in the [Viam app](https://app.viam.com/robots).
-In the left-hand menu of the **CONFIGURE** tab, click the **+** (Create) icon next to the machine {{< glossary_tooltip term_id="part" text="part" >}} you want to add the fragment to.
-
-Select **Insert fragment**.
-Now, you can see the available fragments to add.
-Select [`ViamRover2-2024-rpi5`](https://app.viam.com/fragment/11d1059b-eaed-4ad8-9fd8-d60ad7386aa2/json) and click **Insert fragment** again to add the fragment to your machine configuration:
-
-{{}}
-
-Click **Save** in the upper right corner of the page to save your new configuration.
-
-The fragment adds the following components to your machine's JSON configuration:
-
-- A [board component](/components/board/) named `local` representing the Raspberry Pi.
-- Two [motors](/components/motor/gpio/) (`right` and `left`)
- - The configured pin numbers correspond to where the motor drivers are connected to the board.
-- Two [encoders](/components/encoder/single/), one for each motor
-- A wheeled [base](/components/base/), an abstraction that coordinates the movement of the right and left motors
- - Width between the wheel centers: 356 mm
- - Wheel circumference: 381 mm
- - Spin slip factor: 1
-- A webcam [camera](/components/camera/webcam/)
-- An [accelerometer](https://github.com/viam-modules/tdk-invensense/)
-- A [power sensor](https://github.com/viam-modules/texas-instruments/)
-
-For information about how to configure components yourself when you are not using the fragment, click the links on each component above.
-To see the configured pin numbers and other values specific to this fragment, [view it in the app](https://app.viam.com/fragment?id=7c413f24-691d-4ae6-a759-df3654cfe4c8).
-
-{{% /tab %}}
-{{% tab name="Viam Rover 2 (RPi 4)" %}}
-
-Navigate to your machine in the [Viam app](https://app.viam.com/robots).
-In the left-hand menu of the **CONFIGURE** tab, click the **+** (Create) icon next to the machine {{< glossary_tooltip term_id="part" text="part" >}} you want to add the fragment to.
-
-Select **Insert fragment**.
-Now, you can see the available fragments to add.
-Select [`ViamRover2-2024-rpi4-a`](https://app.viam.com/fragment/7c413f24-691d-4ae6-a759-df3654cfe4c8/json) and click **Insert fragment** again to add the fragment to your machine configuration:
-
-{{}}
-
-Click **Save** in the upper right corner of the page to save your new configuration.
-
-The fragment adds the following components to your machine's JSON configuration:
-
-- A [board component](/components/board/) named `local` representing the Raspberry Pi.
-- Two [motors](/components/motor/gpio/) (`right` and `left`)
- - The configured pin numbers correspond to where the motor drivers are connected to the board.
-- Two [encoders](/components/encoder/single/), one for each motor
-- A wheeled [base](/components/base/), an abstraction that coordinates the movement of the right and left motors
- - Width between the wheel centers: 356 mm
- - Wheel circumference: 381 mm
- - Spin slip factor: 1
-- A webcam [camera](/components/camera/webcam/)
-- An [accelerometer](https://github.com/viam-modules/tdk-invensense/)
-- A [power sensor](https://github.com/viam-modules/texas-instruments/)
-
-For information about how to configure components yourself when you are not using the fragment, click the links on each component above.
-To see the configured pin numbers and other values specific to this fragment, [view it in the app](https://app.viam.com/fragment?id=7c413f24-691d-4ae6-a759-df3654cfe4c8).
-
-{{% /tab %}}
-{{% tab name="Viam Rover 1 (RPi 4)" %}}
-
-Navigate to your machine in the [Viam app](https://app.viam.com/robots).
-In the left-hand menu of the **CONFIGURE** tab, click the **+** (Create) icon next to the machine {{< glossary_tooltip term_id="part" text="part" >}} you want to add the fragment to.
-
-Select **Insert fragment**.
-Now, you can see the available fragments to add.
-Select [`ViamRover202210b`](https://app.viam.com/fragment/3e8e0e1c-f515-4eac-8307-b6c9de7cfb84/json) and click **Insert fragment** again to add the fragment to your machine configuration:
-
-{{}}
-
-Click **Save** in the upper right corner of the page to save your configuration.
-
-The fragment adds the following components to your machine's JSON configuration:
-
-- A [board component](/components/board/) named `local` representing the Raspberry Pi
- - An I2C bus for connection to the accelerometer.
-- Two [motors](/components/motor/gpio/) (`right` and `left`)
- - The configured pin numbers correspond to where the motor drivers are connected to the board.
-- Two [encoders](/components/encoder/single/), one for each motor
-- A wheeled [base](/components/base/), an abstraction that coordinates the movement of the right and left motors
- - Width between the wheel centers: 260 mm
- - Wheel circumference: 217 mm
- - Spin slip factor: 1
-- A webcam [camera](/components/camera/webcam/)
-- An [accelerometer](https://github.com/viam-modules/analog-devices/)
-
-{{% alert title="Info" color="info" %}}
-
-This particular motor driver has pins labeled "ENA" and "ENB."
-Typically, this would suggest that they should be configured as enable pins, but on this specific driver these function as PWM pins, so we configure them as such.
-
-{{% /alert %}}
-
-For information about how you would configure a component yourself if you weren't using the fragment, click the links on each component above.
-To see the configured pin numbers and other values specific to this fragment, [view it in the app](https://app.viam.com/fragment?id=3e8e0e1c-f515-4eac-8307-b6c9de7cfb84).
-
-{{% /tab %}}
-{{% tab name="Viam Rover 2 (Jetson Nano)" %}}
-
-Navigate to your machine in the [Viam app](https://app.viam.com/robots).
-In the left-hand menu of the **CONFIGURE** tab, click the **+** (Create) icon next to the machine {{< glossary_tooltip term_id="part" text="part" >}} you want to add the fragment to.
-
-Select **Insert fragment**.
-Now, you can see the available fragments to add.
-Select [`ViamRover2-2024-jetson-nano-a`](https://app.viam.com/fragment/747e1f43-309b-4311-b1d9-1dfca45bd097/json) and click **Insert fragment** again to add the fragment to your machine configuration.
-
-{{}}
-
-Click **Save** in the upper right corner of the page to save your new configuration.
-
-The fragment adds the following components to your machine's JSON configuration:
-
-- A [board component](/components/board/) named `local` representing the Jetson.
-- Two [motors](/components/motor/gpio/) (`right` and `left`)
- - The configured pin numbers correspond to where the motor drivers are connected to the board.
-- Two [encoders](/components/encoder/single/), one for each motor
-- A wheeled [base](/components/base/), an abstraction that coordinates the movement of the right and left motors
- - Width between the wheel centers: 356 mm
- - Wheel circumference: 381 mm
- - Spin slip factor: 1
-- A webcam [camera](/components/camera/webcam/)
-- An [accelerometer](https://github.com/viam-modules/tdk-invensense/)
-- A [power sensor](https://github.com/viam-modules/texas-instruments/)
-
-For information about how to configure components yourself when you are not using the fragment, click the links on each component above.
-To see the configured pin numbers and other values specific to this fragment, [view it in the app](https://app.viam.com/fragment?id=747e1f43-309b-4311-b1d9-1dfca45bd097).
-
-{{% /tab %}}
-{{% tab name="Viam Rover 2 (Jetson Orin Nano)" %}}
-
-Navigate to your machine in the [Viam app](https://app.viam.com/robots).
-In the left-hand menu of the **CONFIGURE** tab, click the **+** (Create) icon next to the machine {{< glossary_tooltip term_id="part" text="part" >}} you want to add the fragment to.
-
-Select **Insert fragment**.
-Now, you can see the available fragments to add.
-Select [`ViamRover2-2024-nano-orin-a`](https://app.viam.com/fragment/6208e890-8400-4197-bf0f-e8ddeca4e157/json) and click **Insert fragment** again to add the fragment to your machine configuration:
-
-{{}}
-
-Click **Save** in the upper right corner of the page to save your new configuration.
-
-The fragment adds the following components to your machine's JSON configuration:
-
-- A [board component](/components/board/) named `local` representing the Jetson.
-- Two [motors](/components/motor/gpio/) (`right` and `left`)
- - The configured pin numbers correspond to where the motor drivers are connected to the board.
-- Two [encoders](/components/encoder/single/), one for each motor
-- A wheeled [base](/components/base/), an abstraction that coordinates the movement of the right and left motors
- - Width between the wheel centers: 356 mm
- - Wheel circumference: 381 mm
- - Spin slip factor: 1
-- A webcam [camera](/components/camera/webcam/)
-- An [accelerometer](https://github.com/viam-modules/tdk-invensense/)
-- A [power sensor](https://github.com/viam-modules/texas-instruments/)
-
-For information about how to configure components yourself when you are not using the fragment, click the links on each component above.
-To see the configured pin numbers and other values specific to this fragment, [view it in the app](https://app.viam.com/fragment?id=6208e890-8400-4197-bf0f-e8ddeca4e157).
-
-{{% /tab %}}
-{{< /tabs >}}
-
-## See the components on the configuration page
-
-Adding a fragment to your machine adds the configuration to your machine.
-The components and services included in the fragment will now appear as cards on the **CONFIGURE** tab, along with a card for your fragment:
-
-{{}}
-
-## Modify the config
-
-The fragment you added is read-only, but if you need to modify your rover's config you can [overwrite sections of the fragment](/how-tos/one-to-many/#modify-a-fragment).
-
-## Next steps
-
-After you have configured your rover, follow one of these tutorials:
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{% card link="/tutorials/services/navigate-with-rover-base/" %}}
-{{< /cards >}}
diff --git a/docs/appendix/try-viam/rover-resources/rover-tutorial/_index.md b/docs/appendix/try-viam/rover-resources/rover-tutorial/_index.md
deleted file mode 100644
index 0718c9ad67..0000000000
--- a/docs/appendix/try-viam/rover-resources/rover-tutorial/_index.md
+++ /dev/null
@@ -1,434 +0,0 @@
----
-title: "Unbox and Set Up your Viam Rover 2"
-linkTitle: "Unbox and Set Up your Viam Rover 2"
-weight: 10
-type: "docs"
-tags: ["rover", "tutorial"]
-images: ["/appendix/try-viam/rover-resources/viam-rover-2/box-contents.png"]
-imageAlt: "A Viam Rover 2 in a box"
-description: "A list of the contents of the Viam Rover 2 kit, instructions for wiring your rover, and links for additional hardware."
-no_list: true
-aliases:
- - "/get-started/try-viam/rover-resources/rover-tutorial"
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-{{% alert title="Tip" color="tip" %}}
-Another version of the Viam Rover was sold until January 2024.
-If you have purchased a Viam Rover 1, follow [these instructions](/appendix/try-viam/rover-resources/rover-tutorial-1/) instead.
-{{% /alert %}}
-
-The [Viam Rover 2](https://www.viam.com/resources/rover) arrives preassembled with two encoded motors with suspension, a webcam with a microphone unit, a 6 axis IMU, power management and more.
-It is primarily designed for use with a Raspberry Pi 4.
-You can use it with [other types of boards](#motherboard) with some additional setup.
-
-{{< alert title="Important" color="note" >}}
-You must purchase the following hardware separately:
-
-- A Raspberry Pi 4
-- Four 18650 batteries (with charger) or a RC type battery with dimensions no greater than 142mm x 47mm x 60mm (LxWxH) (with charger)
-- A MicroSD card and an adapter/reader
- {{< /alert >}}
-
-This guide covers what's inside the kit and provides instructions for [setting up your rover](#setup).
-
-{{< alert title="Note" color="note" >}}
-The design for this rover is open source.
-Find the details on [GitHub](https://github.com/viamrobotics/Viam-Rover-2).
-{{< /alert >}}
-
-## What's inside the kit
-
-1. One assembled Viam Rover.
-
- {{}}
-
-1. Four M2.5 screws for mounting your Raspberry Pi.
-
- {{}}
-
-1. Two spare stiffer suspension springs.
- You can swap them out with the springs that come with the rover if you need stiffer suspension for higher payload applications.
-
- {{}}
-
-1. Three different Allen wrenches (1.5 mm, 2 mm, and 2.5 mm) to unscrew the top and mount the Raspberry Pi.
-
- {{}}
-
-1. Four extenders to increase the height of the rover to house larger internal single-board computers (such as a Jetson Orin Nano).
-
- {{}}
-
-1. Ribbon cable for connecting the Raspberry Pi 4 to the Viam Rover 2 printed circuit board.
-
- {{}}
-
-All together, your kit looks like this:
-
-{{}}
-
-## Rover components
-
-### Dual drive motors with suspension and integrated motor encoders
-
-{{}}
-
-The motors come with integrated encoders.
-For information on encoders, see [Encoder Component](/components/encoder/).
-For more information on encoded DC motors, see [Encoded Motors](/components/motor/encoded-motor/).
-
-The kit also includes stiffer suspension springs that you can substitute for the ones on the rover.
-Generally, a stiff suspension helps with precise steering control.
-In contrast, a soft suspension allows the wheels to move up and down to absorb small bumps on the rover's path.
-
-### Motor driver
-
-{{}}
-
-The kit comes with an L298N driver dual H-Bridge DC motor driver.
-L298 is a high voltage and high current motor drive chip, and H-Bridge is typically used to control the rotating direction and speed of DC motors.
-
-### 720p webcam with integrated microphone
-
-{{}}
-
-The webcam that comes with the kit is a standard USB camera device and the rover has a custom camera mount for it.
-For more information, see [Camera Component](/components/camera/).
-
-### Motherboard
-
-{{}}
-
-The Viam Rover 2 uses a motherboard to which all ancillary components (buck converter, motor driver, IMU, INA219) are mounted.
-This board includes an auxiliary Raspberry Pi 4 pinout that dupont connectors can be connected to, an auxiliary power input terminal, 5V, 3.3V and Ground pins.
-
-The motherboard also incorporates hole patterns for the following alternative single-board computers:
-
-- Jetson Nano and Orin Nano
-- Rock Pi S
-- Raspberry Pi Zero 2W
-- Raspberry Pi 5
-- Orange Pi Zero 2
-
-See [Alternative Board Configurations](#alternative-board-configurations) for a diagram of this.
-Note that these boards require additional parts to be purchased and will not work out of the box with the Viam Rover 2.
-
-### 6DOF IMU
-
-{{}}
-
-The MPU6050 sensor is a digital 6-axis accelerometer or gyroscope that can read acceleration and angular velocity.
-You can access it through the I2C digital interface.
-You configure it with Viam on your machine as a [movement sensor](https://github.com/viam-modules/tdk-invensense/).
-
-### INA219 power monitoring unit
-
-{{}}
-
-The INA219 unit measures the voltage and current from the power supply.
-You can use it to measure battery life status and power consumption.
-It connects to the Raspberry Pi 4 through the I2C bus.
-You configure it with Viam on your machine as a [power sensor](https://github.com/viam-modules/texas-instruments/).
-
-### DC-DC 5V converter
-
-{{}}
-
-The DC-to-DC power converter, or, buck converter, steps down voltage from its input to its output.
-The OKY3502-4 has a USB output that can provide an additional 5V supply to auxiliary components.
-
-### Switch and low voltage cutoff circuit
-
-{{}}
-
-A slide switch is connected to the rover.
-Use it to turn the power on and off.
-
-{{}}
-
-Mounted above the switch is a low voltage cutoff circuit that can be set to turn off power to the rover when the input voltage drops below a pre-set threshold.
-This can be helpful for preventing batteries fully discharging which can damage lithium ion batteries.
-
-### Battery holders
-
-The Viam Rover 2 comes with two battery holder options.
-The rover nominally operates with four 18650 batteries, but a higher capacity RC-type battery can be mounted into the rear of the rover.
-
-{{% alert title="Note" color="note" %}}
-With either battery option, you must purchase a charger separately.
-{{% /alert %}}
-
-#### 18650 battery pack
-
-{{}}
-
-18650 batteries are the nominal power supply recommended for use with the Viam Rover 2.
-An 18650 battery is a lithium-ion rechargeable battery.
-We recommend the button-top type, though either button or flat top can work.
-Any brand is suitable as long as you comply with the battery safety requirements.
-
-#### Mount for RC-type battery
-
-{{}}
-
-You can mount a larger capacity RC-type battery into the rover.
-You must wire the appropriate connector into the switch circuit.
-
-RC-batteries are lithium-ion rechargeable batteries.
-Caution should always be taken when using such batteries, always comply with the battery safety requirements.
-Check the [safety](#safety) section for more information.
-
-## Safety
-
-Read all instructions fully before using this product.
-
-This product is not a toy and is not suitable for children under 12.
-
-Switch the rover off when not in use.
-
-{{< alert title="Warning" color="warning" >}}
-Lithium-ion batteries may pose a flammable hazard.
-This product requires four 18650 lithium-ion batteries OR an RC-type battery.
-DO NOT connect multiple power sources simultaneously.
-Refer to the battery manufacturer’s operating instructions to ensure safe operation of the Viam Rover.
-Dispose of lithium-ion batteries per manufacturer instructions.
-{{< /alert >}}
-
-{{< alert title="Caution" color="caution" >}}
-Damage may occur to the Raspberry Pi and/or Viam Rover if wired incorrectly.
-Refer to the manufacturer’s instructions for correct wiring.
-{{< /alert >}}
-
-Disclaimer: This product is preliminary and experimental in nature, and is provided "AS IS" without any representation or warranty of any kind.
-Viam does not make any promise or warranty that the product will meet your requirements or be error free.
-Some states do not allow the exclusion or disclaimer of implied warranties, so the above exclusions may not apply to you.
-
-## Setup
-
-{{% alert title="Important" color="tip" %}}
-If you wish to use a Jetson Nano or Jetson Orin Nano, follow [this guide](./jetson-rover-setup/) instead.
-{{% /alert %}}
-
-### Install Raspberry Pi OS
-
-{{% alert title="Tip" color="tip" %}}
-If you are using another board, you can skip this step.
-{{% /alert %}}
-
-Install a 64-bit Raspberry Pi OS onto your Pi following our [Raspberry Pi installation guide](/installation/prepare/rpi-setup/).
-Follow all steps as listed, including the final step, [Enable communication protocols](/installation/prepare/rpi-setup/#enable-communication-protocols), which is required to enable [the accelerometer](#6dof-imu) on your rover.
-Once you have installed Raspberry Pi OS and `viam-server`, put your SD card in the slot on your Pi.
-
-### Add the power supply
-
-You can power the Viam Rover 2 using 18650 batteries or RC-type batteries.
-18650 batteries are the nominal power supply recommended for use with the rover, but RC-type batteries are higher capacity.
-
-{{< tabs >}}
-{{% tab name="18650 Batteries" %}}
-
-{{}}
-
-The Viam Rover 2 arrives with the 18650 battery pack wired into the power input terminal block.
-The battery pack works with batteries 67.5 mm in length, but the battery housing includes a spring to accommodate most batteries of that approximate length.
-
-- Turn the rover over so that you can see the battery housing.
-- Place four 18650 batteries (taking care to ensure correct polarity orientation) inside the battery pack to provide power to the rover, which can be turned on and off through the power switch.
-
-{{% alert title="Tip" color="tip" %}}
-Ensure that the batteries are making contact with the terminals inside the battery pack.
-Some shorter batteries might need to be pushed along to ensure that contact is being made.
-{{% /alert %}}
-
-{{% /tab %}}
-{{% tab name="RC-Type Battery" %}}
-
-{{}}
-
-For users who prefer a higher capacity battery option, the Viam Rover 2 can house RC-type batteries that do not exceed the following dimensions:- 142mm x 47mm x 60mm (LxWxH).
-Using a RC-type battery requires some re-wiring of the Viam Rover 2 which should only be undertaken by users who are comfortable handling electrical assemblies.
-Improper configuration of the power supply could result in damage to the battery and poses a fire hazard.
-A 4-S RC-type battery is recommended (14.8V).
-We make no recommendations regarding specific RC battery brands.
-
-To change the rover's power supply configuration for a RC-battery:
-
-1. Ensure the 18650 battery holder contains no batteries
-2. Unscrew the 18650 battery leads from the power input terminal.
- Move these wires out of the way.
-3. Screw in a power lead that matches that of the selected battery.
- Common options include: EC-type connectors, XT-connectors or T-plugs.
- Ensure lead is long enough to reach the battery.
-4. Ensure that the polarity is correct (the polarity is marked on the PCB).
- **Failure to do so may result in permanent damage to your Viam Rover 2 when powered on.**
-5. Ensure that there is no short between the terminals (for example, due to a stray strand of wire). Use a multimeter to check continuity across the terminal to verify this.
- Failure to do so may result in damage to the battery and may pose a fire hazard.
-6. Place the battery in the receptacle between the two caster wheels:
- {{}}
- Connect the battery to the lead that is wired into the power input terminal.
- Although not necessary, slots in the bottom plate of the rover allow a velcro strap to be placed around the battery to secure it.
-
-{{% /tab %}}
-{{< /tabs >}}
-
-{{% alert title="Caution" color="caution" %}}
-DO NOT connect both power supplies at the same time.
-These suggestions are alternative configurations.
-Connecting multiple batteries together may result in damage to the batteries and rover, it may also pose a fire hazard.
-{{% /alert %}}
-
-### Configure the low voltage cutoff circuit
-
-Now that you have connected your power supply to your rover, you need to configure the [low voltage cutoff circuit](#switch-and-low-voltage-cutoff-circuit).
-You must configure two settings:
-
-1. The low voltage cutoff
-2. The reconnect voltage
-
-The reconnect voltage is the voltage increment above the cutoff point that is needed for the power to reconnect.
-For both 18650 and RC-type battery inputs, the nominal voltage is 14.8V, so you should set the low voltage threshold to 14.7.
-You can adjust this value if using a battery that has an alternative nominal voltage.
-
-To set the low voltage cutoff and reconnect voltage:
-
-1. Turn on the circuit using the switch.
- The LED indicator should indicate a current voltage level of 14.8-16V depending on the battery charge status:
-
- {{}}
-
-2. Hold down the left button until the LED display starts flashing with the low cutoff value.
- The factory default low cutoff value is 12V.
-3. Use the left (+) and right (-) buttons to set the voltage to 14.7V (or whatever you want the cutoff to be).
-4. Wait for the indicator to stop flashing.
-5. Hold down the right button until the LED display starts flashing with the reconnect voltage value. The factory default reconnect voltage is 2.0V.
-6. Use the left (+) and right (-) buttons to set the reconnect voltage to 0.2V.
-7. Wait for the indicator to stop flashing.
-
-Your voltage cutoff circuit is now configured.
-When the voltage drops below 14.8V (or reaches the cutoff point you chose), a relay will disconnect the motherboard.
-A minimum voltage of 14.9V will be needed to reconnect the power (that is, after charging the batteries).
-
-### Connect the ribbon cable, Pi, and camera
-
-{{% alert title="Tip" color="tip" %}}
-If you are using another board, follow the instructions in [Alternative board configurations](#alternative-board-configurations) in place of this step.
-{{% /alert %}}
-
-To be able to attach the Raspberry Pi, unscrew the top of the rover with the biggest Allen key.
-Then use the smallest Allen key and the provided M2.5 screws to attach the Raspberry Pi to your rover through the standoffs on the motherboard.
-The Raspberry Pi 4 should be mounted such that the USB ports are to the right, as viewed from above.
-
-Use the ribbon cable to connect the Raspberry Pi 4 to the motherboard.
-The ribbon cable comes connected to the motherboard out of the box, wrap it over the top of the Raspberry Pi 4 and connect with the GPIO pins as shown:
-
-{{}}
-
-{{}}
-
-Also, connect the webcam's USB lead to any USB port on your Pi.
-
-Assuming you are using a Raspberry Pi 4, you can skip the following section and move to [Screw the top plate back on and switch the rover on](#screw-the-top-plate-back-on-and-switch-the-rover-on).
-
-### Alternative board configurations
-
-This guide assumes you are using a Raspberry Pi 4, but you can use [different boards](#motherboard) with your Viam Rover 2 with some modifications while attaching the boards.
-
-{{% alert title="Tip" color="tip" %}}
-If you are using a Jetson board, you should be following [this guide](./jetson-rover-setup/).
-{{% /alert %}}
-
-Reference the appropriate alternative hole pattern provided on the motherboard:
-
-{{}}
-
-Detach the motherboard, unscrew the standoffs, and move them to the correct holes.
-Then, use the smallest Allen key and the provided M2.5 screws to attach your board to your rover through these standoffs.
-
-{{< expand "Raspberry Pi Zero 2W" >}}
-If you are using a Raspberry Pi Zero 2W, you should be able to connect your ribbon cable straight to the board.
-If not, you will have to take off the ribbon cable and use [dupont connectors](https://www.amazon.com/IWISS-1550PCS-Connector-Headers-Balancer/dp/B08X6C7PZM/) to wire a connection from the motherboard to the single-board computer's GPIO pins.
-{{< /expand >}}
-
-{{< expand "Raspberry Pi 5" >}}
-If you are using a Raspberry Pi 5, use the same screw placements as for the Raspberry Pi 4.
-The hardware setup is the same.
-The only difference is in the [configuration](/appendix/try-viam/rover-resources/rover-tutorial-fragments/).
-{{< /expand >}}
-
-Then connect the webcam's USB lead to any USB port on your board.
-
-If you need to increase the height of your rover to accommodate your board being larger than a Raspberry Pi 4, place the [height extender standoffs](#whats-inside-the-kit) now.
-
-### Screw the top plate back on and switch the rover on
-
-Screw the top plate back on with the biggest Allen key and use the power switch to turn the rover on.
-Wait a second for the low voltage cutoff relay to trip and provide power to the rover motherboard.
-If the Pi has power, the lights on the Raspberry Pi will light up.
-
-### Enable I2C on your Pi
-
-Enable the I2C protocol on your Pi to get readings from the power sensor when controlling your rover.
-
-1. SSH into your Pi.
- Launch the configuration tool by running the following command:
-
- ```sh {class="command-line" data-prompt="$"}
- sudo raspi-config
- ```
-
-2. Use your keyboard to select **Interface Options**, and press return.
- Select **I2C** enabled.
-
-3. Then, to apply the changes, restart your Raspberry Pi if it hasn't already prompted you to do so.
-
- ```sh {class="command-line" data-prompt="$"}
- sudo reboot
- ```
-
-### Control your rover on the Viam app
-
-If you followed the instructions in the [Pi installation guide](/installation/prepare/rpi-setup/), you should have already made an account on the [Viam app](https://app.viam.com), installed `viam-server` on the board, and added a new machine.
-
-If not, add a new machine in the [Viam app](https://app.viam.com) and follow the {{< glossary_tooltip term_id="setup" text="setup instructions" >}} until your machine is connected.
-
-To configure your rover so you can start driving it, [add a Viam Rover 2 Fragment to your machine](/appendix/try-viam/rover-resources/rover-tutorial-fragments/).
-
-## Next steps
-
-Before you can use your Viam rover with the Viam platform you need to configure your rover:
-
-{{< cards >}}
-{{% card link="/appendix/try-viam/rover-resources/rover-tutorial-fragments/" %}}
-{{< /cards >}}
-
-After you have configured your rover, follow one of these tutorials:
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{% card link="/tutorials/services/navigate-with-rover-base/" %}}
-{{< /cards >}}
-
-### Extensibility
-
-Due to the aluminum chassis and its expandable mounting features, you can extend the Viam Rover.
-With it, you can customize your rover by mounting additional sensors, lidar, robot arms, or other components.
-The following are just a few ideas, but you can expand or modify the rover kit with any components you want:
-
-- For GPS navigation, we support NMEA (using serial and I2C) and RTK.
- Make and model don't make a difference as long as you use these protocols.
- See [Movement Sensor Component](/components/movement-sensor/) for more information.
-- For [LiDAR laser range scanning](/services/slam/cartographer/), we recommend RPlidar (including A1, which is a sub-$100 LIDAR).
-- For robot arms, we tried the [Yahboom DOFBOT robotics arm](https://category.yahboom.net/products/dofbot-jetson_nano) with success.
-
-### Mount an RPlidar to the rover
-
-If you are mounting an RPlidar to your rover, be sure to position the RPlidar so that it faces forward in the direction of travel, facing in the same direction as the included webcam.
-For example, if you are using the [RPlidar A1](https://www.slamtec.com/en/Lidar/A1) model, mount it to the Rover so that the pointed end of the RPlidar mount housing points in the direction of the front of the Rover.
-This ensures that the generated {{< glossary_tooltip term_id="slam" text="SLAM" >}} map is oriented in the expected direction relative to the Rover, with the top of the generated map corresponding to the direction the RPlidar is facing when you initiate mapping.
-
-If you need a mount plate for your RPlidar A1 model, you can 3D print an adapter plate using the following:
-
-- [RPlidar A1 adapter STL](https://github.com/viamrobotics/Viam-Rover-2/blob/main/CAD/RPIidar_adapter_v2.STL)
diff --git a/docs/appendix/try-viam/rover-resources/rover-tutorial/jetson-rover-setup.md b/docs/appendix/try-viam/rover-resources/rover-tutorial/jetson-rover-setup.md
deleted file mode 100644
index 189e228db6..0000000000
--- a/docs/appendix/try-viam/rover-resources/rover-tutorial/jetson-rover-setup.md
+++ /dev/null
@@ -1,168 +0,0 @@
----
-title: "Set up your Rover 2 with a Jetson"
-linkTitle: "Set Up your Rover 2 with a Jetson"
-weight: 10
-type: "docs"
-tags: ["rover", "tutorial"]
-images: ["/appendix/try-viam/rover-resources/viam-rover-2/box-contents.png"]
-imageAlt: "A Viam Rover 2 in a box"
-description: "Instructions for setting up a Viam Rover 2 with a Jetson Nano or Jetson Orin Nano."
-aliases:
- - /get-started/try-viam/rover-resources/rover-tutorial/jetson-rover-setup/
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-The [Viam Rover 2](https://www.viam.com/resources/rover) arrives preassembled with two encoded motors with suspension, a webcam with a microphone unit, a 6 axis IMU, power management and more.
-It is primarily designed for use with a Raspberry Pi 4, but you can use it with a larger Jetson board with some additional setup.
-
-This guide provides supplemental instructions for setting up your rover with a Jetson Nano.
-
-{{< tabs >}}
-{{% tab name="Jetson Nano" %}}
-
-{{% alert title="Important" color="tip" %}}
-You must purchase the following hardware separately:
-
-- Four 18650 batteries (with charger) or a RC type battery with dimensions no greater than 142mm x 47mm x 60mm (LxWxH) (with charger)
-- A MicroSD card and an adapter/reader
-- A longer 40 pin ribbon cable: female-female
-- 4 25 mm female-female standoffs
-- WiFi board: either [a board that directly interfaces with the Nano](https://www.amazon.com/Wireless-AC8265-Wireless-Developer-Support-Bluetooth/dp/B07V9B5C6M/) or [a USB based device](https://www.amazon.com/wireless-USB-WiFi-Adapter-PC/dp/B07P5PRK7J/)
-- Electrical tape
-
-The ribbon cable you purchase must meet these requirements:
-
-- Female-female
-- 2.54 mm spacing
-- Both connectors facing the same direction
-- Pin continuity order to be 12-12
-- Recommended length ~200 mm
- {{% /alert %}}
-
-## Safety
-
-Read all instructions fully before using this product.
-
-This product is not a toy and is not suitable for children under 12.
-
-Switch the rover off when not in use.
-
-{{< alert title="Warning" color="warning" >}}
-Lithium-ion batteries may pose a flammable hazard.
-This product requires four 18650 lithium-ion batteries OR an RC-type battery.
-DO NOT connect multiple power sources simultaneously.
-Refer to the battery manufacturer’s operating instructions to ensure safe operation of the Viam Rover.
-Dispose of lithium-ion batteries per manufacturer instructions.
-{{< /alert >}}
-
-{{< alert title="Caution" color="caution" >}}
-Damage may occur to the board and/or Viam Rover if wired incorrectly.
-Refer to the manufacturer’s instructions for correct wiring.
-{{< /alert >}}
-
-Disclaimer: This product is preliminary and experimental in nature, and is provided "AS IS" without any representation or warranty of any kind.
-Viam does not make any promise or warranty that the product will meet your requirements or be error free.
-Some states do not allow the exclusion or disclaimer of implied warranties, so the above exclusions may not apply to you.
-
-## Setup
-
-1. Install the WiFi board/device on the Nano. Follow the manufacturer's instructions to do so.
-2. Power the Jetson Nano with a power supply and [prepare the device and install `viam-server`](/installation/prepare/jetson-nano-setup/).
-3. Switch back to the main guide and complete these two steps:
- [Add the power supply](/appendix/try-viam/rover-resources/rover-tutorial/#add-the-power-supply) and [Configure the low-voltage cutoff circuit](/appendix/try-viam/rover-resources/rover-tutorial/#configure-the-low-voltage-cutoff-circuit).
-4. Unscrew the top of the rover with the biggest Allen key.
-5. Take the [height extenders](/appendix/try-viam/rover-resources/rover-tutorial/#whats-inside-the-kit) provided in your kit.
- Apply them to the rover chassis posts.
-6. Unscrew the standoffs in the motherboard and relocate them to the Jetson board hole pattern: {{}}
-7. Connect the ribbon cable to the motherboard and Jetson Nano.
- The ribbon cable needs to be routed towards the front of the rover and flip back to the pins on the Jetson Nano, as pictured: {{}}
-8. Use the smallest Allen key and the provided M2.5 screws to attach your board to your rover through these standoffs. The USB ports should be facing the left-hand side of the rover, when viewed from above: {{}}
-9. Connect the webcam's USB lead to any USB port on your board.
-10. Flip the power switch to turn your rover on.
-
-{{% /tab %}}
-{{% tab name="Jetson Orin Nano" %}}
-
-{{% alert title="Important" color="tip" %}}
-You must purchase the following hardware separately:
-
-- A 4S RC type battery with dimensions no greater than 142mm x 47mm x 60mm (LxWxH) (with charger)
-- A MicroSD card and an adapter/reader
-- A longer ribbon cable: female-female (ensure that the contacts are correct)
-- 4 25 mm female-female standoffs
-- WiFi board: either [a board that directly interfaces with the Nano](https://www.amazon.com/Wireless-AC8265-Wireless-Developer-Support-Bluetooth/dp/B07V9B5C6M/) or [a USB based device](https://www.amazon.com/wireless-USB-WiFi-Adapter-PC/dp/B07P5PRK7J/)
-- A wired DC jack connector with the same polarity as the Jetson Orin Nano power input
-- Electrical tape
-
-The ribbon cable you purchase must meet these requirements:
-
-- Female-female
-- 2.54 mm spacing
-- Both connectors facing the same direction
-- Pin continuity order to be 12-12
-- Recommended length ~200 mm
- {{% /alert %}}
-
-## Safety
-
-Read all instructions fully before using this product.
-
-This product is not a toy and is not suitable for children under 12.
-
-Switch the rover off when not in use.
-
-{{< alert title="Warning" color="warning" >}}
-Lithium-ion batteries may pose a flammable hazard.
-This product requires four 18650 lithium-ion batteries OR an RC-type battery.
-DO NOT connect multiple power sources simultaneously.
-Refer to the battery manufacturer’s operating instructions to ensure safe operation of the Viam Rover.
-Dispose of lithium-ion batteries per manufacturer instructions.
-{{< /alert >}}
-
-{{< alert title="Caution" color="caution" >}}
-Damage may occur to the Jetson Orin Nano and/or Viam Rover if wired incorrectly.
-Refer to the manufacturer’s instructions for correct wiring.
-{{< /alert >}}
-
-Disclaimer: This product is preliminary and experimental in nature, and is provided "AS IS" without any representation or warranty of any kind.
-Viam does not make any promise or warranty that the product will meet your requirements or be error free.
-Some states do not allow the exclusion or disclaimer of implied warranties, so the above exclusions may not apply to you.
-
-## Setup
-
-1. Power the Jetson Orin Nano with a power supply and [prepare the device and install `viam-server`](/installation/prepare/jetson-nano-setup/).
-2. Switch back to the main guide and complete these two steps:
- [Add the power supply](/appendix/try-viam/rover-resources/rover-tutorial/#add-the-power-supply) and [Configure the low-voltage cutoff circuit](/appendix/try-viam/rover-resources/rover-tutorial/#configure-the-low-voltage-cutoff-circuit).
-3. Unscrew the top of the rover with the biggest Allen key.
-4. Take the [height extenders](/appendix/try-viam/rover-resources/rover-tutorial/#whats-inside-the-kit) provided in your kit.
- Apply them to the rover chassis posts.
-5. Unscrew the standoffs in the motherboard and relocate them to the Jetson board hole pattern: {{}}
-6. **IMPORTANT:** Disconnect the 5V buck converter. Unlike other boards, the Jetson Orin Nano requires a 7-20V input, which means that the board must be powered directly from the battery.
- **Before commencing, ensure that everything is powered off.**
- It is recommended that you clip the buck converter wires completely and place electrical tape over the exposed contacts, as pictured:
- {{}}
- {{}}
-7. Connect the ribbon cable to the motherboard and Jetson Orin Nano.
-8. Use the smallest Allen key and the provided M2.5 screws to attach your board to your rover through these standoffs. The USB ports should be facing the left-hand side of the rover, when viewed from above: {{}}
-9. Connect a WiFi adapter or a board that directly interfaces to the underside of the Jetson Orin Nano.
-10. Connect the webcam's USB lead to any USB port on your board.
-11. Flip the power switch to turn your rover on.
-
-{{% /tab %}}
-{{< /tabs >}}
-
-### Control your rover on the Viam app
-
-If you followed the instructions in the [Jetson installation guide](/installation/prepare/jetson-nano-setup/), you should have already made an account on the [Viam app](https://app.viam.com), installed `viam-server` on the board, and added a new machine.
-
-To configure your rover so you can start driving it, [add a Viam Rover 2 Fragment to your machine](/appendix/try-viam/rover-resources/rover-tutorial-fragments/).
-
-## Next steps
-
-After adding the appropriate fragment, follow one of these tutorials with your borrowed or owned rover:
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{< /cards >}}
diff --git a/docs/appendix/try-viam/try-viam-tutorial.md b/docs/appendix/try-viam/try-viam-tutorial.md
deleted file mode 100644
index 80d34339c2..0000000000
--- a/docs/appendix/try-viam/try-viam-tutorial.md
+++ /dev/null
@@ -1,235 +0,0 @@
----
-title: "Control A Rented Viam Rover"
-linkTitle: "Control A Rented Viam Rover"
-weight: 39
-type: "docs"
-description: "Remotely control a Viam Rover located on-site at Viam in New York."
-images: ["/appendix/try-viam/rover-resources/viam-rover/rover-front.jpg"]
-imageAlt: "The front of the assembled Viam Rover"
-tags: ["try viam", "app"]
-no_list: true
-draft: true
-aliases:
- - "/try-viam/try-viam-tutorial/"
- - "/get-started/try-viam/try-viam-tutorial/"
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-_Try Viam_ is a way to try out the Viam platform without setting up any hardware yourself.
-You can take over a Viam Rover in our robotics lab to play around!
-
-The rental rover is made up of a chassis with a Raspberry Pi 4B single-board computer, two motors, encoders, and a camera.
-The Try Viam area also has an overhead camera to provide a view of the rental rover, allowing you to view its movements in real time.
-
-Watch this tutorial video for a walkthrough of Try Viam, including [how to reserve a Viam Rover](/appendix/try-viam/reserve-a-rover/#using-the-reservation-system), [navigate the Viam platform](/fleet/), and [drive the rover](#control-tab):
-
-{{}}
-
-## **CONTROL** tab
-
-Click on the rover name at the top to go to the rental rover's **CONTROL** tab where you can drive the machine and interact with each of the machine's components.
-
-At the top of the page you can see the randomly assigned name of the rover, the host, and the IP address.
-
-![The top banner of a Try Viam rover machine page. The randomly generated name for this rover is 'silent-forest'](appendix/try-viam/try-viam/bannerinfo.png)
-
-The **CONTROL** tab contains panels for each of the rover's components:
-
-- the base,
-- the left and right motors,
-- the web game pad,
-- the board, and
-- two cameras.
-
-The order of these components may vary.
-
-{{}}
-
-### Base control
-
-The [base component](/components/base/) is the platform that the other parts of a mobile machine attach to.
-
-Click the `viam_base` component to expand the base control pane to reveal the camera feed and driving interfaces.
-
-![The viam_base component panel on the CONTROL tab. The Keyboard Disabled toggle is grey and not yet enabled.](appendix/try-viam/try-viam/initial-base-control.png)
-
-#### Camera views
-
-In the `viam_base` component panel, select the `cam` for the front-facing camera and the `overhead-cam:overheadcam` for an overhead view of your rover.
-We recommend enabling both cameras so you can have a better sense of what's happening in the space.
-
-![The viam_base component panel showing both the 'cam' and 'overheadcam' camera feeds enabled.](appendix/try-viam/try-viam/enable-both-cameras.png)
-
-You can also view and control the camera streams from the individual camera components on the [**CONTROL** page](/cloud/machines/#control).
-
-#### Movement control
-
-To move your rover, click on **viam_base**.
-You can use the **W**, **A**, **S**, and **D** buttons to move forward, turn left, move backwards, and turn right.
-
-If you enable the keyboard toggle, you can also control the rover's movement with the **W**, **A**, **S**, and **D** keys and the arrow keys on your keyboard.
-
-{{% alert title="Tip" color="tip" %}}
-
-Each time you show or hide a camera, **Keyboard Enabled** automatically toggles to **Keyboard Disabled**.
-
-If you change your camera configurations, you must re-enable your keyboard control to control your rover again.
-This behavior is for safety purposes.
-
-{{% /alert %}}
-
-##### Discrete movement control
-
-If you go from the from **Keyboard** to the **Discrete** tab, you can choose between:
-
-- Different movement modes: `Straight` or `Spin`
-- Different movement types: `Continuous` or `Discrete`
-
- In _continuous_ movement mode you can set a speed at which the rover will move indefinitely in the specified direction.
- In _discrete_ movement mode you can set a speed at which to move and a distance to cover before stopping.
-
-- Directions: `Forwards` and `Backwards`.
-
-![The DISCRETE tab of the viam_base component panel. Movement mode, movement type, and direction mode toggles are shown as well as a speed (mm/sec) field and a distance field (the latter of which is greyed out because the movement type toggle is set to continuous instead of discrete movement).](appendix/try-viam/try-viam/discrete.png)
-
-### Camera control
-
-While you can view the camera streams [from the base component panel](#camera-views), you can access more features on each individual [camera component](/components/camera/) panel. In these panels, you can:
-
-- Set the refresh frequency
-- Export screenshots
-- View point cloud data (for machines with depth cameras)
-
-**cam Stream**:
-
-![The front-facing camera panel (for the component named 'cam').](appendix/try-viam/try-viam/cam-panel.png)
-
-**overhead-cam:overheadcam Stream**:
-
-![The overhead camera panel (for the component named 'overhead-cam').](appendix/try-viam/try-viam/overhead-cam-panel.png)
-
-### Motor control
-
-The [motor components](/components/motor/) enable you to move the base.
-The motors are named `left` and `right`, corresponding to their location on the rover base.
-Their initial state is **Idle**.
-You can click on each motor panel and make the motor **RUN** or **STOP**.
-
-![The left and right motor panels on the CONTROL tab.](appendix/try-viam/try-viam/left-right-panels.png)
-
-Run each motor at a different power level to go faster or slower, and toggle rotation directions to go forwards or backwards.
-You can also see their current positions (based on encoder readings) in real time:
-
-![The left motor running at 20% power and forwards and right motor running at 80% power and backwards.](appendix/try-viam/try-viam/motors-running.png)
-
-{{}}
-
-#### Board control
-
-The [board component](/components/board/) is the signal wire hub of a machine which allows you to control the states of individual GPIO pins on the board.
-
-For the Viam Rover, the board component is named `local` and controls a Raspberry Pi on the Viam Rover.
-With it, you can control the states of individual GPIO pins on the board.
-
-![The board panel in the CONTROL tab, including fields to get and set GPIO pin states.](appendix/try-viam/try-viam/board-panel.png)
-
-#### Web gamepad control
-
-The [web gamepad component](/components/input-controller/webgamepad/) is disabled by default, but if you have a compatible gamepad, you can enable the **Enabled** toggle.
-
-## Learn about machine configuration
-
-On the Viam app, navigate to the **Components** subtab, under **CONFIGURE**.
-There you can view the configuration for each component in the machine: attributes, component dependencies, pin assignments, and more.
-
-![The CONFIG tab in Builder mode (as opposed to Raw JSON). The board component panel and right motor panel are visible.](appendix/try-viam/try-viam/config-builder.png)
-
-### Board configuration
-
-The [board component](/components/board/) is the signal wire hub of a machine.
-Configuring a board component allows you to control the states of individual GPIO pins to command the electrical signals sent through and received by the board.
-For the Viam Rover, the board component is a Raspberry Pi with **Name** `local`, **Type** `board`, and **Model** `viam:raspberry-pi:rpi`.
-
-### Encoder configuration
-
-An [encoder](/components/encoder/) is a device that is used to sense angular position, direction and/or speed of rotation.
-In this case, the encoders on the left and right motors are `Lenc` and `Renc` and configure the pins to `le` and `re`.
-
-{{< alert title="Important" color="note" >}}
-When configuring encoded motors for your own robot, you must configure the encoders before the motors because the motors depend on the encoders.
-{{< /alert >}}
-
-![The right encoder config panel with the board attribute set to 'local' and the pins struct containing 'i' set to 're'.](appendix/try-viam/try-viam/right-encoder.png)
-
-### Motor configuration
-
-Both [motors](/components/motor/) on this rover use the model `gpio` which is the model for basic DC motors that are connected to and controlled by the configured board.
-
-The attributes section lists the board the motor is wired to, and since the rover's motors are encoded the user interface also shows the encoded motor attributes: the encoder name, motor ramp rate limit, encoder ticks per rotation, and max RPM limit.
-
-You can click **{}** (Switch to Advanced) on the top right of the component's card to view the attributes field in raw JSON format.
-The attributes pane contains the current JSON configuration for this component.
-Click **Switch to Builder** to return to the default graphical user interface.
-
-### Base configuration
-
-The [base component](/components/base/) is the platform that the other parts of a mobile robot attach to.
-By configuring a base component, the individual components are organized to produce coordinated movement and you gain an interface to control the movement of the whole physical base of the robot without needing to send separate commands to individual motors.
-The base's type is `base` and its model is `wheeled` which configures a robot with wheels on its base, like the Viam Rover.
-The **left** and **right** attributes configure the motors on the left and right side of the rover, which are named `left` and `right`, respectively.
-
-The **Wheel Circumference** (in millimeters) is 217.
-The **Width** is the distance between wheel centerlines, 260mm in this case.
-The **Spin Slip Factor** of 1.76 is used in steering calculations to account for slippage of the wheels against the ground while turning.
-
-![The base configuration panel, showing right and left motors, wheel circumference set to 217, width set to 260mm, and spin slip factor set to 1.76.](appendix/try-viam/try-viam/base-config.png)
-
-### Camera configuration
-
-The [camera component](/components/camera/) configures the webcam that is plugged into the Raspberry Pi of the rover.
-The camera component has the **Type** `camera`, the **Model** `webcam`, and the **Video Path** is `video0`.
-
-For more information on choosing the correct video path, refer to our [webcam documentation](/components/camera/webcam/).
-
-![The video path in the webcam configuration panel is set to 'video0'.](appendix/try-viam/try-viam/camera-config.png)
-
-### Gamepad configuration
-
-The [web gamepad](/components/input-controller/webgamepad/) component has the **Type** `input_controller` and the **Model** `webgamepad`.
-
-![The gamepad configuration panel. No attributes are configured.](appendix/try-viam/try-viam/gamepad-config.png)
-
-If you connect a generic gamepad controller to your computer, you can use it to control your machine.
-
-If you are configuring your own machine, be aware that using the gamepad requires a service.
-To see how the service is configured, navigate to the **Services** section under the **CONFIGURE** tab.
-The **Services** subtab contains the "Base Remote Control" service which uses three attributes:
-
-- **base**: `viam_base`
-- **control_mode**: `joystickControl`
-- **input_controller**: `WebGamepad`
-
-The names for **base** and **input_controller** correspond to the naming scheme from the **Components** tab.
-
-![The base remote control service named 'base_rc' on the Services subtab of the CONFIG tab.](appendix/try-viam/try-viam/base-rc.png)
-
-### Raw JSON
-
-The 'Builder' configuration mode provides a user-friendly, guided experience for you.
-In the background, the Viam app translates the Viam machine configuration into JSON.
-You can view the complete JSON for your rover by clicking on **Raw JSON** at the top left of the **CONFIGURE** tab.
-
-![The CONFIG tab with the mode toggled to Raw JSON. A section of the full raw JSON config is displayed but one would have to scroll to see all of it.](appendix/try-viam/try-viam/raw-json.png)
-
-You can [copy this `JSON` config between rental rovers](/appendix/try-viam/reserve-a-rover/#how-can-i-reuse-my-borrowed-rover).
-
-## Next steps
-
-If you have questions, check out our [FAQ](/appendix/try-viam/reserve-a-rover/) or join our [Discord Community](https://discord.gg/viam), where you can ask questions and meet other people working on robots.
-
-{{< cards >}}
-{{% card link="/how-tos/drive-rover/" %}}
-{{% card link="/how-tos/detect-color/" %}}
-{{% card link="/appendix/try-viam/rover-resources/" %}}
-{{< /cards >}}
diff --git a/docs/cloud/_index.md b/docs/cloud/_index.md
deleted file mode 100644
index cf949ff3c5..0000000000
--- a/docs/cloud/_index.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-title: "Cloud Organization Hierarchy"
-linkTitle: "Cloud Organization Hierarchy"
-weight: 430
-type: "docs"
-description: "Configure, control, debug, and manage your machines from the cloud at app.viam.com on your own or with a team."
-tags: ["fleet management", "cloud", "app"]
-images: ["/fleet/fleet.svg"]
-no_list: true
-menuindent: true
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-Viam fleet management allows you to organize, manage, and control any number of machines alone or in collaboration with others.
-You can manage and control your fleet of {{< glossary_tooltip term_id="machine" text="smart machines" >}} from the [Viam app](https://app.viam.com), using the [CLI](/cli/), or using the [fleet management API](/appendix/apis/fleet/).
-
-## Work with groups of machines
-
-To organize your fleet you use:
-
-
-
-{{< cards >}}
-{{% manualcard link="/cloud/organizations/" %}}
-
-#### Organizations
-
-The highest level grouping, generally used for different companies.
-
-{{% /manualcard %}}
-{{% manualcard link="/cloud/locations/" %}}
-
-#### Locations
-
-A virtual grouping of devices up with up to three levels of nesting that can represent a grouping of machines that are co-located in a building, like a factory, or a grouping of machines that are thousands of miles apart and are grouped together by function or as an organizational unit.
-
-An organization can have multiple locations.
-{{% /manualcard %}}
-{{% manualcard link="/cloud/machines/" %}}
-
-#### Machines
-
-A grouping of {{< glossary_tooltip term_id="component" text="components" >}} and {{< glossary_tooltip term_id="service" text="services" >}} across one {{< glossary_tooltip term_id="part" text="part" >}} or more parts working closely together to complete tasks.
-Each machine resides in a location.
-
-{{% /manualcard %}}
-{{< /cards >}}
-
-
-
-{{}}
-
-
-
-The organization structure enables you to:
-
-- configure groups of machines with reusable {{< glossary_tooltip term_id="fragment" text="fragments" >}} that [configure](/configure/) a set of resources for each machine that uses the fragment.
-- deploy [code packages](/registry/) or [machine learning models](/services/ml/), without manually copying files by uploading it to Viam's cloud and deploying it to your fleet
-- control a machine with code, the app's [**CONTROL** tab](/cloud/machines/#control), or the [Viam mobile app](/fleet/control/#control-interface-in-the-viam-mobile-app)
-- obtain health metrics, such as status, uptime, version, or [logs](machines/#logs)
-- perform debugging
-
-All of this is possible when you are close to your machine, as well as remotely from anywhere in the world.
-
-## Use Viam for collaboration
-
-When you create a Viam account, Viam automatically creates an organization for you.
-You can use this organization as your collaboration hub by inviting collaborators to your organization.
-You can also add additional organizations as desired at any time.
-
-To facilitate collaboration, you can grant individual collaborators or entire organizations granular permissions for individual machines or entire locations.
-This allows you flexibility to manage internal machines, sell devices to external customers and keep managing them, and collaborate with different partners or companies on groups of machines.
-For more information, see [Permissions](/cloud/rbac/#permissions).
-
-### Configuration
-
-When you or your collaborators change the configuration of a machine or a group of machines in the Viam app, `viam-server` automatically synchronizes the configuration and updates the running resources within 15 seconds.
-This means everyone who has access can change a fleet's [configuration](machines/#configure), even while your machines are running.
-
-You can see configuration changes made by yourself or by your collaborators by selecting **History** on the right side of your machine part's card on the **CONFIGURE** tab.
-You can also revert to an earlier configuration from the History tab.
-
-{{< alert title="Simultaneous config edits" color="caution" >}}
-If you edit a config while someone else edits the same config, the person who saves last will overwrite any prior changes that aren't reflected in the new config.
-
-Before editing a config, we recommend you refresh the page to ensure you have all the latest changes.
-{{< /alert >}}
-
-Machine [configuration](machines/#configure) and machine [code](/sdks/) is intentionally kept separate, allowing you to keep track of versioning and debug issues separately.
-
-## Next steps
-
-To learn about configuring and provisioning many machines, see [Deploy a Large Fleet](/fleet/).
-
-To learn about monitoring and remotely controlling the machines in your fleet, see [Control Interface](/fleet/control/).
-
-Check out the following tutorial for an example of organizing a fleet into locations, configuring multiple machines, and syncing data from all of them:
-
-{{< cards >}}
-{{% card link="/tutorials/control/air-quality-fleet/" %}}
-{{< /cards >}}
diff --git a/docs/cloud/account.md b/docs/cloud/account.md
deleted file mode 100644
index 00c22c3bae..0000000000
--- a/docs/cloud/account.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: "Account Management"
-linkTitle: "Accounts"
-weight: 80
-type: "docs"
-description: "Log in and out of your Viam account."
-tags: ["fleet management", "cloud", "app"]
-no_list: true
-aliases:
- - /fleet/account/
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-the [Viam app](https://app.viam.com/) is a web UI for managing and building machines.
-
-## Create account and log In
-
-To get started on the Viam app, you must log in as an authorized user.
-Viam support sign up using Google, GitHub, Apple, and email.
-
-Navigate to [the main page](https://app.viam.com/).
-If you haven't created an account yet, click **Sign Up** to create a new account using your preferred Single Sign On method or your email address and a password.
-If you already have an account, click **Log In** to log in using your Single Sign On credentials or your email address and password.
-
-If you forget your password to the app, click **Forgot password** and enter your email address to obtain instructions to reset your password.
-
-{{< alert title="Info" color="info" >}}
-Accounts created from separate authentication sources are unique to each other.
-{{< /alert >}}
-
-
-
-## Sign out
-
-To log out or sign out of the [Viam app](https://app.viam.com/), click on your profile icon in the upper right corner of your browser window.
-Click **Sign out** to sign out of accessing all organizations, locations, and machines your credentials manage.
diff --git a/docs/cloud/locations.md b/docs/cloud/locations.md
deleted file mode 100644
index 542ad41416..0000000000
--- a/docs/cloud/locations.md
+++ /dev/null
@@ -1,116 +0,0 @@
----
-title: "Manage Locations and Sub-locations"
-linkTitle: "Locations"
-weight: 30
-type: "docs"
-no_list: true
-description: A location is a virtual grouping of machines that allows you to organize machines and manage access to your fleets.
-tags: ["fleet management", "cloud", "app"]
-aliases:
- - /manage/fleet/locations/
- - /fleet/locations/
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-In Viam, every machine belongs to a location.
-A location is a virtual grouping of machines that allows you to organize machines and manage access.
-Generally, a location defines a group of machines that are geographically close to each other.
-If you are familiar with Google Drive, you can think of a location as similar to a folder within a shared drive.
-
-For example, an organization called Good Robots Inc has two warehouses across New York and Oregon.
-Good Robots Inc can organize its machines into two locations based on their physical presence in a warehouse.
-
-You can also use locations as proxies for environments such as "Production" and "Testing" or other groupings.
-Locations do not have to correspond with physical locations.
-
-Each machine you add to Viam belongs to a location.
-Each location belongs to an organization.
-
-{{< alert title="Limit" color="note" >}}
-By default, you can create up to 100 locations in an organization.
-If you need to create more locations, [contact support](mailto:support@viam.com).
-{{< /alert >}}
-
-{{}}
-
-You can access your locations on the Viam app on the **FLEET** tab's [**LOCATIONS** subtab](https://app.viam.com/fleet/locations).
-
-## Add a location
-
-When you create a new organization, Viam automatically creates a new location for you.
-You can create additional locations by typing a new location name in the **New Location** field in the left side navigation bar on the **FLEET** page's [**LOCATIONS** subtab](https://app.viam.com/fleet/locations/) and clicking **Add**.
-
-Click a location's name to display the list of machines associated with that location.
-
-## Create a sub-location
-
-To create a sub-location you must first create the sub-location as a location and then choose a parent location:
-
-1. Create a location and add at least one machine to it.
-2. At the bottom of the location's page, use the **New Parent Location** dropdown to choose a parent location.
-3. Click **Change**.
-
-You can nest locations up to three levels deep.
-
-To move a sub-location to the top level of locations, select **Root** from the **New Parent Location** dropdown and then click **Change**.
-
-## Share a location
-
-A location always belongs to the organization it was created in.
-Members of the organization have access to all locations in the organization by default.
-
-For more information on the permissions the roles assign for each resource, see [Permissions](/cloud/rbac/#locations).
-
-You can share a location beyond its organization by sharing a location with an additional organization:
-
-### Share a location with an additional organization
-
-Share your location with another organization you belong to by selecting the organization from the **Add Organization** dropdown menu and clicking **Share**.
-
-To share your location with an organization you are not a member of, select the location or enter the organization ID (a string like `1ab2c3d1-1234-123a-abcd-abcdef123456`) and click **Share**.
-Members of the org can find the org ID on their org settings page.
-
-{{% alert title="Note" color="info" %}}
-
-Once you share a _nested_ location (sub-location), its parent location cannot be changed.
-
-{{% /alert %}}
-
-#### Remove an organization from a shared location
-
-You can remove any organization except the primary owner from the shared list by clicking the **X** to the right of the location in the shared list.
-
-
-
-#### Rotate a secret key
-
-If you ever need to rotate this key, click on the **Generate Key** button to generate a new key.
-
-Viam supports flexible key rotation with up to two keys in use at one time.
-After generating a new secret key, update all references to the key in your code as soon as possible and then remove the old key.
-
-### Share a location with Viam support
-
-If you request support, you must share your location with the Viam Support team.
-To do so, navigate to the location you need support with and click, **Add Viam support**.
-
-Once you have received support, you can remove Viam Support from your location by clicking **Remove Viam support**.
-
-## Delete a location
-
-You can delete a location that is _empty of machines_ by clicking the trash can icon next to the location name at the top of the page for that location.
-The icon will not appear if there are any machines in the location.
diff --git a/docs/cloud/machines.md b/docs/cloud/machines.md
deleted file mode 100644
index d48e0c91f5..0000000000
--- a/docs/cloud/machines.md
+++ /dev/null
@@ -1,138 +0,0 @@
----
-title: "Manage Machines"
-linkTitle: "Machines"
-weight: 10
-type: "docs"
-description: "A machine is an organizational concept, consisting of either one or multiple parts working closely together to complete tasks."
-tags: ["fleet management", "cloud", "app"]
-images: ["/fleet/app-usage/create-machine.png"]
-aliases:
- - /fleet/robots/
- - /manage/fleet/machines/
- - /fleet/machines/
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-A _machine_ is an organizational concept, consisting of either one {{< glossary_tooltip term_id="part" text="part" >}}, or multiple _parts_ working closely together to complete tasks.
-The machine represents the configuration and entry point for one or more computers (and the components they control) coupled into one logical grouping of parts that work together to complete tasks.
-A machine usually reflects a physical device, from a camera collecting images, to a wheeled rover, or an articulated arm on a factory floor.
-A machine always has a main part that receives client requests, and any number of other parts.
-
-## Add a new machine
-
-Add a new machine in the [Viam app](https://app.viam.com) by clicking **+ Add machine**, providing a name in the **New machine** field and clicking **Add machine** again.
-
-![The 'First Location' page on the Viam app with a new machine name in the New machine field and the Add Machine button next to the field highlighted.](/fleet/app-usage/create-machine.png)
-
-Click the name of a machine to go to that machine's page, where you'll find a variety of tools for working with your machine.
-
-## Navigating the machine page
-
-Next to the machine name, there is an indicator of the machine's status.
-Click on the **status** dropdown to open a menu with information about each {{< glossary_tooltip term_id="part" text="part" >}} of your machine.
-Once you connect to the `viam-server` instance on a part, this display includes its OS, Host, `viam-server` version, IP addresses, and what time it was last online or remote address (if live):
-
-![The machine page with part menu expanded](/fleet/app-usage/machine-page.png)
-
-### Set up a new machine
-
-
-
-To connect to the `viam-server` instance on a part, follow the setup instructions.
-Open the part status dropdown menu in the top left corner of the page, next to the machine's name.
-Click **View setup instructions** to open the setup instructions.
-
-Select your system's architecture and select the version of the {{< glossary_tooltip term_id="RDK" text="RDK" >}} to use.
-Then, follow the instructions on the page to connect and set up your machine.
-
-{{% alert title="Tip" color="tip" %}}
-If your machine is controlled by a microcontroller, install the [**viam-micro-server**](/installation/viam-micro-server-setup/#install-viam-micro-server) instead of full `viam-server`.
-{{% /alert %}}
-
-More in-depth information on installing `viam-server` can be found in our [Installation Guide](/installation/viam-server-setup/#install-viam-server).
-
-Once all parts of your machine are set up and connected to the app, the part status display at the top left corner of the page turns green.
-Now, you can manage your machine with one of four tabs: **CONFIGURE**, **CONTROL**, **LOGS**, and **CONNECT**:
-
-{{}}
-
-### CONFIGURE
-
-The configuration of a machine describes the {{< glossary_tooltip term_id="resource" text="resources" >}} that it has access to.
-When a {{< glossary_tooltip term_id="part" text="machine part" >}} that is managed with the Viam app first comes online, it requests its configuration from the [Viam app](https://app.viam.com).
-Once the machine has a configuration, it caches it locally and can use the configuration for up to 60 days.
-The machine checks for new configurations every 15 seconds and changes its configuration automatically when a new configuration is available.
-
-After connecting your machine, go to the **CONFIGURE** tab, and start adding {{< glossary_tooltip term_id="component" text="components" >}}, {{< glossary_tooltip term_id="service" text="services" >}}, and other {{< glossary_tooltip term_id="resource" text="resources" >}}.
-
-
-
-The Viam app keeps a record of your configuration changes, allowing you to revert to earlier configurations if needed.
-To see the history of the configuration of a machine part, click on **History** on the right side of its card on the **CONFIGURE** tab.
-
-For more information, see the [configuration documentation](/configure/#the-configure-tab).
-
-{{< alert title="Tip" color="tip" >}}
-If you are managing a large fleet, you can use {{< glossary_tooltip term_id="fragment" text="fragments" >}} when [configuring your fleet](/fleet/fragments/).
-{{< /alert >}}
-
-### CONTROL
-
-Once you have configured components and services for your machine, you can visually test and remotely operate them from the **CONTROL** tab in the [Viam app](https://app.viam.com) or the [Viam mobile app](/fleet/control/#control-interface-in-the-viam-mobile-app).
-
-{{}}
-
-You can also switch between different machine parts by selecting the part from the left-hand menu.
-
-For more information, see [Control machines](/fleet/control/).
-
-### LOGS
-
-To make debugging issues with your machines easier, each machine automatically sends its logs to the cloud.
-You can access your logs from the **LOGS** tab in the [Viam app](https://app.viam.com) and filter your logs for specific keywords or log levels:
-
-{{}}
-
-You can click on the part names in the left-hand menu to switch logs between parts. You can also change your timestamp format to ISO or Local depending on your preference.
-
-To view logs in the Viam mobile app:
-
-1. Select an organization clicking on the menu icon in the top left corner and tapping an organization.
-2. Tap the **Locations** tab and tap on a location and then on a machine.
-3. Click the menu button marked "**...**" in the upper right corner.
-4. Click **View Logs**.
-
-### CONNECT
-
-#### Code sample
-
-To start programming your machine, go to the **CONNECT** tab and select the **Code sample** page.
-This has sample code snippets you can copy and paste into your control code to connect to your machine.
-
-{{% snippet "show-secret.md" %}}
-
-For more information on the SDKs, see [Write control code with Viam's SDKs](/appendix/apis/).
-
-#### Configure as remote part
-
-On the **CONNECT** tab, there is also a page called **Configure as remote part**.
-This page has instructions for how to configure a {{< glossary_tooltip term_id="part" text="part" >}} of your machine as a [remote part](/architecture/parts/) of another machine.
-
-#### API keys
-
-Your machine and the Viam app communicate securely using [WebRTC](https://pkg.go.dev/go.viam.com/utils@v0.0.3/rpc#hdr-Connection) with unique secrets.
-The **API keys** page of the **CONNECT** tab allows you to access, generate, and delete your [API keys](/cloud/rbac/#api-keys), which grant access to organizations, locations, and machines.
-
-![The Security tab of a machine's page noting the Machine part API keys dropdown menu, with the clipboard icon on the far right and the Generate Key button underneath the dropdown.](/fleet/app-usage/machine-secrets.png)
-
-Copy an API key or API key ID by clicking on the clipboard icon.
-Click **Show details** and **Access settings** to go to your organization settings page, where you can modify the access your API keys provide.
-
-{{% snippet "secret-share.md" %}}
-
-## Delete a machine
-
-To delete a machine, click on the **...** menu in the top right hand corner of its page, select **Delete machine**, and confirm that you're sure.
-
-{{< imgproc alt="The delete machine button and the confirmation checkbox (Sure?) next to it." src="/fleet/app-usage/delete.png" resize="300x" >}}
diff --git a/docs/cloud/organizations.md b/docs/cloud/organizations.md
deleted file mode 100644
index b00e269c44..0000000000
--- a/docs/cloud/organizations.md
+++ /dev/null
@@ -1,94 +0,0 @@
----
-title: "Manage Organizations"
-linkTitle: "Organizations"
-weight: 30
-type: "docs"
-description: "An organization is a group of one or more locations that helps you organize and manage access to your fleet."
-tags: ["fleet management", "cloud", "app"]
-aliases:
- - /manage/fleet/organizations/
- - /fleet/organizations/
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-An organization is a group of one or more locations that helps you organize your fleet.
-
-An organization is the highest level grouping in the Viam platform, which generally represents a company, or other institution.
-You can also use organizations for departments or other entities that can have one or more [locations](/cloud/locations/).
-If you are familiar with Google Drive, you can think of an organization as a shared drive.
-
-{{}}
-
-When you or another user registers for an account with Viam, they become a member of an organization.
-If the user was invited to an organization, they become a part of that organization.
-If the user registered without invitation, an organization and a {{< glossary_tooltip term_id="location" text="location" >}} is automatically created for the user.
-
-A user can create more organizations at any time.
-
-Any member of an organization can invite new users to that organization.
-
-For example, you may have an account with one organization for your personal smart machines at home and another organization for the smart machines at work.
-
-{{}}
-
-You organization is shown in the upper right corner of the [Viam app](https://app.viam.com).
-If you click on the organization dropdown, the app displays your name, email, and a list of organizations you belong to.
-
-{{< imgproc alt="The org dropdown showing an example user's name, email, Sign out button, list of organizations, and org settings button." src="/fleet/app-usage/my-org.png" resize="400x" declaredimensions=true >}}
-
-If you used an email invite to sign up, you have two organizations to begin with: the organization that invited you and a personal organization for other projects.
-
-Click an organization's name to navigate to its list of locations.
-
-### Create a new organization
-
-To create a new organization, click on the Org's **Settings** in the top right of the navigation bar.
-Then enter the name for your new organization in the **New Organization** field in the upper left of the page.
-
-### Invite someone to an organization
-
-To invite a user to your organization, click on the Org's **Settings** in the top right of the navigation bar.
-In the members section of the page, click on **Grant access** and enter their email address.
-Then select the resource that you would like to grant the user access to and the designated role and click **Invite**.
-
-{{< imgproc alt="The user invitation menu on the Organization settings page." src="/fleet/app-usage/invite-user.png" resize="900x" declaredimensions=true >}}
-
-You can grant a user access to the following resources:
-
-- an {{< glossary_tooltip term_id="organization" text="organization" >}}
-- a {{< glossary_tooltip term_id="location" text="location" >}}
-- a {{< glossary_tooltip term_id="machine" text="machine" >}}
-
-For more information on the permissions the roles assign for each resource, see [Permissions](/cloud/rbac/#permissions).
-
-#### Use the mobile app
-
-You can also use the [Viam mobile app](/fleet/control/#control-interface-in-the-viam-mobile-app) to invite users to your organization, on the go. Navigate to Home on the mobile app, and select your organization. Click the gear icon in the upper right corner to access the mobile organization settings page. On the settings page enter an email address, select a role, and tap **Grant Access**.
-
-### Create a namespace for your organization
-
-When uploading [custom modules](/registry/) to the Viam Registry, you must set a namespace for your organization to associate your module with.
-
-To create a new namespace for your organization, click on the Org's **Settings** in the top right of the navigation bar, then click the **Set a public namespace** button.
-Enter a name or use the suggested name for your namespace, and then click **Set namespace**.
-Consider the following as you chose a namespace:
-
-- A namespace may only contain letters, numbers, and the dash (`-`) character.
-- Once set, a namespace _cannot be changed_: choose your namespace carefully!
-- You must pick a unique namespace that is not already in use by another organization.
-- As you enter your namespace, a message will appear to the right of the text box indicating whether the namespace is available, or whether an invalid character is detected.
-
-{{< imgproc alt="The namespace creation menu on the Organization settings page." src="/fleet/app-usage/create-namespace.png" resize="700x" declaredimensions=true >}}
-
-### Leave an organization
-
-To leave an organization, click on the Org's **Settings** in the top right of the navigation bar.
-Then click **Leave organization**.
-
-### Delete an organization
-
-To delete an organization, click on the Org's **Settings** in the top right of the navigation bar.
-Then click **Delete organization**.
-
-If the organization to delete contains any locations, you must delete them before you can delete the organization.
diff --git a/docs/configure/_index.md b/docs/configure/_index.md
deleted file mode 100644
index 2fbe574f6b..0000000000
--- a/docs/configure/_index.md
+++ /dev/null
@@ -1,394 +0,0 @@
----
-title: "Machine Configuration"
-linkTitle: "Machine Configuration"
-weight: 429
-type: "docs"
-description: "Before you can program a machine, you must configure its components and services as well as any modules, remotes, processes and frames."
-imageAlt: "Configure a Machine"
-images: ["/viam.svg"]
-tags: ["manage", "components"]
-aliases:
- - /manage/configuration/
- - /build/configure/
- - /build/
-no_list: true
-menuindent: true
-date: "2022-01-01"
-# updated: "" # When the content was last entirely checked
----
-
-Before you can program a smart machine, you must configure it.
-
-A machine's configuration defines the _{{< glossary_tooltip term_id="resource" text="resources" >}}_ (hardware and software services) it has access to, as well as any relevant parameters for those resources.
-You can configure the following resources:
-
-- [Components](/configure/#components): _{{< glossary_tooltip term_id="component" text="Components" >}}_ are the hardware of your machine.
-- [Services](/configure/#services): _{{< glossary_tooltip term_id="service" text="Services" >}}_ are the software that runs on your machine.
-- [Processes](/configure/#processes): Processes automatically run specified scripts when the machine boots.
-- [Modules](/configure/#modules): {{< glossary_tooltip term_id="module" text="Modules" >}} provide {{< glossary_tooltip term_id="modular-resource" text="modular resources" >}}, which are a way to add resource types or models that are not built into Viam.
-- [Remote parts](/configure/#remote-parts): Remotes are a way to connect two separate machines so one can access the resources of the other.
-- [Sub-parts](/configure/#sub-parts): Sub-parts are a way to connect two computers inside the same machine.
-- [Fragments](/configure/#fragments): Fragments are a way of sharing and managing identical configuration files (or parts of config files) across multiple machines.
-- [Frames](#frames): Frames hold reference frame information for the relative position of components in space.
-- [Triggers](/configure/#triggers): Triggers allow you to trigger actions when certain types of data are sent from your machine to the cloud, or when the internet connectivity of your machine changes.
-- [Network](/configure/#network): Networking options allow you to configure the bind address for accepting connections.
-
-To start configuring, go to the [Viam app](https://app.viam.com) and create a new machine.
-Open the part status dropdown menu in the top left corner of the page, next to the machine's name.
-Click **View setup instructions** to open the setup instructions.
-Follow the appropriate instructions for your machine's architecture.
-
-The setup steps copy your machine's credentials to your machine.
-When you turn on your machine, `viam-server` starts up and uses the provided credentials to fetch its full config from the [Viam app](https://app.viam.com).
-Once the machine has a configuration, it caches it locally and can use the configuration for up to 60 days.
-Since the configuration is cached locally, your machine does not need to stay connected to the Viam app after it has obtained its configuration file.
-
-If it is online, the machine checks for new configurations every 15 seconds and changes its configuration automatically when a new configuration is available.
-All communication happens securely over HTTPS using secret tokens that are in a machine's configuration.
-
-If your machine will never connect to the internet, you can also create a [local configuration file](/internals/local-configuration-file/) on the machine itself.
-
-{{< alert title="Tip" color="tip" >}}
-On Linux, the configuration is stored at /etc/viam.json by default and `viam-server` uses this configuration if no configuration is specified on startup.
-
-You can store your config file in a custom location if desired.
-See [Run `viam-server`](/installation/manage-viam-server/#run-viam-server) for more information.
-{{< /alert >}}
-
-After you have completed the setup steps and successfully connected to your machine, go to the **CONFIGURE** tab to start adding to the configuration.
-
-## The CONFIGURE tab
-
-The **CONFIGURE** tab on the [Viam app](https://app.viam.com) is the place to configure everything about your machine.
-
-You can switch between **Builder**, **JSON**, and **Frame** mode by clicking on the icon in the upper left-hand corner:
-
-![Mode selector on CONFIGURE tab.](/build/configure/mode-selector.png)
-
-- **Builder** mode provides a graphical interface for configuring your machine resources.
-- **JSON** mode provides a text editing field where you can write and edit the config manually.
-- **Frame** mode provides a graphical interface for configuring and visualizing the relative position of components in space.
- For more information, see the [Frame System documentation](/services/frame-system/).
-
-Regardless of the editing mode you choose, Viam stores the configuration file in [JSON (JavaScript Object Notation)](https://en.wikipedia.org/wiki/JSON).
-
-{{< alert title="Caution: Simultaneous config edits" color="caution" >}}
-If you edit a config while someone else edits the same config, the person who saves last will overwrite any prior changes that aren't reflected in the new config.
-
-Before editing a config, we recommend you refresh the page to ensure you have all the latest changes.
-{{< /alert >}}
-
-If you add components in **Builder** mode and click **Save** in the top right corner of the screen, you can switch to **JSON** and see the JSON that has been generated by the builder.
-
-{{% expand "An example JSON config file for a machine with a board component, motor component, camera component, and vision service configured" %}}
-
-```json
-{
- "components": [
- {
- "name": "local",
- "model": "pi",
- "type": "board",
- "namespace": "rdk",
- "attributes": {},
- "depends_on": []
- },
- {
- "name": "my-motor",
- "model": "gpio",
- "type": "motor",
- "namespace": "rdk",
- "attributes": {
- "pins": {
- "a": "13",
- "b": "15"
- },
- "board": "local",
- "max_rpm": 120
- },
- "depends_on": []
- },
- {
- "name": "my_camera",
- "model": "webcam",
- "type": "camera",
- "namespace": "rdk",
- "attributes": {
- "video_path": "video0"
- }
- }
- ],
- "services": [
- {
- "name": "detector",
- "type": "vision",
- "attributes": {
- "register_models": [
- {
- "parameters": {
- "segment_size_px": 200,
- "hue_tolerance_pct": 0.05,
- "detect_color": "#19FFD9"
- },
- "type": "color_detector",
- "name": "green_detector"
- }
- ]
- }
- }
- ],
- "modules": []
-}
-```
-
-See [Example JSON configuration file](/internals/local-configuration-file/#example-json-configuration-file) for an additional example.
-
-{{% /expand %}}
-
-
-
-### Components
-
-Components represent the pieces of hardware on your machine that you want to control with Viam.
-To add a new component, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Component** or hit **C**.
-Search for and select your desired {{< glossary_tooltip term_id="model" text="model" >}}.
-
-You must configure each component with a type, a model, a name, attributes, and dependencies:
-
-- `type`: The broad component category, such as `motor`, `arm` or `camera`.
- Components of a given type have a common API.
-
-- `model`: Indicates the more specific category of hardware.
- Components of the same model are supported using the same low-level code.
-
-- `name`: Serves as an identifier when accessing the resource from your code, as well as when configuring other resources that are dependent on that resource.
- You can either accept the suggested default name when creating a component or choose a unique name for a component.
- The name must start with a letter or number and only contain letters, numbers, dashes, and underscores with a max length of 60.
-
-- `attributes`: Configure component details such as how the component is wired to the machine, its dimensions, and other specifications; attributes vary widely between models.
- See a {{< glossary_tooltip term_id="component" text="component" >}}'s documentation for more details.
-
-- `depends_on`: Any components that a given component relies upon, and that must be initialized on boot before this component is initialized.
- Many built-in components have convenient implicit dependencies, in which case `depends_on` can be left blank.
- For example, a [`gpio` motor](/components/motor/gpio/) depends on the `board` to which it is wired, but it has a dedicated `board` attribute and `viam-server` will automatically initialize that board before it looks for the motor.
-
-- `log_configuration`: Specify the log level for a resource. The default log level is `"Info"`. For example:
-
- ```json
- "log_configuration": {
- "level": "Debug"
- }
- ```
-
-For specific information on how to configure each supported component type, see the {{< glossary_tooltip term_id="component" text="component" >}}'s documentation:
-
-{{< cards >}}
-{{% relatedcard link="/components/arm" %}}
-{{% relatedcard link="/components/base" %}}
-{{% relatedcard link="/components/board" %}}
-{{% relatedcard link="/components/camera" %}}
-{{% relatedcard link="/components/encoder" %}}
-{{% relatedcard link="/components/gantry" %}}
-{{% relatedcard link="/components/generic" %}}
-{{% relatedcard link="/components/gripper" %}}
-{{% relatedcard link="/components/input-controller" %}}
-{{% relatedcard link="/components/motor" %}}
-{{% relatedcard link="/components/movement-sensor" %}}
-{{% relatedcard link="/components/power-sensor" %}}
-{{% relatedcard link="/components/sensor" %}}
-{{% relatedcard link="/components/servo" %}}
-{{< /cards >}}
-
-Some resources have a **TEST** section on the bottom half of their configuration pane which you can expand and interact with to test out controlling the component.
-You must be running `viam-server` and connected to your machine to use this feature.
-
-{{}}
-
-On the **...** menu in the upper right corner of each resource you can **Duplicate**, **Delete**, and **Disable** or **Enable** it.
-
-{{}}
-
-{{% alert title="Tip" color="tip" %}}
-
-When you configure a component on the **CONFIGURE** tab, it will also appear on the **CONTROL** tab which gives you an interface to interact with it.
-The **Code sample** page on the **CONNECT** tab will also update to include code for some basic interaction with that component using the Viam [SDKs](/appendix/apis/).
-
-{{% /alert %}}
-
-### Services
-
-Services are software packages that make it easier to add complex capabilities such as motion planning or object detection to your machine.
-To add a new service, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Service** or hit **S**.
-Search for and select your desired {{< glossary_tooltip term_id="model" text="model" >}}.
-
-You must configure a service with a `name` and a `type`:
-
-- `type`: specifies which of the Viam services you want to use on your machine, such as the vision service or the motion service.
-- `name`: serves as an identifier when accessing the resource from your code, as well as when configuring other resources that are dependent on that resource.
- You can accept the suggested default name when creating a service or choose a choose any unique name for a service.
- The name must start with a letter or number and can only contain letters, numbers, dashes, and underscores with a max length of 60.
-- `log_configuration`: Specify the log level for a resource. The default log level is `"Info"`. For example:
-
- ```json
- "log_configuration": {
- "level": "Debug"
- }
- ```
-
-The other aspects of configuring a service are highly specific to the type of service, review the docs for the service you are interested in:
-
-{{< cards >}}
-{{% relatedcard link="/services/data/" %}}
-{{% relatedcard link="/services/ml/" alt_title="Machine Learning" %}}
-{{% relatedcard link="/services/motion" %}}
-{{% relatedcard link="/services/navigation" %}}
-{{% relatedcard link="/services/slam" %}}
-{{% relatedcard link="/services/vision" %}}
-{{% relatedcard link="/services/generic" %}}
-{{% relatedcard link="/services/frame-system" %}}
-{{< /cards >}}
-
-Some resources have a **TEST** section on the bottom half of their configuration pane which you can expand and interact with to test out controlling the service.
-You must be running `viam-server` and connected to your machine to use this feature.
-
-You can disable a service without removing it from the configuration by selecting the **...** menu in the upper right corner and selecting **Disable**.
-
-{{% alert title="Tip" color="tip" %}}
-
-When you configure a service on the **CONFIGURE** tab, it will also appear on the **CONTROL** tab which gives you an interface to test and interact with it.
-The **Code sample** page on the **CONNECT** tab will also update to include code for some basic interaction with that service using the Viam [SDKs](/appendix/apis/).
-
-{{% /alert %}}
-
-### Processes
-
-To automatically run a specified command when the machine boots, configure a _{{< glossary_tooltip term_id="process" text="process" >}}_.
-You can configure any command, for example one that executes a binary or a script, to run as a process.
-
-To add a new process, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Process**.
-Find more information in the [processes documentation](/configure/processes/).
-
-### Modules
-
-Modules allow you to add [modular resources](/registry/) to your machines which add resource types or models that are not built into Viam.
-Many models are available in the [registry](https://app.viam.com/registry) and you are able to add them as components or services.
-
-#### Local Modules
-
-To add a module that is not in the registry and is local to your machine, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Local module**.
-Follow the instructions in our [registry documentation](/registry/modular-resources/#configuration) to configure the module.
-
-### Remote parts
-
-Configuring a remote part is a way to connect two separate machines so one can access the resources of the other.
-
-To configure a remote part, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Remote part**.
-Find more information in our [machine parts documentation](/architecture/parts/).
-
-### Sub-parts
-
-Configure a sub-part to connect two computers inside the same machine.
-
-To configure a sub-part, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Sub-part**.
-Find more information in our [machine parts documentation](/architecture/parts/).
-
-### Fragments
-
-You can use fragments to share similar {{< glossary_tooltip term_id="resource" text="resource" >}} configuration files across multiple machines in your fleet.
-For example, if you have multiple machines with the same motor hardware, wired the same way, you can create a fragment to configure that motor and share it easily across all of your machines, without needing to individually configure the motor component for each machine.
-
-To use a fragment, click the **+** icon next to your {{< glossary_tooltip term_id="part" text="machine part" >}} in the left-hand menu of the **CONFIGURE** tab and select **Insert fragment**.
-See [Use Fragments to Configure a Fleet](/fleet/fragments/) for more information on creating and deploying fragments.
-
-### Frames
-
-The frame system holds reference frame information for the relative position of components in space.
-
-Click on the **Frame** mode to visualize and configure the relative positions of components.
-Find more information in the [frame system documentation](/services/frame-system/).
-
-### Triggers
-
-Triggers allow you to trigger actions when certain types of data are sent from your machine to the cloud, or when the internet connectivity of your machine changes.
-For example, you can configure a trigger to send you a notification when your robot's sensor collects a new reading.
-
-See [Configure a Trigger](/configure/triggers/) for more information on triggers.
-
-### Network
-
-You can configure your machine's bind address and heartbeat window.
-
-On your machine's **CONFIGURE** tab, click the **+** button and select **Network**.
-
-{{< tabs >}}
-{{% tab name="Builder UI" %}}
-
-In the **network** panel, configure your **Bind address** and your **Heartbeat window**.
-
-{{% /tab %}}
-{{% tab name="JSON" %}}
-
-```json
- ... // components {...}, services {...},
- "network": {
- "bind_address": "0.0.0.0:8080",
- "sessions": {
- "heartbeat_window": "30s" // Changes heartbeat window to 30 seconds
- }
- },
- ...
-```
-
-{{% /tab %}}
-{{< /tabs >}}
-
-
-| Attribute | Type | Required? | Description |
-| --------- | ---- | --------- | ----------- |
-| `bind_address` | string | Optional | The address `viam-server` binds to for accepting connections. Default: `"0.0.0.0:8080"` when managed by the Viam app or when authentication and TLS are enabled. |
-| `sessions.heartbeat_window` | string | Optional | A _heartbeat_ is a signal that indicates machine connectivity. Heartbeats are sent automatically from Viam's SDKs unless you disable them with the session management API or session management is not implemented by the server in question. Heartbeats are automatically sent at an interval that is one fifth of the heartbeat window. Default: `"2s"`. Use a higher value in high-latency networks. Requires a restart to take effect. |
-
-## Configuration History
-
-The Viam app keeps a record of each machine's configuration changes, allowing you to revert to earlier configurations if needed and see who made specific changes.
-
-To see the configuration history for a machine part, click on the **History** link at the top right corner of the machine part's card in the Viam app.
-
-{{}}
-
-To restore to an earlier version of your configuration, click the **Restore version** button next to the desired configuration.
-
-## Troubleshooting
-
-If you run into issues, here are some things to try:
-
-- Check the [**LOGS** tab](/cloud/machines/#logs) to view log messages and errors from `viam-server`.
- You can also [access the local log file](/installation/manage-viam-server/#view-viam-server-logs) on your machine if needed.
-- Make sure all configured components are saved to your config.
- If they aren't, you will see an **Unsaved changes** note next to the **Save** button in the top right corner of the page.
-- Try restarting `viam-server` by navigating to the app's **CONFIGURE** tab in **Builder** mode, clicking the **...** menu on the right side of the machine part's card, and selecting **Restart part**.
- It takes a few minutes for the server to shut down and restart.
-- If you need to revert to an earlier configuration, use the [Configuration History](#configuration-history) to restore to an earlier version.
-- Make sure the issue is not hardware related.
- Some things to check are that the machine has adequate power, all wires are properly connected, and no chips or other hardware components are shorted or overheated.
-- See [Troubleshooting](/appendix/troubleshooting/) for additional troubleshooting steps.
-- {{< snippet "social.md" >}}
-
-## Local setup
-
-Configuring `viam-server` with the Viam app allows you to use Viam's cloud features:
-
-- [Fleet Management](/fleet/)
-- [Data Management](/services/data/)
-- [Machine Learning](/services/ml/)
-
-However, if you are configuring a machine that can never connect to the internet, you can create a [local configuration file](/internals/local-configuration-file/) on your machine.
-A locally-configured machine will not be able to access Viam's cloud features.
-
-## Next steps
-
-After configuring your machine, you can use the [Viam SDKs](/appendix/apis/) to program and control your machine.
-
-If you want to try configuring a machine but don't have any hardware on hand, try the [Build a Mock Robot](/tutorials/configure/build-a-mock-robot/) tutorial.
diff --git a/docs/data-ai/_index.md b/docs/data-ai/_index.md
new file mode 100644
index 0000000000..9a73a98319
--- /dev/null
+++ b/docs/data-ai/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "AI & data"
+title: "Use data & AI"
+weight: 250
+layout: "docs"
+type: "docs"
+no_list: true
+open_on_desktop: true
+overview: true
+---
diff --git a/docs/data-ai/ai/_index.md b/docs/data-ai/ai/_index.md
new file mode 100644
index 0000000000..27948b7ad8
--- /dev/null
+++ b/docs/data-ai/ai/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "Leverage AI"
+title: "Leverage AI"
+weight: 300
+layout: "empty"
+type: "docs"
+empty_page: true
+open_on_desktop: true
+header_only: true
+---
diff --git a/docs/data-ai/ai/act.md b/docs/data-ai/ai/act.md
new file mode 100644
index 0000000000..4adb7aea52
--- /dev/null
+++ b/docs/data-ai/ai/act.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Act based on inferences"
+title: "Act based on inferences"
+weight: 70
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/advanced/_index.md b/docs/data-ai/ai/advanced/_index.md
new file mode 100644
index 0000000000..233056f4cd
--- /dev/null
+++ b/docs/data-ai/ai/advanced/_index.md
@@ -0,0 +1,8 @@
+---
+linkTitle: "Advanced"
+title: "Advanced"
+weight: 200
+layout: "empty"
+type: "docs"
+empty_page: true
+---
diff --git a/docs/data-ai/ai/advanced/conditional-sync.md b/docs/data-ai/ai/advanced/conditional-sync.md
new file mode 100644
index 0000000000..9d8fae7746
--- /dev/null
+++ b/docs/data-ai/ai/advanced/conditional-sync.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Upload external data"
+title: "Upload external data for training"
+weight: 20
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/alert.md b/docs/data-ai/ai/alert.md
new file mode 100644
index 0000000000..8f26dda2eb
--- /dev/null
+++ b/docs/data-ai/ai/alert.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Alert on inferences"
+title: "Alert on inferences"
+weight: 60
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/create-dataset.md b/docs/data-ai/ai/create-dataset.md
new file mode 100644
index 0000000000..060ff51f24
--- /dev/null
+++ b/docs/data-ai/ai/create-dataset.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Create a dataset"
+title: "Create a dataset"
+weight: 10
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/deploy.md b/docs/data-ai/ai/deploy.md
new file mode 100644
index 0000000000..d8cc3a5953
--- /dev/null
+++ b/docs/data-ai/ai/deploy.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Deploy model"
+title: "Deploy a model"
+weight: 40
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/run-inference.md b/docs/data-ai/ai/run-inference.md
new file mode 100644
index 0000000000..9587691af1
--- /dev/null
+++ b/docs/data-ai/ai/run-inference.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Run inference"
+title: "Run inference on a model"
+weight: 50
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/train-tflite.md b/docs/data-ai/ai/train-tflite.md
new file mode 100644
index 0000000000..0149e8e904
--- /dev/null
+++ b/docs/data-ai/ai/train-tflite.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Train TFlite model"
+title: "Train a TFlite model"
+weight: 20
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/ai/train.md b/docs/data-ai/ai/train.md
new file mode 100644
index 0000000000..4d8c06f95b
--- /dev/null
+++ b/docs/data-ai/ai/train.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Train other models"
+title: "Train other models"
+weight: 30
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/data/_index.md b/docs/data-ai/data/_index.md
new file mode 100644
index 0000000000..be6f6ef798
--- /dev/null
+++ b/docs/data-ai/data/_index.md
@@ -0,0 +1,11 @@
+---
+linkTitle: "Manage data"
+title: "Manage data"
+weight: 200
+layout: "empty"
+type: "docs"
+empty_page: true
+open_on_desktop: true
+header_only: true
+---
+
diff --git a/docs/data-ai/data/advanced/_index.md b/docs/data-ai/data/advanced/_index.md
new file mode 100644
index 0000000000..233056f4cd
--- /dev/null
+++ b/docs/data-ai/data/advanced/_index.md
@@ -0,0 +1,8 @@
+---
+linkTitle: "Advanced"
+title: "Advanced"
+weight: 200
+layout: "empty"
+type: "docs"
+empty_page: true
+---
diff --git a/docs/data-ai/data/advanced/conditional-sync.md b/docs/data-ai/data/advanced/conditional-sync.md
new file mode 100644
index 0000000000..85cf099dc5
--- /dev/null
+++ b/docs/data-ai/data/advanced/conditional-sync.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Conditional sync"
+title: "Conditional sync"
+weight: 20
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/data/advanced/filter-before-sync.md b/docs/data-ai/data/advanced/filter-before-sync.md
new file mode 100644
index 0000000000..d283ffb4c1
--- /dev/null
+++ b/docs/data-ai/data/advanced/filter-before-sync.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Filter data"
+title: "Filter data before sync"
+weight: 10
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/data/export.md b/docs/data-ai/data/export.md
new file mode 100644
index 0000000000..713fa40b32
--- /dev/null
+++ b/docs/data-ai/data/export.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Export data"
+title: "Export data"
+weight: 40
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/data/query.md b/docs/data-ai/data/query.md
new file mode 100644
index 0000000000..1919558fa3
--- /dev/null
+++ b/docs/data-ai/data/query.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Query data"
+title: "Query data"
+weight: 20
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/data/visualize.md b/docs/data-ai/data/visualize.md
new file mode 100644
index 0000000000..50e52c5b54
--- /dev/null
+++ b/docs/data-ai/data/visualize.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Visualize data"
+title: "Visualize data"
+weight: 20
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/get-started/_index.md b/docs/data-ai/get-started/_index.md
new file mode 100644
index 0000000000..e02e0b0326
--- /dev/null
+++ b/docs/data-ai/get-started/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "Get started"
+title: "Get started"
+weight: 100
+layout: "empty"
+type: "docs"
+empty_page: true
+open_on_desktop: true
+header_only: true
+---
diff --git a/docs/data-ai/get-started/capture-sync.md b/docs/data-ai/get-started/capture-sync.md
new file mode 100644
index 0000000000..681aeae47c
--- /dev/null
+++ b/docs/data-ai/get-started/capture-sync.md
@@ -0,0 +1,9 @@
+---
+linkTitle: "Capture and sync"
+title: "Capture and sync data"
+weight: 10
+layout: "docs"
+type: "docs"
+no_list: true
+description: "TODO"
+---
diff --git a/docs/data-ai/reference/_index.md b/docs/data-ai/reference/_index.md
new file mode 100644
index 0000000000..7fd76af858
--- /dev/null
+++ b/docs/data-ai/reference/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "Reference"
+title: "Reference"
+weight: 500
+layout: "empty"
+type: "docs"
+empty_page: true
+open_on_desktop: true
+header_only: true
+---
diff --git a/docs/data-ai/reference/data-client.md b/docs/data-ai/reference/data-client.md
new file mode 100644
index 0000000000..f8e23e1057
--- /dev/null
+++ b/docs/data-ai/reference/data-client.md
@@ -0,0 +1,8 @@
+---
+title: "Upload and Retrieve Data with Viam's Data Client API"
+linkTitle: "Data Client API"
+weight: 30
+type: "docs"
+layout: "empty"
+canonical: "/dev/apis/data-client/"
+---
diff --git a/docs/services/data/_index.md b/docs/data-ai/reference/data/_index.md
similarity index 98%
rename from docs/services/data/_index.md
rename to docs/data-ai/reference/data/_index.md
index ea76f012ef..c11448dd9e 100644
--- a/docs/services/data/_index.md
+++ b/docs/data-ai/reference/data/_index.md
@@ -1,6 +1,6 @@
---
title: "Data Management Service"
-linkTitle: "Data Management"
+linkTitle: "Data Management Service"
description: "Configure the data management service to capture data from your components and services and sync it to the cloud."
weight: 10
type: "docs"
@@ -767,8 +767,8 @@ The following components and services support data capture, for the following me
| Type | Method |
| ---- | ------ |
-| [Movement Sensor](/components/movement-sensor/) | [`AngularVelocity`](/appendix/apis/components/movement-sensor/#getangularvelocity), [`LinearAcceleration`](/appendix/apis/components/movement-sensor/#getlinearacceleration), [`LinearVelocity`](/appendix/apis/components/movement-sensor/#getlinearvelocity) |
-| [Sensor](/components/sensor/) | [`GetReadings`](/appendix/apis/components/sensor/#getreadings) |
+| [Movement Sensor](/components/movement-sensor/) | [`AngularVelocity`](/dev/reference/apis/components/movement-sensor/#getangularvelocity), [`LinearAcceleration`](/dev/reference/apis/components/movement-sensor/#getlinearacceleration), [`LinearVelocity`](/dev/reference/apis/components/movement-sensor/#getlinearvelocity) |
+| [Sensor](/components/sensor/) | [`GetReadings`](/dev/reference/apis/components/sensor/#getreadings) |
{{% /tab %}}
{{< /tabs >}}
@@ -794,12 +794,12 @@ You can also access data from a resource, machine part, or machine menu.
## API
-The [data management service API](/appendix/apis/services/data/) supports the following methods:
+The [data management service API](/dev/reference/apis/services/data/) supports the following methods:
{{< readfile "/static/include/services/apis/generated/data_manager-table.md" >}}
The data client API supports a separate set of methods that allow you to upload and export data to and from the Viam app.
-For information about that API, see [Data Client API](/appendix/apis/data-client/).
+For information about that API, see [Data Client API](/dev/reference/apis/data-client/).
## Troubleshooting
diff --git a/docs/data-ai/reference/ml-model-client.md b/docs/data-ai/reference/ml-model-client.md
new file mode 100644
index 0000000000..bd68278b3b
--- /dev/null
+++ b/docs/data-ai/reference/ml-model-client.md
@@ -0,0 +1,8 @@
+---
+title: "ML Model API"
+linkTitle: "ML Model API"
+weight: 30
+type: "docs"
+layout: "empty"
+canonical: "/dev/apis/data-client/"
+---
diff --git a/docs/data-ai/reference/ml-training-client.md b/docs/data-ai/reference/ml-training-client.md
new file mode 100644
index 0000000000..4cb9487449
--- /dev/null
+++ b/docs/data-ai/reference/ml-training-client.md
@@ -0,0 +1,8 @@
+---
+title: "Work with ML Training Jobs with Viam's ML Training API"
+linkTitle: "ML Training Client API"
+weight: 40
+type: "docs"
+layout: "empty"
+canonical: "/dev/apis/ml-training-client/"
+---
diff --git a/docs/services/ml/_index.md b/docs/data-ai/reference/ml.md
similarity index 96%
rename from docs/services/ml/_index.md
rename to docs/data-ai/reference/ml.md
index 517a87f9e8..5da7d8985b 100644
--- a/docs/services/ml/_index.md
+++ b/docs/data-ai/reference/ml.md
@@ -1,7 +1,7 @@
---
title: "ML Model Service"
-linkTitle: "ML Model"
-weight: 30
+linkTitle: "ML Model Service"
+weight: 11
type: "docs"
tags: ["data management", "ml", "model training"]
aliases:
@@ -66,7 +66,7 @@ You can search the machine learning models that are available to deploy on this
## API
-The [ML model service API](/appendix/apis/services/ml/) supports the following methods:
+The [ML model service API](/dev/reference/apis/services/ml/) supports the following methods:
{{< readfile "/static/include/services/apis/generated/mlmodel-table.md" >}}
diff --git a/docs/data-ai/reference/vision-client.md b/docs/data-ai/reference/vision-client.md
new file mode 100644
index 0000000000..469b4d6c13
--- /dev/null
+++ b/docs/data-ai/reference/vision-client.md
@@ -0,0 +1,8 @@
+---
+title: "Vision Service API"
+linkTitle: "Vision Service API"
+weight: 30
+type: "docs"
+layout: "empty"
+canonical: "/dev/apis/vision-client/"
+---
diff --git a/docs/services/vision/_index.md b/docs/data-ai/reference/vision/_index.md
similarity index 88%
rename from docs/services/vision/_index.md
rename to docs/data-ai/reference/vision/_index.md
index 4599b314df..018e076807 100644
--- a/docs/services/vision/_index.md
+++ b/docs/data-ai/reference/vision/_index.md
@@ -1,6 +1,6 @@
---
title: "Vision Service"
-linkTitle: "Computer Vision"
+linkTitle: "Vision Service"
weight: 20
type: "docs"
description: "The vision service enables your machine to use its on-board cameras to intelligently see and interpret the world around it."
@@ -55,8 +55,8 @@ The returned detections consist of the bounding box around the identified object
**Supported API methods:**
-- [GetDetections()](/appendix/apis/services/vision/#getdetections)
-- [GetDetectionsFromCamera()](/appendix/apis/services/vision/#getdetectionsfromcamera)
+- [GetDetections()](/dev/reference/apis/services/vision/#getdetections)
+- [GetDetectionsFromCamera()](/dev/reference/apis/services/vision/#getdetectionsfromcamera)
## Classifications
@@ -73,8 +73,8 @@ The returned classifications consist of the image's class label and confidence s
**Supported API methods:**
-- [GetClassifications()](/appendix/apis/services/vision/#getclassifications)
-- [GetClassificationsFromCamera()](/appendix/apis/services/vision/#getclassificationsfromcamera)
+- [GetClassifications()](/dev/reference/apis/services/vision/#getclassifications)
+- [GetClassificationsFromCamera()](/dev/reference/apis/services/vision/#getclassificationsfromcamera)
## Segmentations
@@ -88,7 +88,7 @@ Any camera that can return 3D pointclouds can use 3D object segmentation.
**Supported API methods:**
-- [GetObjectPointClouds()](/appendix/apis/services/vision/#getobjectpointclouds)
+- [GetObjectPointClouds()](/dev/reference/apis/services/vision/#getobjectpointclouds)
## Configuration
@@ -98,7 +98,7 @@ Any camera that can return 3D pointclouds can use 3D object segmentation.
## API
-The vision service supports the following [vision service API](/appendix/apis/services/vision/) methods:
+The vision service supports the following [vision service API](/dev/reference/apis/services/vision/) methods:
{{< readfile "/static/include/services/apis/generated/vision-table.md" >}}
diff --git a/docs/services/vision/color_detector.md b/docs/data-ai/reference/vision/color_detector.md
similarity index 100%
rename from docs/services/vision/color_detector.md
rename to docs/data-ai/reference/vision/color_detector.md
diff --git a/docs/services/vision/detector_3d_segmenter.md b/docs/data-ai/reference/vision/detector_3d_segmenter.md
similarity index 96%
rename from docs/services/vision/detector_3d_segmenter.md
rename to docs/data-ai/reference/vision/detector_3d_segmenter.md
index 86fc60f604..d6cc00b079 100644
--- a/docs/services/vision/detector_3d_segmenter.md
+++ b/docs/data-ai/reference/vision/detector_3d_segmenter.md
@@ -100,7 +100,7 @@ Click the **Save** button in the top right corner of the page and proceed to [te
## Test your segmenter
-The following code uses the [`GetObjectPointClouds`](/appendix/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
+The following code uses the [`GetObjectPointClouds`](/dev/reference/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
{{< tabs >}}
{{% tab name="Python" %}}
diff --git a/docs/services/vision/mlmodel.md b/docs/data-ai/reference/vision/mlmodel.md
similarity index 100%
rename from docs/services/vision/mlmodel.md
rename to docs/data-ai/reference/vision/mlmodel.md
diff --git a/docs/services/vision/obstacles_depth.md b/docs/data-ai/reference/vision/obstacles_depth.md
similarity index 96%
rename from docs/services/vision/obstacles_depth.md
rename to docs/data-ai/reference/vision/obstacles_depth.md
index 0e5da97777..2111695393 100644
--- a/docs/services/vision/obstacles_depth.md
+++ b/docs/data-ai/reference/vision/obstacles_depth.md
@@ -126,14 +126,14 @@ If you want to identify multiple boxes over the flat plane with your segmenter:
- First, [configure your frame system](/services/frame-system/#configuration) to configure the relative spatial orientation of the components of your machine, including your [camera](/components/camera/), within Viam's [frame system service](/services/frame-system/).
- After configuring your frame system, your camera will populate its own `Properties` with these spatial intrinsic parameters from the frame system.
- - You can get those parameters from your camera through the [camera API](/appendix/apis/components/camera/#getproperties).
+ - You can get those parameters from your camera through the [camera API](/dev/reference/apis/components/camera/#getproperties).
- The segmenter now returns multiple boxes within the `GeometryInFrame` object it captures.
Click the **Save** button in the top right corner of the page and proceed to [test your segmenter](#test-your-segmenter).
## Test your segmenter
-The following code uses the [`GetObjectPointClouds`](/appendix/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
+The following code uses the [`GetObjectPointClouds`](/dev/reference/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
{{< tabs >}}
{{% tab name="Python" %}}
diff --git a/docs/services/vision/obstacles_distance.md b/docs/data-ai/reference/vision/obstacles_distance.md
similarity index 91%
rename from docs/services/vision/obstacles_distance.md
rename to docs/data-ai/reference/vision/obstacles_distance.md
index 21ee09cdc3..100cfef9b4 100644
--- a/docs/services/vision/obstacles_distance.md
+++ b/docs/data-ai/reference/vision/obstacles_distance.md
@@ -82,11 +82,11 @@ The following parameters are available for a `obstacles_distance` segmenter:
| Parameter | Required? | Description |
| --------- | --------- | ----------- |
-| `num_queries`| Optional | How many times the model should call [`GetPointCloud()`](/appendix/apis/components/camera/#getpointcloud) before taking the average of the measurements and returning the single closest point. Accepts an integer between `1` and `20`. Default: `10` |
+| `num_queries`| Optional | How many times the model should call [`GetPointCloud()`](/dev/reference/apis/components/camera/#getpointcloud) before taking the average of the measurements and returning the single closest point. Accepts an integer between `1` and `20`. Default: `10` |
## Test your segmenter
-The following code uses the [`GetObjectPointClouds`](/appendix/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
+The following code uses the [`GetObjectPointClouds`](/dev/reference/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
{{< tabs >}}
{{% tab name="Python" %}}
diff --git a/docs/services/vision/obstacles_pointcloud.md b/docs/data-ai/reference/vision/obstacles_pointcloud.md
similarity index 97%
rename from docs/services/vision/obstacles_pointcloud.md
rename to docs/data-ai/reference/vision/obstacles_pointcloud.md
index 96dfc15459..91062ce44e 100644
--- a/docs/services/vision/obstacles_pointcloud.md
+++ b/docs/data-ai/reference/vision/obstacles_pointcloud.md
@@ -118,7 +118,7 @@ Click the **Save** button in the top right corner of the page and proceed to [te
## Test your segmenter
-The following code uses the [`GetObjectPointClouds`](/appendix/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
+The following code uses the [`GetObjectPointClouds`](/dev/reference/apis/services/vision/#getobjectpointclouds) method to run a segmenter vision model on an image from the machine's camera `"cam1"`:
{{< tabs >}}
{{% tab name="Python" %}}
diff --git a/docs/dev/_index.md b/docs/dev/_index.md
new file mode 100644
index 0000000000..da9c4a4f2d
--- /dev/null
+++ b/docs/dev/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "Dev tools"
+title: "Dev tools"
+weight: 600
+layout: "docs"
+type: "docs"
+no_list: true
+open_on_desktop: true
+overview: true
+---
diff --git a/docs/appendix/contributing.md b/docs/dev/contributing.md
similarity index 100%
rename from docs/appendix/contributing.md
rename to docs/dev/contributing.md
diff --git a/docs/dev/reference/_index.md b/docs/dev/reference/_index.md
new file mode 100644
index 0000000000..a11cc4cbac
--- /dev/null
+++ b/docs/dev/reference/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "Reference"
+title: "Reference"
+weight: 300
+layout: "empty"
+type: "docs"
+empty_page: true
+open_on_desktop: true
+header_only: true
+---
diff --git a/docs/dev/reference/apis/_index.md b/docs/dev/reference/apis/_index.md
new file mode 100644
index 0000000000..8d9111357a
--- /dev/null
+++ b/docs/dev/reference/apis/_index.md
@@ -0,0 +1,88 @@
+---
+title: "Viam's Client APIs"
+linkTitle: "APIs"
+weight: 10
+type: "docs"
+description: "Access and control your machine or fleet with the SDKs' client libraries for the resource and robot APIs."
+icon: true
+images: ["/services/icons/sdk.svg"]
+tags: ["client", "sdk", "viam-server", "networking", "apis", "robot api"]
+aliases:
+ - /program/sdks/
+ - /program/apis/
+ - /build/program/apis/
+no_list: true
+date: "2024-10-01"
+# updated: "" # When the content was last entirely checked
+---
+
+Every Viam {{< glossary_tooltip term_id="resource" text="resource" >}} exposes an [application programming interface (API)](https://en.wikipedia.org/wiki/API) described through [protocol buffers](https://developers.google.com/protocol-buffers).
+
+The API methods provided by the SDKs for each of these resource APIs wrap gRPC client requests to the machine when you execute your program, providing you a convenient interface for accessing information about and controlling the {{< glossary_tooltip term_id="resource" text="resources" >}} you have [configured](/configure/) on your machine.
+
+## Platform APIs
+
+{{< cards >}}
+{{% manualcard link="/dev/reference/apis/fleet/" title="Fleet Management API" %}}
+
+Create and manage organizations, locations, and machines, get logs from individual machines, and manage fragments and permissions.
+
+{{% /manualcard %}}
+{{% manualcard link="/dev/reference/apis/data-client/" title="Data Client API" %}}
+
+Upload, download, filter, tag or perform other tasks on data like images or sensor readings.
+
+{{% /manualcard %}}
+{{% manualcard link="/dev/reference/apis/robot/" title="Machine Management API" %}}
+
+Manage your machines: connect to your machine, retrieve status information, and send commands remotely.
+
+{{% /manualcard %}}
+{{% manualcard link="/dev/reference/apis/ml-training-client/" title="ML Training Client API" %}}
+
+Submit and manage ML training jobs running on the Viam app.
+
+{{% /manualcard %}}
+{{% manualcard link="/dev/reference/apis/billing-client/" title="Billing Client API" %}}
+
+Retrieve billing information from the Viam app.
+
+{{% /manualcard %}}
+
+{{< /cards >}}
+
+## Component APIs
+
+These APIs provide interfaces for controlling and getting information from the {{< glossary_tooltip term_id="component" text="components" >}} of a machine:
+
+{{< cards >}}
+{{< card link="/dev/reference/apis/components/arm/" customTitle="Arm API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/base/" customTitle="Base API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/board/" customTitle="Board API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/camera/" customTitle="Camera API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/encoder/" customTitle="Encoder API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/gantry/" customTitle="Gantry API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/generic/" customTitle="Generic API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/gripper/" customTitle="Gripper API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/input-controller/" customTitle="Input controller API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/motor/" customTitle="Motor API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/movement-sensor/" customTitle="Movement sensor API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/power-sensor/" customTitle="Power sensor API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/sensor/" customTitle="Sensor API" noimage="True" >}}
+{{< card link="/dev/reference/apis/components/servo/" customTitle="Servo API" noimage="True" >}}
+{{< /cards >}}
+
+## Service APIs
+
+These APIs provide interfaces for controlling and getting information from the services you configured on a machine.
+
+{{< cards >}}
+{{% card link="/dev/reference/apis/services/data/" customTitle="Data management service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/vision/" customTitle="Vision service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/ml/" customTitle="ML model service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/motion/" customTitle="Motion service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/navigation/" customTitle="Navigation service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/generic/" customTitle="Generic service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/slam/" customTitle="SLAM service API" noimage="True" %}}
+{{% card link="/dev/reference/apis/services/base-rc/" customTitle="Base Remote Control service API" noimage="True" %}}
+{{< /cards >}}
diff --git a/docs/appendix/apis/billing-client.md b/docs/dev/reference/apis/billing-client.md
similarity index 100%
rename from docs/appendix/apis/billing-client.md
rename to docs/dev/reference/apis/billing-client.md
diff --git a/docs/appendix/apis/components/_index.md b/docs/dev/reference/apis/components/_index.md
similarity index 77%
rename from docs/appendix/apis/components/_index.md
rename to docs/dev/reference/apis/components/_index.md
index 9c8eba8326..33a4cfc90e 100644
--- a/docs/appendix/apis/components/_index.md
+++ b/docs/dev/reference/apis/components/_index.md
@@ -4,6 +4,6 @@ title: "Component APIs"
weight: 5
empty_node: true
layout: "empty"
-canonical: "/appendix/apis/"
+canonical: "/dev/reference/apis/"
type: "docs"
---
diff --git a/docs/appendix/apis/components/arm.md b/docs/dev/reference/apis/components/arm.md
similarity index 100%
rename from docs/appendix/apis/components/arm.md
rename to docs/dev/reference/apis/components/arm.md
diff --git a/docs/appendix/apis/components/base.md b/docs/dev/reference/apis/components/base.md
similarity index 100%
rename from docs/appendix/apis/components/base.md
rename to docs/dev/reference/apis/components/base.md
diff --git a/docs/appendix/apis/components/board.md b/docs/dev/reference/apis/components/board.md
similarity index 100%
rename from docs/appendix/apis/components/board.md
rename to docs/dev/reference/apis/components/board.md
diff --git a/docs/appendix/apis/components/camera.md b/docs/dev/reference/apis/components/camera.md
similarity index 100%
rename from docs/appendix/apis/components/camera.md
rename to docs/dev/reference/apis/components/camera.md
diff --git a/docs/appendix/apis/components/encoder.md b/docs/dev/reference/apis/components/encoder.md
similarity index 100%
rename from docs/appendix/apis/components/encoder.md
rename to docs/dev/reference/apis/components/encoder.md
diff --git a/docs/appendix/apis/components/gantry.md b/docs/dev/reference/apis/components/gantry.md
similarity index 100%
rename from docs/appendix/apis/components/gantry.md
rename to docs/dev/reference/apis/components/gantry.md
diff --git a/docs/appendix/apis/components/generic.md b/docs/dev/reference/apis/components/generic.md
similarity index 96%
rename from docs/appendix/apis/components/generic.md
rename to docs/dev/reference/apis/components/generic.md
index 1503914b0f..3a124297e8 100644
--- a/docs/appendix/apis/components/generic.md
+++ b/docs/dev/reference/apis/components/generic.md
@@ -10,7 +10,7 @@ date: "2022-01-01"
# updated: "" # When the content was last entirely checked
---
-The generic API allows you to give commands to your [generic components](/components/generic/) for running model-specific commands using [`DoCommand`](/appendix/apis/components/generic/#docommand).
+The generic API allows you to give commands to your [generic components](/components/generic/) for running model-specific commands using [`DoCommand`](/dev/reference/apis/components/generic/#docommand).
The generic component supports the following method:
diff --git a/docs/appendix/apis/components/gripper.md b/docs/dev/reference/apis/components/gripper.md
similarity index 100%
rename from docs/appendix/apis/components/gripper.md
rename to docs/dev/reference/apis/components/gripper.md
diff --git a/docs/appendix/apis/components/input-controller.md b/docs/dev/reference/apis/components/input-controller.md
similarity index 97%
rename from docs/appendix/apis/components/input-controller.md
rename to docs/dev/reference/apis/components/input-controller.md
index 3bd12e8729..42b9d0ed4e 100644
--- a/docs/appendix/apis/components/input-controller.md
+++ b/docs/dev/reference/apis/components/input-controller.md
@@ -64,14 +64,14 @@ Each `Event` object represents a singular event from the input device, and has f
1. `Time`: `time.Time` the event occurred.
2. `Event`: `EventType` indicating the type of event (for example, a specific button press or axis movement).
-3. `Control`: `Control` indicating which [Axis](#axis-controls), [Button](/appendix/apis/components/input-controller/#button-controls), or Pedal on the controller has been changed.
-4. `Value`: `float64` indicating the position of an [Axis](/appendix/apis/components/input-controller/#axis-controls) or the state of a [Button](/appendix/apis/components/input-controller/#button-controls) on the specified control.
+3. `Control`: `Control` indicating which [Axis](#axis-controls), [Button](/dev/reference/apis/components/input-controller/#button-controls), or Pedal on the controller has been changed.
+4. `Value`: `float64` indicating the position of an [Axis](/dev/reference/apis/components/input-controller/#axis-controls) or the state of a [Button](/dev/reference/apis/components/input-controller/#button-controls) on the specified control.
#### EventType field
A string-like type indicating the specific type of input event, such as a button press or axis movement.
-- To select for events of all type when registering callback function with [RegisterControlCallback](/appendix/apis/components/input-controller/#registercontrolcallback), you can use `AllEvents` as your `EventType`.
+- To select for events of all type when registering callback function with [RegisterControlCallback](/dev/reference/apis/components/input-controller/#registercontrolcallback), you can use `AllEvents` as your `EventType`.
- The registered function is then called in addition to any other callback functions you've registered, every time an `Event` happens on your controller.
This is useful for debugging without interrupting normal controls, or for capturing extra or unknown events.
diff --git a/docs/appendix/apis/components/motor.md b/docs/dev/reference/apis/components/motor.md
similarity index 100%
rename from docs/appendix/apis/components/motor.md
rename to docs/dev/reference/apis/components/motor.md
diff --git a/docs/appendix/apis/components/movement-sensor.md b/docs/dev/reference/apis/components/movement-sensor.md
similarity index 100%
rename from docs/appendix/apis/components/movement-sensor.md
rename to docs/dev/reference/apis/components/movement-sensor.md
diff --git a/docs/appendix/apis/components/power-sensor.md b/docs/dev/reference/apis/components/power-sensor.md
similarity index 100%
rename from docs/appendix/apis/components/power-sensor.md
rename to docs/dev/reference/apis/components/power-sensor.md
diff --git a/docs/appendix/apis/components/sensor.md b/docs/dev/reference/apis/components/sensor.md
similarity index 100%
rename from docs/appendix/apis/components/sensor.md
rename to docs/dev/reference/apis/components/sensor.md
diff --git a/docs/appendix/apis/components/servo.md b/docs/dev/reference/apis/components/servo.md
similarity index 100%
rename from docs/appendix/apis/components/servo.md
rename to docs/dev/reference/apis/components/servo.md
diff --git a/docs/appendix/apis/data-client.md b/docs/dev/reference/apis/data-client.md
similarity index 100%
rename from docs/appendix/apis/data-client.md
rename to docs/dev/reference/apis/data-client.md
diff --git a/docs/appendix/apis/fleet.md b/docs/dev/reference/apis/fleet.md
similarity index 99%
rename from docs/appendix/apis/fleet.md
rename to docs/dev/reference/apis/fleet.md
index 00adfc624a..ca670bc7f2 100644
--- a/docs/appendix/apis/fleet.md
+++ b/docs/dev/reference/apis/fleet.md
@@ -17,7 +17,7 @@ tags:
]
aliases:
- /program/apis/fleet/
- - /appendix/apis/fleet/
+ - /dev/reference/apis/fleet/
- /build/program/apis/fleet/
date: "2024-09-20"
# updated: "" # When the content was last entirely checked
diff --git a/docs/appendix/apis/ml-training-client.md b/docs/dev/reference/apis/ml-training-client.md
similarity index 100%
rename from docs/appendix/apis/ml-training-client.md
rename to docs/dev/reference/apis/ml-training-client.md
diff --git a/docs/appendix/apis/robot.md b/docs/dev/reference/apis/robot.md
similarity index 98%
rename from docs/appendix/apis/robot.md
rename to docs/dev/reference/apis/robot.md
index 53b94bbca2..f55ab1f6fe 100644
--- a/docs/appendix/apis/robot.md
+++ b/docs/dev/reference/apis/robot.md
@@ -12,7 +12,7 @@ date: "2022-01-01"
# updated: "" # When the content was last entirely checked
---
-The _machine API_ allows you to connect to your machine from within a supported [Viam SDK](/appendix/apis/), retrieve status information, and send commands remotely.
+The _machine API_ allows you to connect to your machine from within a supported [Viam SDK](/dev/reference/apis/), retrieve status information, and send commands remotely.
The machine API is supported for use with the [Viam Python SDK](https://python.viam.dev/autoapi/viam/robot/client/index.html#viam.robot.client.RobotClient), the [Viam Go SDK](https://pkg.go.dev/go.viam.com/rdk/robot/client#RobotClient), and the [Viam C++ SDK](https://cpp.viam.dev/classviam_1_1sdk_1_1RobotClient.html).
diff --git a/docs/appendix/apis/services/SLAM.md b/docs/dev/reference/apis/services/SLAM.md
similarity index 100%
rename from docs/appendix/apis/services/SLAM.md
rename to docs/dev/reference/apis/services/SLAM.md
diff --git a/docs/appendix/apis/services/_index.md b/docs/dev/reference/apis/services/_index.md
similarity index 76%
rename from docs/appendix/apis/services/_index.md
rename to docs/dev/reference/apis/services/_index.md
index fb20e2665f..3cee866623 100644
--- a/docs/appendix/apis/services/_index.md
+++ b/docs/dev/reference/apis/services/_index.md
@@ -4,6 +4,6 @@ title: "Service APIs"
weight: 5
empty_node: true
layout: "empty"
-canonical: "/appendix/apis/"
+canonical: "/dev/reference/apis/"
type: "docs"
---
diff --git a/docs/appendix/apis/services/base-rc.md b/docs/dev/reference/apis/services/base-rc.md
similarity index 100%
rename from docs/appendix/apis/services/base-rc.md
rename to docs/dev/reference/apis/services/base-rc.md
diff --git a/docs/appendix/apis/services/data.md b/docs/dev/reference/apis/services/data.md
similarity index 94%
rename from docs/appendix/apis/services/data.md
rename to docs/dev/reference/apis/services/data.md
index 2dc20cd47e..e29e32fa8f 100644
--- a/docs/appendix/apis/services/data.md
+++ b/docs/dev/reference/apis/services/data.md
@@ -17,7 +17,7 @@ The [data management service](/services/data/) supports the following methods:
{{< readfile "/static/include/services/apis/generated/data_manager-table.md" >}}
The data client API supports a separate set of methods that allow you to upload and export data to and from the Viam app.
-For information about that API, see [Data Client API](/appendix/apis/data-client/).
+For information about that API, see [Data Client API](/dev/reference/apis/data-client/).
## Establish a connection
diff --git a/docs/appendix/apis/services/generic.md b/docs/dev/reference/apis/services/generic.md
similarity index 94%
rename from docs/appendix/apis/services/generic.md
rename to docs/dev/reference/apis/services/generic.md
index 292de7b1a6..c142951b31 100644
--- a/docs/appendix/apis/services/generic.md
+++ b/docs/dev/reference/apis/services/generic.md
@@ -11,7 +11,7 @@ date: "2022-01-01"
# updated: "" # When the content was last entirely checked
---
-The generic service API allows you to give commands to your [generic services](/services/generic/) for running model-specific commands using [`DoCommand`](/appendix/apis/services/generic/#docommand).
+The generic service API allows you to give commands to your [generic services](/services/generic/) for running model-specific commands using [`DoCommand`](/dev/reference/apis/services/generic/#docommand).
The generic service supports the following methods:
diff --git a/docs/appendix/apis/services/ml.md b/docs/dev/reference/apis/services/ml.md
similarity index 100%
rename from docs/appendix/apis/services/ml.md
rename to docs/dev/reference/apis/services/ml.md
diff --git a/docs/appendix/apis/services/motion.md b/docs/dev/reference/apis/services/motion.md
similarity index 92%
rename from docs/appendix/apis/services/motion.md
rename to docs/dev/reference/apis/services/motion.md
index cce2557dec..ecb4f178bd 100644
--- a/docs/appendix/apis/services/motion.md
+++ b/docs/dev/reference/apis/services/motion.md
@@ -25,7 +25,7 @@ To get started using Viam's SDKs to connect to and control your machine, go to y
When executed, this sample code creates a connection to your machine as a client.
Because the motion service is enabled by default, you don't give it a `"name"` while configuring it.
-Use the name `"builtin"` to access the built-in motion service in your code with methods like [`FromRobot()`](/appendix/apis/services/motion/#fromrobot) that require a `ResourceName`.
+Use the name `"builtin"` to access the built-in motion service in your code with methods like [`FromRobot()`](/dev/reference/apis/services/motion/#fromrobot) that require a `ResourceName`.
Import the motion package for the SDK you are using:
diff --git a/docs/appendix/apis/services/navigation.md b/docs/dev/reference/apis/services/navigation.md
similarity index 100%
rename from docs/appendix/apis/services/navigation.md
rename to docs/dev/reference/apis/services/navigation.md
diff --git a/docs/appendix/apis/services/vision.md b/docs/dev/reference/apis/services/vision.md
similarity index 100%
rename from docs/appendix/apis/services/vision.md
rename to docs/dev/reference/apis/services/vision.md
diff --git a/docs/appendix/apis/sessions.md b/docs/dev/reference/apis/sessions.md
similarity index 92%
rename from docs/appendix/apis/sessions.md
rename to docs/dev/reference/apis/sessions.md
index c6cb319e5e..10b8bfd7fe 100644
--- a/docs/appendix/apis/sessions.md
+++ b/docs/dev/reference/apis/sessions.md
@@ -29,7 +29,7 @@ The period of time during which a client is connected to a machine is called a _
_Session management_ is a safety precaution that allows you to manage the clients that are authenticated and communicating with a machine's `viam-server` instance.
The default session management configuration checks for presence to ensures that a machine only moves when a client is actively connected and stops any components that remain running when a client disconnects.
This is especially important for machines that physically move.
-For example, imagine a wheeled rover gets a [`SetPower()`](/appendix/apis/components/base/#setpower) command as the last input from a client before the connection to the machine is interrupted.
+For example, imagine a wheeled rover gets a [`SetPower()`](/dev/reference/apis/components/base/#setpower) command as the last input from a client before the connection to the machine is interrupted.
Without session management, the API request from the client would cause the rover's motors to move, causing the machine to continue driving forever and potentially colliding with objects and people.
For more information, see [Client Sessions and Machine Network Connectivity](/sdks/connectivity/).
@@ -76,7 +76,7 @@ To manage your session with the session management API:
### Disable default session management
The `SessionsClient` that serves the session management API is automatically enabled on your machine.
-It is instantiated as part of your [`RobotClient`](/appendix/apis/robot/) instance (client of the Machine API).
+It is instantiated as part of your [`RobotClient`](/dev/reference/apis/robot/) instance (client of the Machine API).
If you want to disable it, you can pass the option to your machine, as demonstrated in the following code snippets:
{{< tabs >}}
@@ -126,6 +126,6 @@ You can do this with Viam's client SDKs.
### Use the session management API to manually manage sessions
-Use your [`RobotClient()`](/appendix/apis/robot/) instance to access the [`SessionsClient`](https://pkg.go.dev/go.viam.com/rdk/session) within your client SDK program.
+Use your [`RobotClient()`](/dev/reference/apis/robot/) instance to access the [`SessionsClient`](https://pkg.go.dev/go.viam.com/rdk/session) within your client SDK program.
This is a [gRPC](https://grpc.io/) client that `viam-server` instantiates at robot runtime.
Then, define your own [`SessionsClient`](https://github.com/viamrobotics/rdk/blob/main/robot/client/client.go).
diff --git a/docs/appendix/changelog.md b/docs/dev/reference/changelog.md
similarity index 100%
rename from docs/appendix/changelog.md
rename to docs/dev/reference/changelog.md
diff --git a/docs/appendix/glossary/api-namespace-triplet.md b/docs/dev/reference/glossary/api-namespace-triplet.md
similarity index 91%
rename from docs/appendix/glossary/api-namespace-triplet.md
rename to docs/dev/reference/glossary/api-namespace-triplet.md
index 852562aa27..d382bced49 100644
--- a/docs/appendix/glossary/api-namespace-triplet.md
+++ b/docs/dev/reference/glossary/api-namespace-triplet.md
@@ -13,7 +13,7 @@ The `namespace` for built-in Viam resources is `rdk`, while the `type` is `compo
`subtype` refers to a specific component or service, like a `camera` or `vision`.
One subtype can have various {{< glossary_tooltip term_id="model" text="models" >}}, custom or built-in, but they all must conform to the subtype's API definition.
-This requirement ensures that when a resource of that model is deployed, you can [interface with it](/sdks/) using the same [client API methods](/appendix/apis/) you would when programming resources of the same subtype with a different model.
+This requirement ensures that when a resource of that model is deployed, you can [interface with it](/sdks/) using the same [client API methods](/dev/reference/apis/) you would when programming resources of the same subtype with a different model.
For example:
diff --git a/docs/appendix/glossary/attribute.md b/docs/dev/reference/glossary/attribute.md
similarity index 100%
rename from docs/appendix/glossary/attribute.md
rename to docs/dev/reference/glossary/attribute.md
diff --git a/docs/appendix/glossary/base.md b/docs/dev/reference/glossary/base.md
similarity index 100%
rename from docs/appendix/glossary/base.md
rename to docs/dev/reference/glossary/base.md
diff --git a/docs/appendix/glossary/board.md b/docs/dev/reference/glossary/board.md
similarity index 100%
rename from docs/appendix/glossary/board.md
rename to docs/dev/reference/glossary/board.md
diff --git a/docs/appendix/glossary/client-application.md b/docs/dev/reference/glossary/client-application.md
similarity index 100%
rename from docs/appendix/glossary/client-application.md
rename to docs/dev/reference/glossary/client-application.md
diff --git a/docs/appendix/glossary/component.md b/docs/dev/reference/glossary/component.md
similarity index 100%
rename from docs/appendix/glossary/component.md
rename to docs/dev/reference/glossary/component.md
diff --git a/docs/appendix/glossary/fragment.md b/docs/dev/reference/glossary/fragment.md
similarity index 100%
rename from docs/appendix/glossary/fragment.md
rename to docs/dev/reference/glossary/fragment.md
diff --git a/docs/appendix/glossary/frame-system.md b/docs/dev/reference/glossary/frame-system.md
similarity index 100%
rename from docs/appendix/glossary/frame-system.md
rename to docs/dev/reference/glossary/frame-system.md
diff --git a/docs/appendix/glossary/frame.md b/docs/dev/reference/glossary/frame.md
similarity index 100%
rename from docs/appendix/glossary/frame.md
rename to docs/dev/reference/glossary/frame.md
diff --git a/docs/appendix/glossary/gantry.md b/docs/dev/reference/glossary/gantry.md
similarity index 100%
rename from docs/appendix/glossary/gantry.md
rename to docs/dev/reference/glossary/gantry.md
diff --git a/docs/appendix/glossary/grpc.md b/docs/dev/reference/glossary/grpc.md
similarity index 100%
rename from docs/appendix/glossary/grpc.md
rename to docs/dev/reference/glossary/grpc.md
diff --git a/docs/appendix/glossary/index.md b/docs/dev/reference/glossary/index.md
similarity index 100%
rename from docs/appendix/glossary/index.md
rename to docs/dev/reference/glossary/index.md
diff --git a/docs/appendix/glossary/location.md b/docs/dev/reference/glossary/location.md
similarity index 100%
rename from docs/appendix/glossary/location.md
rename to docs/dev/reference/glossary/location.md
diff --git a/docs/appendix/glossary/machine-config.md b/docs/dev/reference/glossary/machine-config.md
similarity index 100%
rename from docs/appendix/glossary/machine-config.md
rename to docs/dev/reference/glossary/machine-config.md
diff --git a/docs/appendix/glossary/machine.md b/docs/dev/reference/glossary/machine.md
similarity index 100%
rename from docs/appendix/glossary/machine.md
rename to docs/dev/reference/glossary/machine.md
diff --git a/docs/appendix/glossary/model-namespace-triplet.md b/docs/dev/reference/glossary/model-namespace-triplet.md
similarity index 100%
rename from docs/appendix/glossary/model-namespace-triplet.md
rename to docs/dev/reference/glossary/model-namespace-triplet.md
diff --git a/docs/appendix/glossary/model.md b/docs/dev/reference/glossary/model.md
similarity index 94%
rename from docs/appendix/glossary/model.md
rename to docs/dev/reference/glossary/model.md
index 0265a5ed5e..ec85f251fd 100644
--- a/docs/appendix/glossary/model.md
+++ b/docs/dev/reference/glossary/model.md
@@ -5,7 +5,7 @@ full_link:
short_description: A particular implementation of a resource. For example, UR5e is a model of the arm component subtype.
---
-A particular implementation of a {{< glossary_tooltip term_id="resource" text="resource" >}} {{< glossary_tooltip term_id="subtype" text="subtype" >}} that implements its [API](/appendix/apis/).
+A particular implementation of a {{< glossary_tooltip term_id="resource" text="resource" >}} {{< glossary_tooltip term_id="subtype" text="subtype" >}} that implements its [API](/dev/reference/apis/).
Models allow you to control hardware or software of a similar category, such as motors, with a consistent set of methods as an interface, even if the underlying implementation differs.
diff --git a/docs/appendix/glossary/modular-resource.md b/docs/dev/reference/glossary/modular-resource.md
similarity index 100%
rename from docs/appendix/glossary/modular-resource.md
rename to docs/dev/reference/glossary/modular-resource.md
diff --git a/docs/appendix/glossary/module.md b/docs/dev/reference/glossary/module.md
similarity index 100%
rename from docs/appendix/glossary/module.md
rename to docs/dev/reference/glossary/module.md
diff --git a/docs/appendix/glossary/mql.md b/docs/dev/reference/glossary/mql.md
similarity index 100%
rename from docs/appendix/glossary/mql.md
rename to docs/dev/reference/glossary/mql.md
diff --git a/docs/appendix/glossary/organization.md b/docs/dev/reference/glossary/organization.md
similarity index 100%
rename from docs/appendix/glossary/organization.md
rename to docs/dev/reference/glossary/organization.md
diff --git a/docs/appendix/glossary/part.md b/docs/dev/reference/glossary/part.md
similarity index 100%
rename from docs/appendix/glossary/part.md
rename to docs/dev/reference/glossary/part.md
diff --git a/docs/appendix/glossary/pin-number.md b/docs/dev/reference/glossary/pin-number.md
similarity index 100%
rename from docs/appendix/glossary/pin-number.md
rename to docs/dev/reference/glossary/pin-number.md
diff --git a/docs/appendix/glossary/process.md b/docs/dev/reference/glossary/process.md
similarity index 100%
rename from docs/appendix/glossary/process.md
rename to docs/dev/reference/glossary/process.md
diff --git a/docs/appendix/glossary/protobuf.md b/docs/dev/reference/glossary/protobuf.md
similarity index 100%
rename from docs/appendix/glossary/protobuf.md
rename to docs/dev/reference/glossary/protobuf.md
diff --git a/docs/appendix/glossary/rdk.md b/docs/dev/reference/glossary/rdk.md
similarity index 100%
rename from docs/appendix/glossary/rdk.md
rename to docs/dev/reference/glossary/rdk.md
diff --git a/docs/appendix/glossary/remote-part.md b/docs/dev/reference/glossary/remote-part.md
similarity index 100%
rename from docs/appendix/glossary/remote-part.md
rename to docs/dev/reference/glossary/remote-part.md
diff --git a/docs/appendix/glossary/resource.md b/docs/dev/reference/glossary/resource.md
similarity index 90%
rename from docs/appendix/glossary/resource.md
rename to docs/dev/reference/glossary/resource.md
index 38c6147fca..64908efa2f 100644
--- a/docs/appendix/glossary/resource.md
+++ b/docs/dev/reference/glossary/resource.md
@@ -17,4 +17,4 @@ Resources are individual, addressable elements of a machine.
Each part has local resources and can also have resources from another {{< glossary_tooltip term_id="remote-part" text="remote">}} machine part.
The capabilities of each resource are exposed through the part’s API.
-Each resource on your machine implements either one of the [existing Viam APIs](/appendix/apis/), or a [custom interface](/registry/advanced/#new-api-subtypes).
+Each resource on your machine implements either one of the [existing Viam APIs](/dev/reference/apis/), or a [custom interface](/registry/advanced/#new-api-subtypes).
diff --git a/docs/appendix/glossary/sdk.md b/docs/dev/reference/glossary/sdk.md
similarity index 90%
rename from docs/appendix/glossary/sdk.md
rename to docs/dev/reference/glossary/sdk.md
index 6c5eb52314..d4854df97e 100644
--- a/docs/appendix/glossary/sdk.md
+++ b/docs/dev/reference/glossary/sdk.md
@@ -1,7 +1,7 @@
---
title: SDK (Software Development Kit)
id: sdk
-full_link: /appendix/apis/
+full_link: /dev/reference/apis/
short_description: Viam provides software development kits (SDKs) to help you write client applications and create support for custom component types.
---
@@ -9,4 +9,4 @@ Viam provides software development kits (SDKs) to help you write client applicat
The SDKs wrap the `viam-server` {{< glossary_tooltip term_id="grpc" text="gRPC" >}} {{< glossary_tooltip term_id="viam-robot-api" text="Viam Robot API" >}} and streamline connection, authentication, and encryption.
-For more information, see [Interact with Resources with Viam's Client SDKs](/appendix/apis/).
+For more information, see [Interact with Resources with Viam's Client SDKs](/dev/reference/apis/).
diff --git a/docs/appendix/glossary/service.md b/docs/dev/reference/glossary/service.md
similarity index 100%
rename from docs/appendix/glossary/service.md
rename to docs/dev/reference/glossary/service.md
diff --git a/docs/appendix/glossary/setup.md b/docs/dev/reference/glossary/setup.md
similarity index 100%
rename from docs/appendix/glossary/setup.md
rename to docs/dev/reference/glossary/setup.md
diff --git a/docs/appendix/glossary/slam.md b/docs/dev/reference/glossary/slam.md
similarity index 100%
rename from docs/appendix/glossary/slam.md
rename to docs/dev/reference/glossary/slam.md
diff --git a/docs/appendix/glossary/smart-machine.md b/docs/dev/reference/glossary/smart-machine.md
similarity index 100%
rename from docs/appendix/glossary/smart-machine.md
rename to docs/dev/reference/glossary/smart-machine.md
diff --git a/docs/appendix/glossary/sql.md b/docs/dev/reference/glossary/sql.md
similarity index 100%
rename from docs/appendix/glossary/sql.md
rename to docs/dev/reference/glossary/sql.md
diff --git a/docs/appendix/glossary/subtype.md b/docs/dev/reference/glossary/subtype.md
similarity index 100%
rename from docs/appendix/glossary/subtype.md
rename to docs/dev/reference/glossary/subtype.md
diff --git a/docs/appendix/glossary/type.md b/docs/dev/reference/glossary/type.md
similarity index 100%
rename from docs/appendix/glossary/type.md
rename to docs/dev/reference/glossary/type.md
diff --git a/docs/appendix/glossary/viam-agent.md b/docs/dev/reference/glossary/viam-agent.md
similarity index 100%
rename from docs/appendix/glossary/viam-agent.md
rename to docs/dev/reference/glossary/viam-agent.md
diff --git a/docs/appendix/glossary/viam-micro-server.md b/docs/dev/reference/glossary/viam-micro-server.md
similarity index 100%
rename from docs/appendix/glossary/viam-micro-server.md
rename to docs/dev/reference/glossary/viam-micro-server.md
diff --git a/docs/appendix/glossary/viam-robot-api.md b/docs/dev/reference/glossary/viam-robot-api.md
similarity index 100%
rename from docs/appendix/glossary/viam-robot-api.md
rename to docs/dev/reference/glossary/viam-robot-api.md
diff --git a/docs/appendix/glossary/viam-server.md b/docs/dev/reference/glossary/viam-server.md
similarity index 100%
rename from docs/appendix/glossary/viam-server.md
rename to docs/dev/reference/glossary/viam-server.md
diff --git a/docs/appendix/glossary/web-sockets.md b/docs/dev/reference/glossary/web-sockets.md
similarity index 100%
rename from docs/appendix/glossary/web-sockets.md
rename to docs/dev/reference/glossary/web-sockets.md
diff --git a/docs/appendix/glossary/webrtc.md b/docs/dev/reference/glossary/webrtc.md
similarity index 100%
rename from docs/appendix/glossary/webrtc.md
rename to docs/dev/reference/glossary/webrtc.md
diff --git a/docs/sdks/_index.md b/docs/dev/reference/sdks/_index.md
similarity index 91%
rename from docs/sdks/_index.md
rename to docs/dev/reference/sdks/_index.md
index 3e09e5337f..7f7428faab 100644
--- a/docs/sdks/_index.md
+++ b/docs/dev/reference/sdks/_index.md
@@ -1,11 +1,10 @@
---
title: "Write control code with Viam SDKs"
linkTitle: "SDKs"
-weight: 650
+weight: 10
type: "docs"
description: "Program and control your machines in the languages you already know like Python, Go, TypeScript, C++, and Flutter."
no_list: true
-menuindent: true
images: ["/general/code.png"]
aliases:
- "product-overviews/sdk-as-client"
@@ -18,14 +17,14 @@ date: "2024-05-23"
# updated: "" # When the content was last entirely checked
---
-Viam's SDK libraries wrap Viam's [gRPC APIs](https://github.com/viamrobotics/api) for interacting with a machine's [components](/appendix/apis/#component-apis) and [services](/appendix/apis/#service-apis), as well as for [cloud capabilities](/appendix/apis/robot/), such as [data management](/appendix/apis/data-client/) and [fleet management](/appendix/apis/fleet/).
+Viam's SDK libraries wrap Viam's [gRPC APIs](https://github.com/viamrobotics/api) for interacting with a machine's [components](/dev/reference/apis/#component-apis) and [services](/dev/reference/apis/#service-apis), as well as for [cloud capabilities](/dev/reference/apis/robot/), such as [data management](/dev/reference/apis/data-client/) and [fleet management](/dev/reference/apis/fleet/).
You can run control code from anywhere; it does not necessarily have to be run on the same machine that runs `viam-server`.
![Diagram showing how a client connects to a machine with Viam. Diagram shows a client as a computer sending commands to a machine. Robot 1 then communicates with other robotic parts over gRPC and WebRTC and communicating that information back to the client.](/build/program/sdks/robot-client.png)
## Backend SDKs
-Use the backend SDK to build business logic to control [components](/appendix/apis/#component-apis) and [services](/appendix/apis/#service-apis), as well as manage your [fleet](/appendix/apis/fleet/) and [data](/appendix/apis/data-client/), and [billing information](/appendix/apis/billing-client/), or [provision](/fleet/provision/) machines.
+Use the backend SDK to build business logic to control [components](/dev/reference/apis/#component-apis) and [services](/dev/reference/apis/#service-apis), as well as manage your [fleet](/dev/reference/apis/fleet/) and [data](/dev/reference/apis/data-client/), and [billing information](/dev/reference/apis/billing-client/), or [provision](/fleet/provision/) machines.
With the backend SDKs you can also create custom {{< glossary_tooltip term_id="modular-resource" text="modular resources" >}}.
{{< sectionlist-custom >}}
@@ -36,7 +35,7 @@ With the backend SDKs you can also create custom {{< glossary_tooltip term_id="m
## Frontend SDKs
-Use the frontend SDK to control your machine's [components](/appendix/apis/#component-apis), as well as manage your [data](/appendix/apis/data-client/) or [provision](/fleet/provision/) machines.
+Use the frontend SDK to control your machine's [components](/dev/reference/apis/#component-apis), as well as manage your [data](/dev/reference/apis/data-client/) or [provision](/fleet/provision/) machines.
{{< sectionlist-custom >}}
{{% sectionlist-custom-item link="/sdks/typescript/" %}}
@@ -44,7 +43,7 @@ Use the frontend SDK to control your machine's [components](/appendix/apis/#comp
## Mobile SDK
-Use the mobile SDK to build iOS and Android apps to control your machine's [components](/appendix/apis/#component-apis), as well as manage your [fleet](/appendix/apis/fleet/) and [data](/appendix/apis/data-client/), or [provision](/fleet/provision/) machines.
+Use the mobile SDK to build iOS and Android apps to control your machine's [components](/dev/reference/apis/#component-apis), as well as manage your [fleet](/dev/reference/apis/fleet/) and [data](/dev/reference/apis/data-client/), or [provision](/fleet/provision/) machines.
{{< sectionlist-custom >}}
{{% sectionlist-custom-item link="/sdks/flutter/" %}}
@@ -118,7 +117,7 @@ Navigate to the **CONNECT** tab on your machine's page on the [Viam app](https:/
The sample code will show you how to authenticate and connect to a machine's `viam-server` instance, as well as some of the methods you can use on your configured components and services.
-For a full list of available API methods, see [Component APIs](/appendix/apis/#component-apis) and [Service APIs](/appendix/apis/#service-apis):
+For a full list of available API methods, see [Component APIs](/dev/reference/apis/#component-apis) and [Service APIs](/dev/reference/apis/#service-apis):
{{< cards >}}
{{% card link="/appendix/apis" customDescription="Usage examples for each API method." %}}
@@ -321,7 +320,7 @@ If you need to build apps with custom login flows, [contact us](mailto:support@v
## Run code
-After saving your [code sample](/sdks/#code-samples) and adding control logic with [Viam's SDKs](/appendix/apis/), run your program to control your Viam-connected machine.
+After saving your [code sample](/sdks/#code-samples) and adding control logic with [Viam's SDKs](/dev/reference/apis/), run your program to control your Viam-connected machine.
You can remotely control your machine from anywhere in the world.
If your machine and your personal computer are both connected to the Internet, you can run code to control your machine remotely from your personal computer.
@@ -329,7 +328,7 @@ If your machine and your personal computer are both connected to the Internet, y
{{}}
This method is convenient for most use cases because your machine and your personal computer do not have to be connected to the same WAN/LAN to issue control commands.
-When you run code on one computer, creating a client [session](/appendix/apis/sessions/), the code running on that computer sends instructions to your machine's `viam-server` instance over the Internet.
+When you run code on one computer, creating a client [session](/dev/reference/apis/sessions/), the code running on that computer sends instructions to your machine's `viam-server` instance over the Internet.
After editing your code to include your machine's [authentication credentials](#authentication), run a command to execute the program in the terminal of a computer with the appropriate programming language and [Viam SDK](/sdks/) installed:
@@ -397,7 +396,7 @@ For more information, see [How to create and deploy a new module](/how-tos/creat
Your machines do not need to be connected to the Internet for you to be able to run code.
As long as your machine is connected to the same LAN or WAN network as the device running the code, you can connect to it and run code.
-When you use the connection code sample from the [**CONNECT** tab](/sdks/#code-samples), that code establishes a [client session](/appendix/apis/sessions/) that automatically uses the [most efficient route](/sdks/connectivity/) to send commands to your machine.
+When you use the connection code sample from the [**CONNECT** tab](/sdks/#code-samples), that code establishes a [client session](/dev/reference/apis/sessions/) that automatically uses the [most efficient route](/sdks/connectivity/) to send commands to your machine.
That means that when the device your code runs on is on the same network as your machine, even if internet is available, the connection will choose the most efficient route and connect over LAN or WAN.
If you subsequently lose internet connectivity, but stay connected to LAN or WAN, the connection will thus remain.
@@ -411,7 +410,7 @@ Running everything on one machine is also convenient if you have a machine (for
{{}}
The script you run on-machine is the same as the script you run remotely or on a local network.
-When the connection code from the [**CONNECT** tab's **Code sample** page](/sdks/#code-samples) executes, it creates a [client session](/appendix/apis/sessions/) connected to your machine using the [most efficient route](/sdks/connectivity/).
+When the connection code from the [**CONNECT** tab's **Code sample** page](/sdks/#code-samples) executes, it creates a [client session](/dev/reference/apis/sessions/) connected to your machine using the [most efficient route](/sdks/connectivity/).
Because the code is running on the same machine as `viam-server`, the favored route for commands is automatically over localhost.
Install the appropriate programming language and [Viam SDK](/sdks/) on your machine and run a command to execute the program in the terminal of that machine instead of from a separate computer:
diff --git a/docs/sdks/connectivity.md b/docs/dev/reference/sdks/connectivity.md
similarity index 60%
rename from docs/sdks/connectivity.md
rename to docs/dev/reference/sdks/connectivity.md
index 5ebedc6cd1..1f2cda2680 100644
--- a/docs/sdks/connectivity.md
+++ b/docs/dev/reference/sdks/connectivity.md
@@ -12,7 +12,7 @@ date: "2022-01-01"
# updated: "" # When the content was last entirely checked
---
-When connecting to a machine using the connection code from the [**CONNECT** tab](/sdks/#code-samples), a [client session](/appendix/apis/sessions/) automatically uses the most efficient route to connect to your machine either through local LAN or WAN or the internet.
+When connecting to a machine using the connection code from the [**CONNECT** tab](/sdks/#code-samples), a [client session](/dev/reference/apis/sessions/) automatically uses the most efficient route to connect to your machine either through local LAN or WAN or the internet.
When a machine loses its connection to the internet but is still connected to a LAN or WAN:
@@ -25,10 +25,10 @@ When a machine loses its connection to LAN or WAN, all client sessions will time
## Client session timeout and end
-When your client cannot connect to your machine's `viam-server` instance, `viam-server` will end any current client [_sessions_](/appendix/apis/sessions/) on this machine and all client operations will [timeout automatically](/appendix/apis/sessions/) and halt: any active commands will be cancelled, stopping any moving parts, and no new commands will be able to reach the machine until the connection is restored.
+When your client cannot connect to your machine's `viam-server` instance, `viam-server` will end any current client [_sessions_](/dev/reference/apis/sessions/) on this machine and all client operations will [timeout automatically](/dev/reference/apis/sessions/) and halt: any active commands will be cancelled, stopping any moving parts, and no new commands will be able to reach the machine until the connection is restored.
-To disable the default behavior and manage resource timeout and reconfiguration over a networking session yourself, you can [disable the default behavior](/appendix/apis/sessions/#disable-default-session-management) of session management, then use [Viam's SDKs](/sdks/) in your code to make calls to [the session management API](https://pkg.go.dev/go.viam.com/rdk/session#hdr-API).
+To disable the default behavior and manage resource timeout and reconfiguration over a networking session yourself, you can [disable the default behavior](/dev/reference/apis/sessions/#disable-default-session-management) of session management, then use [Viam's SDKs](/sdks/) in your code to make calls to [the session management API](https://pkg.go.dev/go.viam.com/rdk/session#hdr-API).
## Configure a connection timeout
-When connecting to a machine using the [robot API](/appendix/apis/robot/) from a supported [Viam SDK](/appendix/apis/), you can configure an [optional timeout](/appendix/apis/robot/#configure-a-timeout) to account for intermittent or delayed network connectivity.
+When connecting to a machine using the [robot API](/dev/reference/apis/robot/) from a supported [Viam SDK](/dev/reference/apis/), you can configure an [optional timeout](/dev/reference/apis/robot/#configure-a-timeout) to account for intermittent or delayed network connectivity.
diff --git a/docs/sdks/cpp.md b/docs/dev/reference/sdks/cpp.md
similarity index 100%
rename from docs/sdks/cpp.md
rename to docs/dev/reference/sdks/cpp.md
diff --git a/docs/sdks/flutter.md b/docs/dev/reference/sdks/flutter.md
similarity index 100%
rename from docs/sdks/flutter.md
rename to docs/dev/reference/sdks/flutter.md
diff --git a/docs/sdks/go.md b/docs/dev/reference/sdks/go.md
similarity index 100%
rename from docs/sdks/go.md
rename to docs/dev/reference/sdks/go.md
diff --git a/docs/sdks/python/_index.md b/docs/dev/reference/sdks/python/_index.md
similarity index 100%
rename from docs/sdks/python/_index.md
rename to docs/dev/reference/sdks/python/_index.md
diff --git a/docs/sdks/python/python-venv.md b/docs/dev/reference/sdks/python/python-venv.md
similarity index 100%
rename from docs/sdks/python/python-venv.md
rename to docs/dev/reference/sdks/python/python-venv.md
diff --git a/docs/sdks/typescript.md b/docs/dev/reference/sdks/typescript.md
similarity index 100%
rename from docs/sdks/typescript.md
rename to docs/dev/reference/sdks/typescript.md
diff --git a/docs/sdks/use-extra-params.md b/docs/dev/reference/sdks/use-extra-params.md
similarity index 91%
rename from docs/sdks/use-extra-params.md
rename to docs/dev/reference/sdks/use-extra-params.md
index 3e1f980460..c958dca214 100644
--- a/docs/sdks/use-extra-params.md
+++ b/docs/dev/reference/sdks/use-extra-params.md
@@ -13,7 +13,7 @@ date: "2022-01-01"
# updated: "" # When the content was last entirely checked
---
-How to [use](#use) and [define](#define) the `extra` parameters that many {{< glossary_tooltip term_id="resource" text="resource" >}} [API methods](/appendix/apis/) offer in the Go and Python SDKs.
+How to [use](#use) and [define](#define) the `extra` parameters that many {{< glossary_tooltip term_id="resource" text="resource" >}} [API methods](/dev/reference/apis/) offer in the Go and Python SDKs.
## Use
@@ -21,7 +21,7 @@ You can use `extra` parameters with modular {{< glossary_tooltip term_id="resour
For example, a new model of [sensor](/components/sensor/), or a new model of {{< glossary_tooltip term_id="slam" text="SLAM" >}} service.
-The `extra` parameters in that built-in resource type's [API](/appendix/apis/) allow users to pass information to a resource's driver that isn't specified as a parameter for all models of the resource type.
+The `extra` parameters in that built-in resource type's [API](/dev/reference/apis/) allow users to pass information to a resource's driver that isn't specified as a parameter for all models of the resource type.
This is necessary to keep the API of resource types consistent across, for example, all models of [motor](/components/motor/) or all models of [camera](/components/camera/).
Send extra information in an API call in `extra` parameters as follows:
@@ -96,7 +96,7 @@ If `extra` information must be passed to a resource, it is handled within a new,
To do this, define a custom implementation of the resource's API as a new _model_, and modify the resource's API methods to handle the `extra` information you send.
Follow the steps in the [Modular Resources documentation](/how-tos/create-module/) to do so.
-For an example of how to check the values of keys in an `extra` parameter of a built-in resource [API method](/appendix/apis/), reference this modification to the built-in [sensor](/components/sensor/) resource type's [Readings](/appendix/apis/components/sensor/#getreadings) method in the code of a [new sensor model](/registry/):
+For an example of how to check the values of keys in an `extra` parameter of a built-in resource [API method](/dev/reference/apis/), reference this modification to the built-in [sensor](/components/sensor/) resource type's [Readings](/dev/reference/apis/components/sensor/#getreadings) method in the code of a [new sensor model](/registry/):
{{< tabs >}}
{{% tab name="Python" %}}
diff --git a/docs/dev/tools/_index.md b/docs/dev/tools/_index.md
new file mode 100644
index 0000000000..7bb329bb1f
--- /dev/null
+++ b/docs/dev/tools/_index.md
@@ -0,0 +1,10 @@
+---
+linkTitle: "Tools"
+title: "Tools"
+weight: 100
+layout: "empty"
+type: "docs"
+empty_page: true
+open_on_desktop: true
+header_only: true
+---
diff --git a/docs/cli.md b/docs/dev/tools/cli.md
similarity index 99%
rename from docs/cli.md
rename to docs/dev/tools/cli.md
index 4d1ff250da..bff512f301 100644
--- a/docs/cli.md
+++ b/docs/dev/tools/cli.md
@@ -1,7 +1,7 @@
---
title: "Viam CLI"
linkTitle: "CLI"
-weight: 700
+weight: 10
type: "docs"
no_list: true
description: "Manage and control your machines from the command line."
@@ -9,7 +9,6 @@ aliases:
- "/build/program/cli"
- /manage/cli/
- /fleet/cli/
-menuindent: true
images: ["/platform/cli.png"]
date: "2024-08-23"
# updated: "" # When the content was last entirely checked
diff --git a/docs/how-tos/_index.md b/docs/dev/tools/how-tos/_index.md
similarity index 99%
rename from docs/how-tos/_index.md
rename to docs/dev/tools/how-tos/_index.md
index 8f69da897f..91d523e83d 100644
--- a/docs/how-tos/_index.md
+++ b/docs/dev/tools/how-tos/_index.md
@@ -1,10 +1,9 @@
---
title: "How-to Guides"
linkTitle: "How-to Guides"
-weight: 200
+weight: 20
type: "docs"
images: ["/registry/module-puzzle-piece.svg"]
-#layout: "howto"
description: "Follow instructions for common tasks and workflows."
no_list: true
notoc: true
diff --git a/docs/how-tos/configure-teleop-workspace.md b/docs/dev/tools/how-tos/configure-teleop-workspace.md
similarity index 100%
rename from docs/how-tos/configure-teleop-workspace.md
rename to docs/dev/tools/how-tos/configure-teleop-workspace.md
diff --git a/docs/appendix/troubleshooting.md b/docs/dev/tools/troubleshooting.md
similarity index 99%
rename from docs/appendix/troubleshooting.md
rename to docs/dev/tools/troubleshooting.md
index ad567fdcfc..80019125cb 100644
--- a/docs/appendix/troubleshooting.md
+++ b/docs/dev/tools/troubleshooting.md
@@ -1,7 +1,7 @@
---
title: "Troubleshooting"
linkTitle: "Troubleshooting"
-weight: 40
+weight: 50
type: "docs"
description: "A guide to troubleshooting a Viam-based machine or system of machines with fixes to common problems."
date: "2022-01-01"
diff --git a/docs/dev/tools/tutorials/_index.md b/docs/dev/tools/tutorials/_index.md
new file mode 100644
index 0000000000..fd1e87318c
--- /dev/null
+++ b/docs/dev/tools/tutorials/_index.md
@@ -0,0 +1,31 @@
+---
+title: "Tutorials"
+linkTitle: "Tutorials"
+weight: 30
+type: docs
+layout: "tutorials"
+videos:
+ [
+ "/tutorials/videos/scuttle-gamepad-preview.webm",
+ "/tutorials/videos/scuttle-gamepad-preview.mp4",
+ ]
+videoAlt: "Drive a Scuttle robot with a Bluetooth gamepad."
+images:
+ [
+ "/tutorials/videos/scuttle-gamepad-preview.gif",
+ "/tutorials/try-viam-sdk/image1.gif",
+ ]
+description: "Build a machine yourself by following along with a tutorial."
+no_list: true
+hide_children: true
+sitemap:
+ priority: 1.0
+aliases:
+ - /build/
+outputs:
+ - rss
+ - html
+ - typesense
+date: "2024-10-20"
+# updated: "" # When the content was last entirely checked
+---
diff --git a/docs/dev/tools/tutorials/configure/_index.md b/docs/dev/tools/tutorials/configure/_index.md
new file mode 100644
index 0000000000..4490a561b3
--- /dev/null
+++ b/docs/dev/tools/tutorials/configure/_index.md
@@ -0,0 +1,10 @@
+---
+title: "Configuration Tutorials"
+linkTitle: "Configure"
+childTitleEndOverwrite: "Tutorial"
+weight: 20
+type: docs
+empty_node: true
+layout: "empty"
+canonical: "tutorials/"
+---
diff --git a/docs/dev/tools/tutorials/configure/build-a-mock-robot.md b/docs/dev/tools/tutorials/configure/build-a-mock-robot.md
new file mode 100644
index 0000000000..2867a3444e
--- /dev/null
+++ b/docs/dev/tools/tutorials/configure/build-a-mock-robot.md
@@ -0,0 +1,500 @@
+---
+title: "Build a Mock Robot"
+linkTitle: "Mock Robot"
+type: "docs"
+description: "Create a mock robot using just your personal computer to try using Viam without any robotic hardware."
+videos:
+ [
+ "/tutorials/build-a-mock-robot/mock-robot.webm",
+ "/tutorials/build-a-mock-robot/mock-robot.mp4",
+ ]
+images: ["/tutorials/build-a-mock-robot/mock-robot.gif"]
+videoAlt: "A mock arm's joint positions from the control tab of the Viam app."
+aliases:
+ - "/tutorials/build-a-mock-robot/"
+ - "/tutorials/how-to-build-a-mock-robot/"
+tags: ["mock", "simulation"]
+authors: []
+languages: ["python", "go"]
+viamresources: ["board", "arm", "motor"]
+platformarea: ["core"]
+level: "Beginner"
+date: "2022-10-11"
+# updated: ""
+cost: "0"
+toc_hide: true
+---
+
+
+
+In this tutorial you will build a mock robot to learn how to configure {{< glossary_tooltip term_id="machine" text="smart machines" >}} with Viam.
+You do not need any hardware to do this tutorial.
+
+Follow this tutorial to set up and control a robot with a `fake` [arm](/components/arm/fake/), [board](/components/board/), and [motor](/components/motor/), and an additional mock {{< glossary_tooltip term_id="part" text="sub-part" >}} with a [motor](/components/motor/).
+These `fake` components interact with Viam like real hardware but do not physically exist.
+
+## Set up a mock robot
+
+### Install and start `viam-server` on your computer
+
+You'll need the following hardware and software for this tutorial:
+
+- A computer running Linux or macOS
+- [Go](https://go.dev/doc/install) or [Python 3.9+](https://www.python.org/downloads/)
+
+If you don't already have a Viam account, sign up for one on the [Viam app](https://app.viam.com).
+
+{{% snippet "setup.md" %}}
+
+### Configure your mock robot
+
+[Configure your mock robot](/configure/) to represent a physical machine with robotic board, arm, and motor hardware.
+
+If you were using physical hardware, this process would provide `viam-server` with information about what hardware is attached to it and how to communicate with it.
+For this robot, you configure `viam-server` to use `fake` components that emulate physical hardware.
+
+1. Navigate to the **CONFIGURE** tab of your machine's page in the [Viam app](https://app.viam.com).
+2. Configure a [fake board component](/components/board/fake/):
+
+ - Click the **+** (Create) icon next to your machine part in the left-hand menu and select **Component**.
+ - Select the `board` type, then select the `fake` model.
+ - Enter the name `myBoard` for your board and click **Create**.
+ - Leave the attribute `fail_new` set to false.
+
+3. Configure a [fake arm component](/components/arm/fake/):
+
+ - Click the **+** (Create) icon next to your machine part in the left-hand menu and select **Component**.
+ - Select the `arm` type, then select the `fake` model.
+ - Enter the name `myArm` for your arm and click **Create**.
+ - Make your fake arm act like a [UR5e](https://www.universal-robots.com/products/ur5-robot/) by setting the attribute **arm-model** to `ur5e`.
+ The config panel should look like this:
+
+ {{< imgproc src="/tutorials/build-a-mock-robot/create-arm.png" alt="A fake arm being configured in Builder mode in the Viam app CONFIGURE tab." resize="600x" >}}
+
+ - Click **Save** in the top right of the window to save your config.
+
+4. Configure a [fake motor component](/components/motor/fake/):
+
+ - Click the **+** (Create) icon next to your machine part in the left-hand menu and select **Component**.
+ - Select the `motor` type, then select the `fake` model.
+ - Enter the name `myMotor` for your motor and click **Create**.
+ - Most motors are wired to a board which sends them signals.
+ Even though your motor is fake, make it more realistic by assigning it a `board`.
+ Select `myBoard` from the **board** dropdown.
+
+5. Click **Save**.
+
+You will need to reference the component names later when you connect to your mock robot with code.
+
+## Control your mock robot using the Viam app
+
+When you add components to your machine, the Viam app automatically generates a UI for them under the [**CONTROL** tab](/fleet/control/):
+
+{{< imgproc src="/tutorials/build-a-mock-robot/control-tab.png" alt="The Control tab with the fake arm, and motor components." resize="600x" >}}
+
+You can use the **CONTROL** tab UI to send commands to your machine.
+
+For example, you can control the direction and speed of your motor, or change the joint positions of your machineic arm.
+You can also see the machine's reported positions and speeds change.
+With real physical components, you would not only be able to control and see your machine's readings on this tab, but you would also see your machine move in the physical world.
+
+## Control your mock robot using a Viam SDK
+
+### Install a Viam SDK
+
+Install a Viam SDK (software development kit) so you can write custom logic to control the mock machine.
+Use the programming language you are most comfortable with.
+
+Refer to the appropriate SDK documentation for SDK installation instructions:
+
+- [Viam Python SDK](https://python.viam.dev/)
+- [Viam Go SDK](https://github.com/viamrobotics/rdk/tree/main/robot/client)
+
+### Connect to your mock robot with your code
+
+The easiest way to get started writing an application with Viam's SDKs is to use the sample code on the **CONNECT** tab.
+
+Navigate to your [machine's page on the Viam app](https://app.viam.com/robots), select the **Code sample** page on the **CONNECT** tab, select your SDK language (this tutorial uses Python or Go), and copy the sample code.
+
+{{% snippet "show-secret.md" %}}
+
+This code snippet imports all the necessary libraries, is pre-populated with your machine cloud credentials, and sets up a connection with the Viam app in the cloud.
+Next, paste that sample code into a file named index.py or index.go in your code editor, and save your file locally.
+
+You can now run the code.
+Doing so verifies that the Viam SDK is properly installed, that the `viam-server` instance on your machine is live, and that the computer running the program is able to connect to that instance.
+
+Run your code by entering the following in a new terminal on your computer:
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```sh {class="command-line" data-prompt="$"}
+python3 index.py
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```sh {class="command-line" data-prompt="$"}
+go run index.go
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+If you successfully configured your machine and it is able to connect to the Viam app you should see the program print a list of the various _{{< glossary_tooltip term_id="resource" text="resources" >}}_ that have been configured on your machine in the Viam app:
+
+![Command line output from running python3 index.py when your Raspberry Pi has correctly connected and initialized with the Viam app. The output is an array of resources that have been pulled from the Viam app. The list includes the motion service, arm component, data manager, board component and motor component. There is also a list of arm position and orientation values.](/tutorials/build-a-mock-robot/resource-output.png)
+
+### Control your mock robot
+
+Now, write a program that moves the mock robotic arm to a new random position every second.
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+First, import the [arm component](https://python.viam.dev/autoapi/viam/components/arm/client/index.html) from the Viam Python SDK, and the [random](https://docs.python.org/3/library/random.html) library.
+
+At the top of your index.py file, paste the following:
+
+```python {class="line-numbers linkable-line-numbers"}
+from viam.components.arm import Arm, JointPositions
+import random
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+At the top of your index.go file, paste the following:
+
+First, import the [arm component](https://github.com/viamrobotics/rdk/blob/main/components/arm/client.go) from the Viam Go SDK, and the [random](https://pkg.go.dev/math/rand) and [time](https://pkg.go.dev/time) libraries.
+
+```go {class="line-numbers linkable-line-numbers"}
+import (
+ "fmt"
+ "math/rand"
+ "time"
+ componentpb "go.viam.com/api/component/arm/v1"
+ "go.viam.com/rdk/components/arm"
+)
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Next, initialize your fake robotic arm.
+In the main function, paste the following.
+Make sure that the name of your fake arm matches the arm name you configured earlier.
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```python {class="line-numbers linkable-line-numbers"}
+arm = Arm.from_robot(machine, name='myArm')
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```go {class="line-numbers linkable-line-numbers"}
+myArm, err := arm.FromRobot(machine, "myArm")
+if err != nil {
+ logger.Fatalf("cannot get arm: %v", err)
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Now that your mock arm has been initialized, you can write some code to control it.
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```python {class="line-numbers linkable-line-numbers"}
+# Gets a random position for each servo on the arm that is within the safe
+# range of motion of the arm. Returns a new array of safe joint positions.
+def getRandoms():
+ return [random.randint(-90, 90),
+ random.randint(-120, -45),
+ random.randint(-45, 45),
+ random.randint(-45, 45),
+ random.randint(-45, 45)]
+
+
+# Moves the arm to a new random position every second
+async def randomMovement(arm: Arm):
+ while (True):
+ randomPositions = getRandoms()
+ newRandomArmJointPositions = JointPositions(values=randomPositions)
+ await arm.move_to_joint_positions(newRandomArmJointPositions)
+ print(await arm.get_joint_positions())
+ await asyncio.sleep(1)
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```go {class="line-numbers linkable-line-numbers"}
+// Returns an array of random floats between two numbers
+func getRandoms(min, max float64) []float64 {
+ res := make([]float64, 5)
+ for i := range res {
+ res[i] = min + rand.Float64() * (max - min)
+ }
+ return res
+}
+
+// Moves the arm to a new random position every second
+func randomMovement (ctx context.Context, a arm.Arm ) {
+ for {
+ randomPositions := getRandoms(-90, 90)
+ newRandomArmJointPositions := &componentpb.JointPositions{Values: randomPositions}
+ a.MoveToJointPositions(ctx, newRandomArmJointPositions, nil)
+ fmt.Println(a.JointPositions(ctx, nil))
+ time.Sleep(1 * time.Second)
+ }
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+You can run this code by invoking this function below your arm initialization in `main`.
+Your main function should look like this:
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```python {class="line-numbers linkable-line-numbers"}
+async def main():
+ machine = await connect()
+
+ print('Resources:')
+ print(machine.resource_names)
+
+ arm = Arm.from_robot(machine, 'myArm')
+ await randomMovement(arm)
+
+ await machine.close()
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```go {class="line-numbers linkable-line-numbers"}
+func main() {
+ // Connect to the machine...
+ myArm, err := arm.FromRobot(machine, "myArm")
+ if err != nil {
+ logger.Fatalf("cannot get arm: %v", err)
+ }
+ randomMovement(context.Background(), myArm)
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Now when you run this code, you should see the new mock arm positions listed in the command line.
+
+Verify that your mock robotic arm is working in the **CONTROL** tab of the [Viam app](https://app.viam.com).
+Watch the robotic arm's [`JointPositions()`](/dev/reference/apis/components/arm/#getjointpositions) changing in real-time along with the code on your development machine.
+
+
+ {{}}
+
+
+## Configure your machine's mock sub-part
+
+Now that you have your `fake` robotic arm, board, and motor working, add a `fake` motor sub-part to your machine.
+Imagine for the purpose of this tutorial that the `fake` motor we are adding controls a conveyor belt in front of your mock arm on an assembly line.
+
+### What is a sub-part?
+
+Usually, when building a {{< glossary_tooltip term_id="machine" text="machine" >}}, you pick out a [single-board computer](/components/board/) like the [Jetson Nano](https://github.com/viam-modules/nvidia/) or [Raspberry Pi](https://github.com/viam-modules/raspberry-pi).
+You follow the {{< glossary_tooltip term_id="setup" text="setup instructions" >}} to install `viam-server` on your [board](/components/board/), and you start operating your machine with that computer, adding the {{< glossary_tooltip term_id="component" text="components" >}} and {{< glossary_tooltip term_id="service" text="services" >}} you want to use to that `viam-server` instance.
+
+By utilizing {{< glossary_tooltip term_id="part" text="parts" >}}, you can expand upon this, chaining multiple computers together to build a complex robot with Viam:
+
+- Each individual computer-controlled unit of a machine is called a “{{< glossary_tooltip term_id="part" text="part" >}}” in Viam.
+- Typically, simple robots have just one part, but you can have as many parts as your project requires.
+- Parts are organized in a tree, with one of them being the _main_ part, and the others being _sub-parts_.
+- You can access any sub-part either directly, or through any part above it in the tree.
+- Each part runs a single `viam-server` instance.
+
+### Add a new sub-part in the Viam app
+
+Navigate to the **CONFIGURE** tab of your machine's page on the Viam app.
+
+Click the **+** (Create) icon next to your main machine part in the left-hand menu and select **Sub-part**.
+Your sub-part will automatically be created with a name like `your-machine-name-1`:
+
+{{< imgproc src="/tutorials/build-a-mock-robot/machine-nesting.png" alt="The CONFIGURE tab of the mock machine including the sub-part, showing the nested configuration in the left hand menu." resize="1000x" style="width:500px" >}}
+
+Configure your machine's new sub-part with a fake motor:
+
+1. Click the **+** (Create) icon next to your sub-part in the left-hand menu and select **Component**.
+1. Select the `motor` type, then select the `fake` model.
+1. Enter the name `motor2` for your motor and click **Create**:
+
+ {{< imgproc src="/tutorials/build-a-mock-robot/sub-part-motor.png" alt="The CONFIGURE tab. A new fake motor component called motor2 is being created under the sub-part." resize="400x" >}}
+
+1. Click **Save**.
+
+### Start a new instance of `viam-server` for your mock sub-part
+
+Every sub-part of a machine needs to run an instance of `viam-server`.
+Since you are using only one computer, you need to bind the sub-part to a new port so you can run two servers on your machine at the same time.
+
+The following instructions use port `8081`, but you can use any open port you want.
+
+1. Go to the **CONFIGURE** tab and find the sub-part's card.
+ Expand the card to view the **NETWORK** configuration section for the sub-part.
+1. Click **Set bind address**.
+1. In the **Host** field type `localhost`.
+1. In the **Port** field type `8081`.
+1. Click **Save**.
+
+Your **NETWORK** configuration appears as follows:
+
+{{< imgproc src="/tutorials/build-a-mock-robot/network-config.png" alt="The NETWORK configuration for the sub-part of the mock machine, with Host localhost and Port 8081." resize="1000x" style="width:500px" >}}
+
+### Run a second instance of `viam-server` for your sub-part
+
+Now, it's time to run `viam-server` on your sub-part.
+This instance of `viam-server` will work with the main part's instance of `viam-server` as two parts of one machine.
+
+Stay on the **CONFIGURE** tab.
+Click the **...** (Actions) icon on the right side of the sub-part's card and select **View setup instructions** to open the sub-part's setup instructions.
+Select the platform you want to run `viam-server` on and follow the instructions until you receive confirmation that your sub-part has connected.
+
+Now that you have two instances of `viam-server` running on your local machine, you should be able to see both your main robot arm and your new mock sub motor listed on your main machine's **CONTROL** tab.
+
+{{< imgproc src="/tutorials/build-a-mock-robot/control-all.png" alt="Screenshot of the Viam app's CONTROL tab for the main part that lists the main arm, and the sub part motor component." resize="800x" style="width:600px" >}}
+
+To test that your motor sub-part has been added to your machine, run your Python or Go script again.
+Review the output of your program that prints the machine's resources to see your sub-part's motor's name listed.
+
+## Control a sub-part using the Viam SDK
+
+Now that you have your mock sub-part connected to your main part under your mock robot, you can control all of your sub-part's components and services with Viam's SDKs.
+
+In your main function, you need to instantiate your mock sub motor.
+Make sure your sub-part's name and motor's name matches what you have configured.
+This code uses the name `SubPart` as a placeholder.
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```python {class="line-numbers linkable-line-numbers"}
+motor = Motor.from_robot(robot=machine, name='SubPart:motor2')
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```go {class="line-numbers linkable-line-numbers"}
+myMotor, err := motor.FromRobot(machine, "motor2")
+if err != nil {
+ logger.Fatalf("cannot get motor: %v", err)
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Write a function that toggles your sub-part's motor on and off every second:
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```python {class="line-numbers linkable-line-numbers"}
+# Toggles the motor on and off every second
+async def toggleMotor(motor: Motor):
+ while (True):
+ await motor.set_power(1)
+ print("go")
+ await asyncio.sleep(1)
+ await motor.stop()
+ print("stop")
+ await asyncio.sleep(1)
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```go {class="line-numbers linkable-line-numbers"}
+// Toggles the motor on and off every second
+func toggleMotor (ctx context.Context, m motor.Motor) {
+ for {
+ m.SetPower(ctx, 1, nil)
+ fmt.Println("go")
+ time.Sleep(1 * time.Second)
+ m.Stop(ctx, nil)
+ fmt.Println("stop")
+ time.Sleep(1 * time.Second)
+ }
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Now, invoke your new function in `main()`.
+Comment out invoking `randomMovement()` to focus on testing the sub-part.
+Your main function should look similar to this snippet:
+
+{{< tabs >}}
+{{% tab name="Python" %}}
+
+```python {class="line-numbers linkable-line-numbers"}
+async def main():
+ machine = await connect()
+ print('Resources:')
+ print(machine.resource_names)
+ arm = Arm.from_robot(machine, name='myArm')
+ motor = Motor.from_robot(machine, name='SubPart:motor2')
+ await toggleMotor(motor)
+ # await randomMovement(arm)
+ await machine.close()
+```
+
+{{% /tab %}}
+{{% tab name="Go" %}}
+
+```go {class="line-numbers linkable-line-numbers"}
+func main() {
+ // Connect to the machine...
+ myMotor, err := motor.FromRobot(machine, "motor2")
+ if err != nil {
+ logger.Fatalf("cannot get motor: %v", err)
+ }
+ toggleMotor(context.Background(), myMotor)
+
+ myArm, err := arm.FromRobot(machine, "myArm")
+ if err != nil {
+ logger.Fatalf("cannot get arm: %v", err)
+ }
+ // randomMovement(context.Background(), myArm)
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Run this code to see your mock sub-part's motor toggling between running and idle in real time from the Viam app!
+
+{{}}
+
+## Next steps
+
+In this tutorial, we showed you how to set up a mock robot with a sub-part so that you can learn more about using fake components, setting up a local development environment, and writing code using a Viam SDK.
+
+If you're ready to get started with building robots with real hardware components, pick up a [board](/components/board/) and try following another [tutorial](/tutorials/).
diff --git a/docs/dev/tools/tutorials/configure/configure-rover.md b/docs/dev/tools/tutorials/configure/configure-rover.md
new file mode 100644
index 0000000000..3c98a6ffdd
--- /dev/null
+++ b/docs/dev/tools/tutorials/configure/configure-rover.md
@@ -0,0 +1,497 @@
+---
+title: "Configure a Rover like Yahboom or SCUTTLE"
+linkTitle: "Configure a Rover"
+type: "docs"
+description: "Configure a rover like the a Yahboom 4WD Rover or a SCUTTLE robot on the Viam platform."
+images: ["/tutorials/scuttlebot/scuttle-on-floor-cropped.png"]
+imageAlt: "A SCUTTLE robot on a carpeted floor."
+tags: ["base", "camera", "scuttle", "yahboom"]
+aliases:
+ - "/tutorials/scuttlebot"
+ - "/tutorials/scuttlebot/scuttlebot"
+ - "/tutorials/yahboom-rover/"
+ - "/tutorials/control/yahboom-rover/"
+authors: ["Hazal Mestci"]
+languages: ["python", "go"]
+viamresources: ["board", "motor", "camera", "base", "encoder"]
+platformarea: ["core"]
+level: "Beginner"
+date: "2022-08-02"
+updated: "2024-04-17"
+cost: 540
+---
+
+This tutorial will guide you through configuring a rover.
+
+
+
+If you are using a SCUTTLE, a Yahboom rover, or a different rover, this tutorial covers instructions for your rover model.
+
+{{< alert title="Viam Rover" color="note" >}}
+If you are using a Viam Rover, use the [Viam Rover tutorial fragment](/appendix/try-viam/rover-resources/rover-tutorial-fragments/) instead.
+{{< /alert >}}
+
+## Requirements
+
+- A running an instance of `viam-server`.
+ See our [Installation Guide](/installation/viam-server-setup/) for instructions.
+- A rover like the [SCUTTLE robot](https://www.scuttlerobot.org/shop/) or the [Yahboom 4WD Smart Robot](https://category.yahboom.net/collections/robotics/products/4wdrobot)
+
+Make sure your rover is assembled before starting this tutorial.
+
+## Start configuring your robot
+
+{{% snippet "setup.md" %}}
+
+Once connected, navigate to the machine's **CONFIGURE** tab.
+
+![A SCUTTLE robot on a carpeted floor.](/tutorials/scuttlebot/scuttle-on-floor.png)
+
+The configuration for each rover is different depending on which {{< glossary_tooltip term_id="component" text="components" >}} your rover is composed of.
+In the following, you can see two popular examples with components that are present on most rovers:
+
+## Configure the board
+
+The first component you will add is the [board](/components/board/) which represents the Raspberry Pi to which the other components are wired.
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `board` type, then select the `viam:raspberry-pi:rpi` model.
+Enter `local` as the name and click **Create**.
+You can use a different name but will then need to adjust the name in the following steps to the name you choose.
+
+![An example board configuration in the app builder UI. The name (local), type (board) and model (pi) are shown. No other attributes are configured.](/components/board/pi-ui-config.png)
+
+You don't need to add any attributes for your board.
+
+## Configuring the motors and encoders
+
+### Configure the encoders
+
+{{< alert title="Note" color="note" >}}
+Not all rovers require the configuration of encoders.
+If your motors work without encoders, skip to [configuring your motors](#configure-the-motors).
+{{< /alert >}}
+
+Configure the left and right encoders as follows:
+
+{{< tabs >}}
+{{% tab name="SCUTTLE" %}}
+
+{{< tabs name="Configure AMS-AS5048 Encoders" >}}
+{{% tab name="Config Builder" %}}
+
+Start with the right encoder:
+
+#### Right encoder
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `encoder` type, then select the `AMS-AS5048` model.
+Enter `renc` as the name and click **Create**.
+
+Click the **board** dropdown list and select the name of your board, `local`.
+
+In the **i2c bus** field type `1`, and in the **i2c address** field type `65`.
+
+#### Left encoder
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `encoder` type, then select the `AMS-AS5048` model.
+Enter `lenc` as the name for your encoder and click **Create**.
+
+Click the **board** dropdown list and select the name of your board, `local`.
+
+In the **i2c bus** field type `1`, and in the **i2c address** field type `64`.
+
+{{% /tab %}}
+{{% tab name="JSON" %}}
+
+Add the following JSON objects to the `components` array:
+
+```json {class="line-numbers linkable-line-numbers"}
+{
+ "name": "lenc",
+ "model": "AMS-AS5048",
+ "type": "encoder",
+ "namespace": "rdk",
+ "attributes": {
+ "connection_type": "i2c",
+ "i2c_attributes": {
+ "i2c_bus": "1",
+ "i2c_addr": 64
+ }
+ }
+},
+{
+ "name": "renc",
+ "model": "AMS-AS5048",
+ "type": "encoder",
+ "namespace": "rdk",
+ "attributes": {
+ "connection_type": "i2c",
+ "i2c_attributes": {
+ "i2c_bus": "1",
+ "i2c_addr": 65
+ }
+ }
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+{{% /tab %}}
+{{% tab name="Other" %}}
+
+Follow the instructions for the [model of encoder](/components/encoder/#configuration) your rover uses to configure your encoders and configure at least a `right` and a `left` encoder.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+### Configure the motors
+
+{{< tabs name="motors-config">}}
+{{% tab name="SCUTTLE" %}}
+
+{{< tabs name="gpio-config">}}
+{{% tab name="Config Builder" %}}
+
+Start with the right motor:
+
+#### Right motor
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `motor` type, then select the `gpio` model.
+Enter `right` as the name or use the suggested name for your motor and click **Create**.
+
+Then from the **Board** dropdown, select `local`, the Raspberry Pi the motor is wired to.
+
+Select `Encoded` in the **Encoder** section and select `renc` as the **encoder** and set **ticks per rotation** to `2`.
+
+Next, describe how the motor is wired to the Pi:
+
+1. Switch the Component Pin Assignment Type to `In1/In2`.
+2. Set **A/In1** to `16`.
+3. Set **B/In2** to `15`.
+4. Leave the `pwm` (pulse-width modulation) pin blank, because this specific motor driver's configuration does not require a separate PWM pin.
+
+![The motor config panel.](/tutorials/scuttlebot/pi-wheel.png)
+
+#### Left motor
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `motor` type, then select the `gpio` model.
+Enter `left` as the name or use the suggested name for your motor and click **Create**.
+
+Then select `local` from the **Board** dropdown to choose the Raspberry Pi the motor is wired to.
+
+Select `Encoded` in the **Encoder** section and select `lenc` as the **encoder** and set **ticks per rotation** to `2`.
+
+Next, describe how the motor is wired to the Pi:
+
+1. Switch the Component Pin Assignment Type to `In1/In2`.
+2. Set **A/In1** to `12`.
+3. Set **B/In2** to `11`.
+4. Leave the `pwm` (pulse-width modulation) pin blank, because this specific motor driver's configuration does not require a separate PWM pin.
+
+{{% /tab %}}
+{{% tab name="JSON" %}}
+
+Add the following JSON objects to the `components` array:
+
+```json
+{
+ "name": "right",
+ "model": "gpio",
+ "type": "motor",
+ "namespace": "rdk",
+ "attributes": {
+ "pins": {
+ "a": "16",
+ "b": "15",
+ "pwm": "",
+ "dir": ""
+ },
+ "board": "local",
+ "dir_flip": false,
+ "ticks_per_rotation": 2
+ },
+ "depends_on": [ "local" ]
+},
+{
+ "name": "left",
+ "model": "gpio",
+ "type": "motor",
+ "namespace": "rdk",
+ "attributes": {
+ "pins": {
+ "a": "12",
+ "b": "11",
+ "pwm": ""
+ },
+ "board": "local",
+ "dir_flip": false,
+ "ticks_per_rotation": 2
+ },
+ "depends_on": [ "local" ]
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+{{% /tab %}}
+{{% tab name="Yahboom" %}}
+
+Since both right (and left) side motors of the Yahboom rover are wired together to a single motor driver, you configure the right (and left) side motors as a single [motor component](/components/motor/).
+
+Start with the right set of wheels.
+
+#### Right motor
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `motor` type, then select the `gpio` model.
+Enter `right` as the name or use the suggested name for your motor and click **Create**.
+
+![G P I O motor config in the builder UI with the In1 and In2 pins configured and the PWM pin field left blank.](/components/motor/gpio-config-ui.png)
+
+Click the **Board** dropdown and select `local` as the board the motor driver is wired to.
+Next, configure the **Component Pin Assignment** section to represent how the motor is wired to the board.
+In the **Component Pin Assignment** section of the right motor card, toggle the **Type** to **In1/In2** to use the compatible mode for this motor driver.
+
+If you followed the setup instructions for putting together your Yahboom rover correctly, you can set the **pins** as follows:
+
+- `a` to `35`
+- `b` to `37`
+- `pwm` (pulse-width modulation) to `33`.
+
+Leave `dir` pin blank, because Yahboom's motor driver uses an a/b/pwm configuration.
+
+Click **Show more** and set `max_rpm` to `300`.
+You can ignore the other optional attributes.
+
+#### Left motor
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `motor` type, then select the `gpio` model.
+Enter `left` as the name or use the suggested name for your motor and click **Create**.
+
+Click the **Board** dropdown and select `local` as the board the motor driver is wired to.
+Next, configure the **Component Pin Assignment** section to represent how the motor is wired to the board.
+In the **Component Pin Assignment** section of the right motor card, toggle the **Type** to **In1/In2** to use the compatible mode for this motor driver.
+
+If you followed the setup instructions for putting together your Yahboom rover correctly, you can set the **pins** as follows:
+
+- `a` to `38`
+- `b` to `40`
+- `pwm` (pulse-width modulation) to `36`.
+
+Leave `dir` pin blank, because Yahboom's motor driver uses an a/b/pwm configuration.
+
+Click **Show more** and set `max_rpm` to `300`.
+You can ignore the other optional attributes.
+
+{{% /tab %}}
+{{% tab name="Other" %}}
+
+Follow the instructions for the [model of motor](/components/motor/#configuration) your rover uses to configure your motors and configure at least a `right` and a `left` motor.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+#### Test the motor configuration
+
+{{< alert title="Caution" color="caution" >}}
+
+Ensure the rover has sufficient space to drive around without hitting anyone or anything.
+
+If you don't have enough space, consider holding your robot off the ground so it cannot collide with anything unexpected.
+
+{{< /alert >}}
+
+Now that you have configured your motors, you can actuate them.
+Make sure your machine is turned on.
+Navigate to the **Control** tab.
+
+You'll see a panel for each configured component.
+
+![Motor panels](/tutorials/scuttlebot/scuttle-bothmotors.png)
+
+Click on the panel for the right `motor`.
+
+![Power level adjustment](/tutorials/scuttlebot/pi-moverhmotor.png)
+
+Try changing the motor's **power** level and click **Run**.
+
+{{< alert title="Caution" color="caution" >}}
+Be careful when using your motors!
+Start with the power level set to 20% and increase it incrementally (about 10% each time) until the wheel rotates at a reasonable speed, clicking **Run** at each increment.
+If you hear a "whining" sound from the motor, the power level is not high enough to turn the armature.
+If this happens, increase the power level by 10% increments until it starts to turn.
+{{< /alert >}}
+
+If your wheel turns in reverse when it should turn forward, add the `dir_flip` attribute to the motor's configuration, by clicking **Show more** and setting the attribute to "true."
+
+There, you should see a panel for the right motor: you can use this panel to set the motor's power level.
+
+## (Optional) Configure the camera
+
+Optionally, add a camera to your rover.
+
+{{< tabs name="Configure a Webcam" >}}
+{{% tab name="Config Builder" %}}
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `camera` type, then select the `webcam` model.
+Enter a name or use the suggested name for your camera and click **Create**.
+
+{{< imgproc src="/components/camera/configure-webcam.png" alt="Configuration of a webcam camera in the Viam app config builder." resize="1200x" style="width=600x" >}}
+
+If you click on the **Video Path** field while your robot is live, a dropdown autopopulates with identified camera paths.
+
+{{% /tab %}}
+{{% tab name="JSON" %}}
+
+```json {class="line-numbers linkable-line-numbers"}
+{
+ "name": "Webcam",
+ "model": "webcam",
+ "type": "camera",
+ "namespace": "rdk",
+ "attributes": {
+ "video_path": ""
+ }
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+If your rover has its camera mounted on a pair of [servos](/components/servo/), like the Yahboom rover, you can use these to control the pan and tilt of the camera.
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `servo` type, then select the `viam:raspberry-pi:pi-servo` model.
+Enter `pan` as the name and click **Create**.
+
+Set `Depends On` to `local`, and `pin` to the pin the servo is wired to (`23` for the Yahboom rover).
+
+Finally, add the tilt `servo` as well.
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `servo` type, then select the `viam:raspberry-pi:pi-servo` model.
+Enter `tilt` as the name and click **Create**.
+
+Set `Depends On` to `local`, and `pin` to the pin the servo is wired to (`21` for the Yahboom rover).
+
+### Test the camera stream
+
+{{< readfile "/static/include/components/camera-view-camera-stream.md" >}}
+
+## Configure the base
+
+Next, configure the [base component](/components/base/), which describes the geometry of your chassis and wheels so that the software can calculate how to steer the rover in a coordinated way.
+Configuring a {{% glossary_tooltip term_id="base" text="base"%}} component also provides you with a nice UI for moving the rover around.
+
+{{< alert title="Note" color="note" >}}
+Viam supports most rovers with built-in models like the [`wheeled`](/components/base/wheeled/) base.
+If your rover is not supported out of the box, follow the [Create a Modular Resource to Control a Rover](/tutorials/custom/controlling-an-intermode-rover-canbus/) tutorial to create a model for your rover or mobile robot.
+{{< /alert >}}
+
+{{< tabs name="Configure a Wheeled Base" >}}
+{{% tab name="Config Builder" %}}
+
+Click the **+** icon next to your machine part in the left-hand menu and select **Component**.
+Select the `base` type, then select the `wheeled` model.
+Enter a name or use the suggested name for your base and click **Create**.
+
+{{< tabs >}}
+{{% tab name="SCUTTLE" %}}
+
+1. Select the motors attached to the base in the fields as your **right** and **left** motors.
+2. Enter `250` for `wheel_circumference_mm`.
+3. Enter `400` for `width_mm` (measured between the midpoints of the wheels).
+
+{{% /tab %}}
+{{% tab name="Yahboom" %}}
+
+1. Select the motors attached to the base in the fields as your **right** and **left** motors.
+2. Enter `220` for `wheel_circumference_mm`.
+3. Enter `150` for `width_mm` (measured between the midpoints of the wheels).
+
+{{% /tab %}}
+{{% tab name="Other" %}}
+
+1. Select the motors attached to the base in the fields as your **right** and **left** motors.
+2. Measure the wheel circumference in mm and enter it in the field for `wheel_circumference_mm`.
+3. Measure the width in mm between the midpoints of the wheels and enter it in the field for `width_mm` (measured between the midpoints of the wheels).
+
+{{% /tab %}}
+{{< /tabs >}}
+
+{{< imgproc src="/components/base/wheeled-base-ui-config.png" alt="An example configuration for a wheeled base in the Viam app config builder, with Attributes & Depends On dropdowns and the option to add a frame." resize="1200x" style="width: 900px" >}}
+
+{{% /tab %}}
+{{% tab name="JSON" %}}
+
+```json
+{
+ "components": [
+ {
+ "attributes": {
+ "board": "local",
+ "pins": {
+ "pwm": "",
+ "a": "16",
+ "b": "15"
+ }
+ },
+ "model": "gpio",
+ "name": "right",
+ "type": "motor"
+ },
+ {
+ "attributes": {
+ "board": "local",
+ "pins": {
+ "pwm": "",
+ "a": "12",
+ "b": "11"
+ }
+ },
+ "model": "gpio",
+ "name": "left",
+ "type": "motor"
+ },
+ {
+ "attributes": {
+ "left": ["left"],
+ "right": ["right"],
+ "wheel_circumference_mm": 250,
+ "width_mm": 400
+ },
+ "model": "wheeled",
+ "name": "your-wheeled-base",
+ "type": "base"
+ }
+ ]
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Save the config by clicking **Save** at the top right of the page.
+
+### Test the base
+
+{{< readfile "/static/include/components/test-control/base-control.md" >}}
+
+## Next steps
+
+Now that you have fully configured your SCUTTLE robot, you can drive it around and view its camera stream.
+
+To take things to the next level, check out one of the following tutorials:
+
+{{< cards >}}
+{{% card link="/tutorials/services/color-detection-scuttle" %}}
+{{% card link="/tutorials/control/gamepad/" %}}
+{{% card link="/tutorials/services/webcam-line-follower-robot/" %}}
+{{< /cards >}}
diff --git a/docs/dev/tools/tutorials/configure/pet-photographer.md b/docs/dev/tools/tutorials/configure/pet-photographer.md
new file mode 100644
index 0000000000..4209279ebc
--- /dev/null
+++ b/docs/dev/tools/tutorials/configure/pet-photographer.md
@@ -0,0 +1,1009 @@
+---
+title: "Pet Photographer: Create a Data Filtering Module"
+linkTitle: "Pet Photographer"
+type: "docs"
+description: "Use the filter modular component in the Viam app to photograph your pet in their collar."
+tags: ["vision", "filter", "camera", "detector", "services"]
+imageAlt: "Filtered data from the custom colorfiltercam in the DATA tab showing only photos of a dog wearing a blue collar"
+images: ["/tutorials/pet-photographer/data-capture.png"]
+authors: ["Sky Leilani"]
+languages: ["go", "python"]
+viamresources: ["vision", "camera", "data_manager"]
+platformarea: ["data", "registry"]
+level: "Intermediate"
+date: "2023-09-17"
+# updated: "2024-04-19"
+cost: "0"
+no_list: true
+toc_hide: true
+---
+
+
+
+If your machine [captures](/services/data/) a lot of data, you might want to filter captured data to selectively store only the data you are interested in.
+For example, you might want to use your smart machine's camera to capture images based on specific criteria, such as the presence of a certain color, and omit captured images that don't meet that criteria.
+
+In this tutorial, you will use a custom {{< glossary_tooltip term_id="module" text="module" >}} to function as a color filter, and use it with a [camera](/components/camera/) to only capture images where your pet is in the frame in the following way:
+
+1. Attach a colored object, such as a blue collar, to your pet.
+1. Set up a camera in an area where your pet is likely to appear in the frame, and configure the data management service to capture and sync images from that camera.
+1. Configure the `colorfilter` custom module to filter captured images from your camera, saving them only when your pet, along with their easily-identifiable colored object, is present in the frame.
+
+ {{}}
+
+The source code for this module is available on the [`modular-filter-examples` GitHub repository](https://github.com/viam-labs/modular-filter-examples) .
+In addition to the `colorfilter` module used in this tutorial, the example repository also includes a [sensor reading filter](https://github.com/viam-labs/modular-filter-examples/tree/main/sensorfilter) which you could use to control and filter the data recorded by a [sensor component](/components/sensor/).
+
+## Hardware requirements
+
+To create your own filtering pet photographer robot, you'll need the following hardware:
+
+- A computer
+- A [webcam](/components/camera/webcam/) or other type of [camera](/components/camera/)
+- A colored object, such as a blue collar for enhanced accuracy _(optional)_
+
+{{< alert title="Tip" color="tip" >}}
+In this tutorial, the camera is configured to identify and filter images with the color blue, as it is less common in many environments.
+If your pet already has a distinct color that is different from their environment, you can also configure your camera to use that color to identify pictures of your pet.
+{{< /alert >}}
+
+Make sure your webcam is connected to your computer.
+
+## Setup
+
+{{% snippet "setup.md" %}}
+
+{{< alert title="Note" color="note" >}}
+Your `viam-server` must be [version 0.8.0](https://github.com/viamrobotics/rdk/releases/tag/v0.8.0-rc0) or newer, as filtering capabilities were introduced in the RDK starting from that version.
+{{< /alert >}}
+
+Then, install [Go](https://go.dev/dl/) or [Python](https://www.python.org/downloads/) on both your local development computer and on your machine's board if they are not the same device.
+
+## Add the custom module
+
+In this tutorial, you can choose to add custom data filtering to your machine in one of two ways:
+
+1. [Download the `colorfilter` module](#download-the-colorfilter-module) from Viam and get started quickly.
+1. [Code your own color filtering module](#code-your-own-module), exploring the process of building a module from scratch.
+
+### Download the colorfilter module
+
+Follow the instructions below to download the `colorfilter` module in your preferred programming language:
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+
+1. Clone the [`colorfilter` module](https://github.com/viam-labs/modular-filter-examples) from GitHub onto your computer:
+
+ ```{class="command-line" data-prompt="$"}
+ git clone https://github.com/viam-labs/modular-filter-examples.git
+ ```
+
+1. Navigate to the Python color filter directory, `pycolorfilter`.
+1. Note the path to your module's executable, run.sh, for later use.
+1. [Add the `colorfilter` module to your smart machine as a local module](#add-as-a-local-module) and continue the tutorial from there.
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+1. Clone the [`colorfilter` module](https://github.com/viam-labs/modular-filter-examples) from GitHub onto your machine's computer:
+
+ ```{class="command-line" data-prompt="$"}
+ git clone https://github.com/viam-labs/modular-filter-examples.git
+ ```
+
+1. Navigate to the Go color filter directory, `colorfilter`.
+1. Inside of the `module` directory, [compile the executable](/how-tos/create-module/#compile-or-package-your-module) that runs your module.
+1. Save the path to your module's executable for later use.
+1. [Add the `colorfilter` module to your smart machine as a local module](#add-as-a-local-module) and continue the tutorial from there.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+### Code your own module
+
+To code your own color filtering module, first create the necessary files and directories on your smart machine:
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+
+1. Create a folder for your module with the name of your model `colorfilter`.
+ - Your model name must use all lowercase letters.
+1. Inside that folder, create a file called color_filter.py.
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+1. Create a folder for your module with the name of your model `colorfilter`.
+ - Your model name must use all lowercase letters.
+1. Inside that folder, create:
+ - A file called color_filter.go.
+ - A directory named `module`.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+#### Code a filter resource model
+
+Next, include all the methods that the corresponding Viam SDK requires in the API definition of its built-in {{< glossary_tooltip term_id="subtype" text="subtype" >}}.
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+You can write your own code or copy the code from the `colorfilter` module's [color_filter.py](https://github.com/viam-labs/modular-filter-examples/blob/main/pycolorfilter/color_filter.py) file.
+
+To write your own code, implement a client interface defined by the required methods outlined in the client.py file for the specific resource you are implementing.
+For example, the camera's client.py file is located at [/components/camera/client.py](https://github.com/viamrobotics/viam-python-sdk/blob/main/src/viam/components/camera/client.py).
+
+1. Open the color_filter.py file you just created and implement the required methods from client.py.
+ - Exclude the `get_images` method, which you will customize to add filtering functionality in the upcoming section.
+ - Include the other methods within the class corresponding to your resource type (in this case, the `CameraClient` class).
+
+For more information, refer to [Write your new resource model definition](/how-tos/create-module/#write-your-new-resource-model-definition).
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+To write your own code, implement a client interface defined by the required methods outlined in the client.go file for the specific resource you are implementing.
+For example, the camera's client.go file is located at [/components/camera/client.go](https://github.com/viamrobotics/rdk/blob/main/components/camera/client.go).
+
+1. Open the color_filter.go file you just created and implement the required methods in it.
+ Exclude the `Read` method, which you will replace with a method, `Next`, to add filtering functionality in the upcoming section.
+ - You can create your own code or copy the code from the [viam-labs `colorfilter` repository's color_filter.go](https://github.com/viam-labs/modular-filter-examples/blob/main/colorfilter/color_filter.go) file.
+
+For more information, refer to [Write your new resource model definition](/how-tos/create-module/#write-your-new-resource-model-definition).
+
+{{% /tab %}}
+{{< /tabs >}}
+
+The filter function in your custom filter module must contain two critical elements:
+
+1. A utility function that will check if the caller of the filter function is the [data management service](/services/data/).
+1. A safeguard that ensures if the data management service is not the caller, an error and the unfiltered data is returned.
+
+{{< alert title="Important" color="note" >}}
+You must include both the safeguard and utility functions in order to access data filtering functionality within your module.
+
+For programming languages other than Python and Go, the API of the component you're receiving data from will provide comparable utility functions and safeguards.
+These tools help you to check the caller of your filter function and ensure your smart machine responds accordingly.
+
+For detailed information, please refer to the documentation for your chosen SDK.
+{{< /alert >}}
+
+Follow the steps below to include the utility function and check whether the data management service is the caller of the function responsible for data capture.
+If a service other than the data management service calls the function, it will return the original, unfiltered data.
+
+To check the caller of the collector function using the utility function:
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+First, import `from_dm_from_extra`:
+
+```python {class="line-numbers linkable-line-numbers"}
+from viam.utils import from_dm_from_extra
+```
+
+Then, include it in the conditional statement in your filter function:
+
+```python {class="line-numbers linkable-line-numbers"}
+if from_dm_from_extra(extra):
+ detections = await self.vision_service.get_detections(img)
+```
+
+With this configuration:
+
+- Your camera checks if the data management service is the caller of the filter function by using `from_dm_from_extra`.
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+Write a conditional statement that checks `FromDMContextKey`:
+
+{{< alert title="Important" color="note" >}}
+Use `FromDMContextKey` to check the caller of the data capture function when working with a modular _camera_ using the Go SDK.
+For all other components, you should use `FromDMString` instead.
+See the [sensor filter example](https://github.com/viam-labs/modular-filter-examples/blob/main/sensorfilter/sensor_filter.go) for example code to support working with a sensor.
+{{< /alert >}}
+
+```go {class="line-numbers linkable-line-numbers"}
+if ctx.Value(data.FromDMContextKey{}) != true {
+ // If not data management collector, return underlying stream contents without filtering.
+ return fs.cameraStream.Next(ctx)
+}
+
+// Only return captured image if it contains a certain color set by the vision service.
+img, release, err := fs.cameraStream.Next(ctx)
+
+detections, err := fs.visionService.Detections(ctx, img, map[string]interface{}{})
+```
+
+With this configuration:
+
+- Your camera checks if the data management service is the caller of the filter function by using `FromDMContextKey`.
+- If `FromDMContextKey` is `true` and the data management service is the caller, the camera captures an image by declaring the `img` variable and filling it with the content from the camera stream.
+- Then, after capturing the image, the code requests the next detection.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+After implementing a check to identify the initiator of the filter function, you must include the safeguard that will return an error if the data management service is not the caller.
+
+To do this, include the following in your filter module's resource model:
+
+{{< tabs name="Example tabs">}}
+{{% tab name="Python"%}}
+
+Edit color_filter.py and import the safeguard error `NoCaptureToStoreError` from Viam:
+
+```python {class="line-numbers linkable-line-numbers"}
+from viam.errors import NoCaptureToStoreError
+```
+
+Then, edit the `if from_dm_from_extra(extra)` conditional statement from earlier to add a second conditional statement within it that returns the error when the data management service is not the caller:
+
+```python {class="line-numbers linkable-line-numbers"}
+if from_dm_from_extra(extra):
+ detections = await self.vision_service.get_detections(img)
+ if len(detections) == 0:
+ raise NoCaptureToStoreError()
+```
+
+This code:
+
+- Checks the length (`len`) of the `detections` variable.
+- Raises a `NoCaptureToStoreError()` if `len` is equal to `0` to signify that the data management service is not the caller.
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+Open color_filter.go and write a conditional statement inside of your filter function that includes the error message `data.ErrNoCaptureToStore`:
+
+```go {class="line-numbers linkable-line-numbers"}
+if len(detections) == 0 {
+ return nil, nil, data.ErrNoCaptureToStore
+}
+```
+
+This code:
+
+- Checks the length (`len`) of the `detections` variable.
+- Raises a `data.ErrNoCaptureToStore` error if `len` is equal to `0` to signify that the data management service is not the caller.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+Now that you've included the required utility function and safeguard, your complete color filter function should look like the following:
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+
+```python {class="line-numbers linkable-line-numbers"}
+async def get_image(
+ self,
+ mime_type: str = "",
+ *,
+ extra: Optional[Dict[str, Any]] = None,
+ timeout: Optional[float] = None,
+ **kwargs
+ ) -> Image.Image:
+ """Filters the output of the underlying camera"""
+ img = await self.actual_cam.get_image()
+ if from_dm_from_extra(extra):
+ detections = await self.vision_service.get_detections(img)
+ if len(detections) == 0:
+ raise NoCaptureToStoreError()
+
+ return img
+```
+
+If the data management service is the caller, the filter function requests detections from the vision service and returns the image if the specified color is detected.
+Otherwise, it raises a `NoCaptureToStoreError()` error.
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+This code includes the utility function and safeguard you implemented earlier, and also includes error handling for getting the next source image and obtaining detections.
+
+```go {class="line-numbers linkable-line-numbers"}
+// Next contains the filtering logic and returns select data from the underlying camera.
+func (fs filterStream) Next(ctx context.Context) (image.Image, func(), error) {
+ if ctx.Value(data.FromDMContextKey{}) != true {
+ // If not data management collector, return underlying stream contents without filtering.
+ return fs.cameraStream.Next(ctx)
+ }
+
+ // Only return captured image if it contains a certain color set by the vision service.
+ img, release, err := fs.cameraStream.Next(ctx)
+ if err != nil {
+ return nil, nil, errors.New("could not get next source image")
+ }
+ detections, err := fs.visionService.Detections(ctx, img, map[string]interface{}{})
+ if err != nil {
+ return nil, nil, errors.New("could not get detections")
+ }
+
+ if len(detections) == 0 {
+ return nil, nil, data.ErrNoCaptureToStore
+ }
+
+ return img, release, err
+}
+```
+
+If the data management service is the caller, the filter function requests detections from the vision service and returns the image if the specified color is detected.
+Otherwise, it raises a `data.ErrNoCaptureToStore` error.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+After you have implemented your resource subtype's required methods and written your filter function, your final code should look like this:
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+
+color_filter.py implements "colorfilter", a custom model of the [camera component API](/components/camera/#api).
+
+
+ Click to view sample code from color_filter.py
+
+```python {class="line-numbers linkable-line-numbers"}
+from typing import (
+ ClassVar, Mapping, Sequence, Optional, cast, Tuple, List, Any, Dict
+)
+from typing_extensions import Self
+from viam.module.types import Reconfigurable
+from viam.proto.app.robot import ComponentConfig
+from viam.proto.common import ResourceName, ResponseMetadata, Geometry
+from viam.components.camera import Camera
+from viam.resource.types import Model, ModelFamily
+from viam.resource.base import ResourceBase
+from viam.media.video import NamedImage
+from PIL import Image
+from viam.errors import NoCaptureToStoreError
+from viam.services.vision import Vision
+from viam.utils import from_dm_from_extra
+
+
+class ColorFilterCam(
+ Camera,
+ Reconfigurable
+ ):
+
+ """A ColorFilterCam wraps the underlying camera
+ `actual_cam` and only keeps the data captured on the
+ actual camera if `vision_service` detects a certain
+ color in the captured image.
+ """
+ MODEL: ClassVar[Model] = Model(
+ ModelFamily("example", "camera"),
+ "colorfilter")
+
+ def __init__(self, name: str):
+ super().__init__(name)
+
+ @classmethod
+ def new_cam(
+ cls,
+ config: ComponentConfig,
+ dependencies: Mapping[ResourceName, ResourceBase]
+ ) -> Self:
+ cam = cls(config.name)
+ cam.reconfigure(config, dependencies)
+ return cam
+
+ @classmethod
+ def validate_config(
+ cls,
+ config: ComponentConfig
+ ) -> Sequence[str]:
+ """Validates JSON configuration"""
+ actual_cam = config.attributes.fields["actual_cam"].string_value
+ if actual_cam == "":
+ raise Exception(
+ "actual_cam attribute is required for a ColorFilterCam component"
+ )
+ vision_service = config.attributes.fields[
+ "vision_service"
+ ].string_value
+ if vision_service == "":
+ raise Exception(
+ """
+ vision_service attribute
+ is required for a
+ ColorFilterCam component
+ """
+ )
+ return [actual_cam, vision_service]
+
+ def reconfigure(
+ self,
+ config: ComponentConfig,
+ dependencies: Mapping[ResourceName, ResourceBase]
+ ):
+ """Handles attribute reconfiguration"""
+ actual_cam_name = config.attributes.fields[
+ "actual_cam"
+ ].string_value
+ actual_cam = dependencies[
+ Camera.get_resource_name(actual_cam_name)
+ ]
+ self.actual_cam = cast(Camera, actual_cam)
+
+ vision_service_name = config.attributes.fields[
+ "vision_service"
+ ].string_value
+ vision_service = dependencies[
+ Vision.get_resource_name(
+ vision_service_name
+ )
+ ]
+ self.vision_service = cast(
+ Vision,
+ vision_service
+ )
+
+ async def get_properties(
+ self,
+ *,
+ timeout: Optional[float] = None,
+ **kwargs
+ ) -> Camera.Properties:
+ """Returns details about the camera"""
+ return await self.actual_cam.get_properties()
+
+ async def get_image(
+ self,
+ mime_type: str = "",
+ *,
+ extra: Optional[Dict[str, Any]] = None,
+ timeout: Optional[float] = None,
+ **kwargs
+ ) -> Image.Image:
+ """Filters the output of the underlying camera"""
+ img = await self.actual_cam.get_image()
+ if from_dm_from_extra(extra):
+ detections = await self.vision_service.get_detections(img)
+ if len(detections) == 0:
+ raise NoCaptureToStoreError()
+
+ return img
+
+ async def get_images(
+ self,
+ *,
+ timeout: Optional[float] = None,
+ **kwargs
+ ) -> Tuple[
+ List[NamedImage],
+ ResponseMetadata
+ ]:
+ raise NotImplementedError
+
+ async def get_point_cloud(
+ self,
+ *,
+ extra: Optional[Dict[str, Any]] = None,
+ timeout: Optional[float] = None,
+ **kwargs
+ ) -> Tuple[
+ bytes,
+ str
+ ]:
+ raise NotImplementedError
+
+ async def get_geometries(self) -> List[Geometry]:
+ raise NotImplementedError
+```
+
+In this code:
+
+- The Python SDK simplifies the verification process by exposing the utility function `from_dm_from_extra`, to see if the caller is the data management service for you.
+
+- If the boolean is `true`, the function will call the vision service to get detections and return the image if the color is detected.
+ Otherwise, it raises `NoCaptureToStoreError()`.
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+color_filter.go implements "colorfilter", a custom model of the [camera component API](/components/camera/#api).
+
+
+ Click to view sample code from color_filter.go
+
+```go {class="line-numbers linkable-line-numbers"}
+// Package colorfilter implements a modular camera that filters the output of an underlying camera and only keeps
+// captured data if the vision service detects a certain color in the captured image.
+package colorfilter
+
+import (
+"context"
+"fmt"
+"image"
+
+ "go.viam.com/rdk/logging"
+ "github.com/pkg/errors"
+ "github.com/viamrobotics/gostream"
+
+ "go.viam.com/rdk/components/camera"
+ "go.viam.com/rdk/data"
+ "go.viam.com/rdk/pointcloud"
+ "go.viam.com/rdk/resource"
+ "go.viam.com/rdk/rimage/transform"
+ "go.viam.com/rdk/services/vision"
+
+)
+
+var (
+ // Model is the full model definition.
+ Model = resource.NewModel("example", "camera", "colorfilter")
+ errUnimplemented = errors.New("unimplemented")
+)
+
+func init() {
+ resource.RegisterComponent(camera.API, Model, resource.Registration[camera.Camera, *Config]{
+ Constructor: newCamera,
+ })
+}
+
+func newCamera(ctx context.Context, deps resource.Dependencies, conf resource.Config, logger logging.Logger) (camera.Camera, error) {
+ c := &colorFilterCam{
+ Named: conf.ResourceName().AsNamed(),
+ logger: logger,
+ }
+ if err := c.Reconfigure(ctx, deps, conf); err != nil {
+ return nil, err
+ }
+ return c, nil
+}
+
+// Config contains the name to the underlying camera and the name of the vision service to be used.
+type Config struct {
+ ActualCam string `json:"actual_cam"`
+ VisionService string `json:"vision_service"`
+}
+
+// Validate validates the config and returns implicit dependencies.
+func (cfg \*Config) Validate(path string) ([]string, error) {
+ if cfg.ActualCam == "" {
+ return nil, fmt.Errorf(`expected "actual_cam" attribute in %q`, path)
+ }
+ if cfg.VisionService == "" {
+ return nil, fmt.Errorf(`expected "vision_service" attribute in %q`, path)
+ }
+
+ return []string{cfg.ActualCam, cfg.VisionService}, nil
+
+}
+
+// A colorFilterCam wraps the underlying camera `actualCam` and only keeps the data captured on the actual camera if `visionService`
+// detects a certain color in the captured image.
+type colorFilterCam struct {
+ resource.Named
+ actualCam camera.Camera
+ visionService vision.Service
+ logger loggingg.Logger
+}
+
+// Reconfigure reconfigures the modular component with new settings.
+func (c *colorFilterCam) Reconfigure(ctx context.Context, deps resource.Dependencies, conf resource.Config) error {
+ camConfig, err := resource.NativeConfig[*Config](conf)
+ if err != nil {
+ return err
+ }
+
+ c.actualCam, err = camera.FromDependencies(deps, camConfig.ActualCam)
+ if err != nil {
+ return errors.Wrapf(err, "unable to get camera %v for colorfilter", camConfig.ActualCam)
+ }
+
+ c.visionService, err = vision.FromDependencies(deps, camConfig.VisionService)
+ if err != nil {
+ return errors.Wrapf(err, "unable to get vision service %v for colorfilter", camConfig.VisionService)
+ }
+
+ return nil
+
+}
+
+// DoCommand simply echoes whatever was sent.
+func (c \*colorFilterCam) DoCommand(ctx context.Context, cmd map[string]interface{}) (map[string]interface{}, error) {
+ return cmd, nil
+}
+
+// Close closes the underlying camera.
+func (c \*colorFilterCam) Close(ctx context.Context) error {
+ return c.actualCam.Close(ctx)
+}
+
+// Images does nothing.
+func (c \*colorFilterCam) Images(ctx context.Context) ([]camera.NamedImage, resource.ResponseMetadata, error) {
+ return nil, resource.ResponseMetadata{}, errUnimplemented
+}
+
+// Stream returns a stream that filters the output of the underlying camera stream in the stream.Next method.
+func (c \*colorFilterCam) Stream(ctx context.Context, errHandlers ...gostream.ErrorHandler) (gostream.VideoStream, error) {
+camStream, err := c.actualCam.Stream(ctx, errHandlers...)
+ if err != nil {
+ return nil, err
+ }
+
+ return filterStream{camStream, c.visionService}, nil
+
+}
+
+// NextPointCloud does nothing.
+func (c \*colorFilterCam)NextPointCloud(ctx context.Context)(pointcloud.PointCloud, error)
+{
+ return nil, errUnimplemented
+}
+
+// Properties returns details about the camera.
+func (c \*colorFilterCam) Properties(ctx context.Context)(camera.Properties, error)
+{
+ return c.actualCam.Properties(ctx)
+}
+
+// Projector does nothing.
+func (c \*colorFilterCam) Projector(ctx context.Context) (transform.Projector, error) {
+ return nil, errUnimplemented
+}
+
+type filterStream struct {
+ cameraStream gostream.VideoStream
+ visionService vision.Service
+}
+
+// Next contains the filtering logic and returns select data from the underlying camera.
+func (fs filterStream) Next(ctx context.Context) (image.Image, func(), error) {
+ if ctx.Value(data.FromDMContextKey{}) != true {
+ // If not data management collector, return underlying stream contents without filtering.
+ return fs.cameraStream.Next(ctx)
+ }
+
+ // Only return captured image if it contains a certain color set by the vision service.
+ img, release, err := fs.cameraStream.Next(ctx)
+ if err != nil {
+ return nil, nil, errors.New("could not get next source image")
+ }
+ detections, err := fs.visionService.Detections(ctx, img, map[string]interface{}{})
+ if err != nil {
+ return nil, nil, errors.New("could not get detections")
+ }
+
+ if len(detections) == 0 {
+ return nil, nil, data.ErrNoCaptureToStore
+ }
+
+ return img, release, err
+}
+
+// Close closes the stream.
+func (fs filterStream) Close(ctx context.Context) error {
+ return fs.cameraStream.Close(ctx)
+}
+```
+
+In this code:
+
+- A modular camera coded in Go looks for a flag called `fromDM` in the context (`ctx`) using `ctx.Value(data.FromDMContextKey{})` to figure out if the data management service is the caller.
+
+- If the boolean is `true`, the function will call the vision service to get detections and return the image if the color is .
+ Otherwise, it will raise the [`ErrNoCaptureToStore`](https://github.com/viamrobotics/rdk/blob/214879e147970a454f78035e938ea853fcd79f17/data/collector.go#L44) error.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+For more information, see [Write your new resource model definition](/how-tos/create-module/#write-your-new-resource-model-definition).
+
+#### Code an entry point file
+
+Next, code your module entry point file which `viam-server` will use to initialize and start the filter module.
+
+To code an entry point file yourself, locate the subtype API as defined in the relevant `/.go` file in the [RDK source code](https://github.com/viamrobotics/rdk).
+
+- In this example, the camera's API is defined in the [camera.go](https://github.com/viamrobotics/rdk/blob/main/components/camera/camera.go) file in the RDK source code.
+ When developing your main.go or main.py file, reference this file.
+
+{{< tabs >}}
+{{% tab name="Python"%}}
+
+Follow these steps to code your entry point file:
+
+1. Inside of your filter module's directory, create a new file named main.py.
+ This will be the entry point file for the module.
+1. Add the code below which initializes and starts the filter module.
+
+```python {class="line-numbers linkable-line-numbers"}
+import asyncio
+from viam.components.camera import Camera
+from viam.module.module import Module
+from viam.resource.registry import Registry, ResourceCreatorRegistration
+import color_filter
+
+
+async def main():
+
+ """
+ This function creates and starts a new module,
+ after adding all desired resource models.
+ Resource creators must be
+ registered to the resource
+ registry before the module adds the resource model.
+ """
+ Registry.register_resource_creator(
+ Camera.SUBTYPE,
+ color_filter.ColorFilterCam.MODEL,
+ ResourceCreatorRegistration(
+ color_filter.ColorFilterCam.new_cam,
+ color_filter.ColorFilterCam.validate_config
+ )
+ )
+ module = Module.from_args()
+ module.add_model_from_registry(
+ Camera.SUBTYPE,
+ color_filter.ColorFilterCam.MODEL
+ )
+ await module.start()
+
+if __name__ == "__main__":
+ asyncio.run(main())
+```
+
+{{% /tab %}}
+{{% tab name="Go"%}}
+
+Follow these steps to code your entry point file:
+
+1. Open the folder named `module` inside of your filter module's directory and create a new file named main.go.
+ This will be the entry point file for the module.
+1. Add the code below which initializes and starts the filter module.
+
+```go {class="line-numbers linkable-line-numbers"}
+// Package main is a module which serves the colorfilter custom module.
+package main
+
+import (
+ "context"
+
+ "go.viam.com/rdk/logging"
+ "go.viam.com/rdk/utils"
+
+ "github.com/viam-labs/modular-filter-examples/colorfilter"
+ "go.viam.com/rdk/components/camera"
+ "go.viam.com/rdk/module"
+)
+
+func main() {
+ utils.ContextualMain(mainWithArgs, module.NewLoggerFromArgs("colorfilter_module"))
+}
+
+func mainWithArgs(ctx context.Context, args []string, logger logging.Logger) (err error) {
+ myMod, err := module.NewModuleFromArgs(ctx, logger)
+ if err != nil {
+ return err
+ }
+
+ err = myMod.AddModelFromRegistry(ctx, camera.API, colorfilter.Model)
+ if err != nil {
+ return err
+ }
+
+ err = myMod.Start(ctx)
+ defer myMod.Close(ctx)
+ if err != nil {
+ return err
+ }
+ <-ctx.Done()
+ return nil
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+For more information, see [Create a new module](/how-tos/create-module/).
+
+Once you've written your filter module, [compile your module into a single executable](/how-tos/create-module/#compile-or-package-your-module) that runs your module when executed.
+
+Note the absolute path to your module’s executable for use in the next section.
+
+### Add as a local module
+
+Whether you've downloaded the `colorfilter` module, or written your own color filtering module, the next step is to add the module to your smart machine as a local module:
+
+1. Navigate to the **CONFIGURE** tab of your machine's page in the [Viam app](https://app.viam.com/robots).
+1. Click the **+** (Create) button next to your main part in the left-hand menu and select **Local module**, then **Local module**.
+
+1. Enter a name or use the suggested name for your local module, enter the [module's executable path](/how-tos/create-module/#compile-or-package-your-module), then click **Create**.
+ - The name must use only lowercase characters.
+1. Then, click the **Save** button in the top right corner of the page to save your changes.
+
+![A color filter module that has been added.](/tutorials/pet-photographer/add-colorfilter-module.png)
+
+## Add services
+
+Next, add the following services to your smart machine to support the color filter module:
+
+- The [data management service](/services/data/) enables your smart machine to capture data and sync it to the cloud.
+- The [vision service](/services/vision/#detections) enables your smart machine to perform color detection on objects in a camera stream.
+
+### Add the data management service
+
+To enable data capture on your machine, add and configure the [data management service](/services/data/) to capture and store data on your machine's computer:
+
+{{< tabs >}}
+{{% tab name="Config Builder" %}}
+
+1. On the **CONFIGURE** tab, click the **+** icon next to your machine part in the left-hand menu and select **Service**.
+1. Choose `data management` as the type.
+1. Enter a name or use the suggested name for your instance of the data manager.
+ This tutorial uses the name 'dm' in all example code.
+1. Click **Create**.
+ On the panel that appears, you can manage the capturing and syncing functions individually.
+ By default, the data management service captures data every 0.1 minutes to the ~/.viam/capture directory.
+ Leave the default settings as they are.
+1. Click **Save** in the top right corner of the screen to save your changes.
+
+ ![An instance of the data management service named "dm". The cloud sync and capturing options are toggled on and the directory is empty. The interval is set to 0.1](/tutorials/pet-photographer/data-management-services.png)
+
+ For more detailed information, see [Add the data management service](/services/data/#configuration).
+ {{% /tab %}}
+ {{% tab name="JSON Template" %}}
+ Add the data management service to the services array in your rover’s raw JSON configuration:
+
+```json {class="line-numbers linkable-line-numbers"}
+{
+ "name": "dm",
+ "type": "data_manager",
+ "namespace": "rdk",
+ "attributes": {
+ "sync_interval_mins": 0.1,
+ "capture_dir": "",
+ "tags": [],
+ "additional_sync_paths": []
+ }
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+### Add the vision service
+
+To enable your smart machine to detect a specific color in its camera stream, add a [`color_detector` vision service](/services/vision/color_detector/).
+For this tutorial, we will configure the vision service to recognize a blue dog collar using `#43A1D0` or `rgb(67, 161, 208)`.
+If you have a different item you want to use, or want to match to a color that matches your pet closely, you can use a different color.
+
+{{< tabs >}}
+{{% tab name="Config Builder" %}}
+
+1. Navigate to the **CONFIGURE** tab of your machine's page in the [Viam app](https://app.viam.com).
+1. Click the **+** icon next to your machine part in the left-hand menu and select **Service**.
+1. Select the `vision` type, then select the `color detector` model.
+1. Enter a name or use the suggested name for your color detector.
+ This tutorial uses the name 'my_color_detector' in all example code.
+1. click **Create**.
+1. In the vision service's **Attributes** section, click the color selection box to set the color to be detected.
+ For this tutorial, set the color to `#43A1D0` or `rgb(67, 161, 208)`.
+ Alternatively, you can provide the color of your pet, or use a different brightly-colored collar or ribbon.
+1. Set **Hue Tolerance** to `0.06` and **Segment size px** to `100`.
+1. Click the **Save** button in the top right corner of the page.
+
+Your configuration should look like the following:
+
+![The vision service configuration panel showing the color set to blue, the hue tolerance set to 0.06, and the segment size set to 100.](/tutorials/pet-photographer/vision-service.png)
+
+For more detailed information, refer to [Configure a color detector](/services/vision/color_detector/).
+
+{{% /tab %}}
+{{% tab name="JSON Template" %}}
+
+Add the vision service object to the services array in your rover’s raw JSON configuration:
+
+```json {class="line-numbers linkable-line-numbers"}
+{
+ "name": "my_color_detector",
+ "type": "vision",
+ "model": "color_detector",
+ "attributes": {
+ "segment_size_px": 100,
+ "detect_color": "#43a1d0",
+ "hue_tolerance_pct": 0.06
+ }
+}
+```
+
+Click the **Save** button in the top right corner of the page when done.
+
+{{% /tab %}}
+{{< /tabs >}}
+
+## Enable filtering by color
+
+With the vision and data management services configured, you can now configure your camera to filter by color and sync photos to Viam's cloud.
+
+### Configure your camera
+
+If you haven't already, add a [camera](/components/camera/) component to your smart machine:
+
+1. On the **CONFIGURE** tab, click the **+** (Create) button next to your main part in the left-hand menu and select **Component**.
+ Start typing "webcam" and select **camera / webcam**.
+ Enter a name or use the suggested name for your camera.
+ This tutorial uses the name 'cam' in all example code.
+ Click **Create**.
+
+1. Click the **video path** dropdown and select the webcam you'd like to use for this project from the list of suggestions.
+
+1. Click **Save** in the top right corner of the screen to save your changes.
+
+![An instance of the webcam component named 'cam'](/tutorials/pet-photographer/webcam-component.png)
+
+### Add the color filter component
+
+1. Click the **+** icon next to your machine part in the left-hand menu and select **Local module**, then **Local component**.
+1. On the **Create** menu:
+
+ 1. Select the `camera` type from the dropdown menu.
+ 1. Enter `example:camera:colorfilter`, the {{< glossary_tooltip term_id="model-namespace-triplet" text="model namespace triplet">}} of your modular resource's {{< glossary_tooltip term_id="model" text="model" >}}.
+ 1. Provide a name for this instance of your modular resource.
+ This name must be different from the module name.
+
+ {{}}
+
+1. Click **Create** to create the modular resource.
+1. In the resulting module configuration pane, copy the following JSON configuration into the attributes field:
+
+ ```json {class="line-numbers linkable-line-numbers"}
+ {
+ "vision_service": "my_color_detector",
+ "actual_cam": "cam"
+ }
+ ```
+
+ ![A component panel for a color filter modular resource with the attributes filled out for vision service and actual_cam](/tutorials/pet-photographer/colorfiltercam-component-attributes.png)
+
+### Configure data capture
+
+To add data capture for the color filter camera:
+
+1. Click **Add method** in the **Data capture** section of your color filter camera component.
+
+2. Toggle the **Method** dropdown menu, select **ReadImage**, and set the **Frequency** of the capture to `0.1`, which will configure the data management service to capture images from your camera once every 10 seconds.
+
+3. Click the **MIME type** dropdown and select `image/jpeg`.
+
+4. Click **Save** in the top right corner of the screen.
+
+![A component panel for a color filter modular resource with the attributes filled out for vision service and actual_cam as well as the data capture configuration capture set to capture ReadImage at a frequency of 0.1 images per second.](/tutorials/pet-photographer/colorfiltercam-component.png)
+
+## Test your color filter camera
+
+To test that your color filter camera is capturing and filtering images properly, navigate to the **CONTROL** tab on your machine's page.
+
+On the **colorfiltercam** panel, toggle **View colorfiltercam** to view your camera's live feed.
+Test the filter by positioning your smart machine so that it captures an image of your pet wearing its collar.
+Then examine the **DATA** tab to confirm that only pictures containing your pet wearing their collar are stored.
+
+For example, the following is the result of several dozen pictures of the same dog, but only those pictures where he is wearing the blue collar were captured and synced to the cloud:
+
+![Filtered data tab contents from the colorfiltercam component showing only photos of a dog with a blue collar](/tutorials/pet-photographer/data-capture.png)
+
+## Next steps
+
+Your pet photographer is now set up.
+Place it in an area your pet frequently visits and don't forget to attach the colored object to your pet.
+
+Now you can follow similar steps and customize the code you've written to configure a sensor for detecting specific thresholds or filter out blurry images from your camera's captures.
+
+Try these other tutorials for more on working with the data management and vision services:
+
+{{< cards >}}
+{{% card link="/how-tos/detect-color/" %}}
+{{% card link="/tutorials/projects/pet-treat-dispenser/" %}}
+{{% card link="/tutorials/projects/guardian/" %}}
+{{% card link="/tutorials/projects/send-security-photo/" %}}
+{{% card link="/how-tos/train-deploy-ml/" %}}
+{{< /cards >}}
diff --git a/docs/dev/tools/tutorials/control/_index.md b/docs/dev/tools/tutorials/control/_index.md
new file mode 100644
index 0000000000..046a907554
--- /dev/null
+++ b/docs/dev/tools/tutorials/control/_index.md
@@ -0,0 +1,10 @@
+---
+title: "Control Tutorials"
+linkTitle: "Control"
+childTitleEndOverwrite: "Tutorial"
+weight: 30
+type: docs
+empty_node: true
+layout: "empty"
+canonical: "tutorials/"
+---
diff --git a/docs/dev/tools/tutorials/control/air-quality-fleet.md b/docs/dev/tools/tutorials/control/air-quality-fleet.md
new file mode 100644
index 0000000000..60fecdbce9
--- /dev/null
+++ b/docs/dev/tools/tutorials/control/air-quality-fleet.md
@@ -0,0 +1,823 @@
+---
+title: "Monitor Air Quality with a Fleet of Sensors"
+linkTitle: "Air Quality Fleet"
+type: "docs"
+description: "Configure a fleet of machines to capture air quality sensor data across different locations."
+images: ["/tutorials/air-quality-fleet/three-sensor-dash-wide.png"]
+imageAlt: "A web dashboard showing PM2.5 readings from two air quality sensors."
+tags: ["tutorial"]
+authors: ["Jessamy Taylor"]
+languages: ["typescript"]
+viamresources: ["sensor", "data_manager"]
+platformarea: ["data", "fleet"]
+emailform: true
+level: "Intermediate"
+date: "2024-05-07"
+# updated: "" # When the tutorial was last entirely checked
+cost: 200
+# Learning goals:
+# 1. The reader can distinguish the concepts of organizations and locations and can select the appropriate setup when creating their own projects for their business.
+# 2. The reader can identify when to use fragments and evaluate when it is worth using fragments.
+# The reader can create their own fragments for their projects and knows what to include and exclude from them.
+# 3. The reader recognizes how permissions enable the management of data for a business across multiple customers while providing each customer access to their own data.
+---
+
+In this tutorial you will use a fleet of devices to collect air quality data from different places and display the most recent readings from each device in a custom viewing dashboard.
+
+{{< alert title="Learning Goals" color="info" >}}
+
+By completing this project, you will learn to:
+
+- Configure a fleet of identical machines
+- Organize your fleet using {{< glossary_tooltip term_id="location" text="locations" >}}
+- Collect and sync data from multiple machines
+- Use the Viam TypeScript SDK to query sensor data and create a custom dashboard
+- Use API keys to provide access to different groups of machines
+
+{{< /alert >}}
+
+![Air quality dashboard in a web browser with PM2.5 readings from three different sensor machines displayed.](/tutorials/air-quality-fleet/three-sensor-dash-wide.png)
+
+## Requirements
+
+You can complete this tutorial using any number of air quality sensing machines.
+
+For each machine, you will need the following hardware:
+
+- [SDS011 Nova PM sensor](https://www.amazon.com/SDS011-Quality-Detection-Conditioning-Monitor/dp/B07FSDMRR5)
+ - If you choose to use a different air quality sensor, you may need to [create your own module](/how-tos/create-module/) implementing the [sensor API](/components/sensor/#api) for your specific hardware.
+- A single-board computer (SBC) [capable of running `viam-server`](https://docs.viam.com/installation/)
+- An appropriate power supply
+
+Make sure all of your sensors are wired to your SBC before starting this tutorial.
+
+## Decide how you will organize your fleet
+
+Before you start connecting your devices to the Viam app, you'll need to decide how you want to group your devices.
+
+In the Viam app, {{< glossary_tooltip term_id="machine" text="machines" >}} are grouped into _locations_, and locations are grouped into _organizations_:
+
+- Each location can represent either a physical location or some other conceptual grouping.
+- An organization is the highest level grouping, and often contains all the locations (and machines) of an entire company.
+
+These groupings allow you to manage permissions; you can grant a user access to an individual machine, to all the machines in a location, or to everything in an entire organization.
+You choose how to group your machines.
+
+{{}}
+
+
+
+For more information, see [Fleet Management](/how-tos/manage-fleet/#organize-your-machines).
+
+### Example
+
+Imagine you create an air quality monitoring company called Pollution Monitoring Made Simple.
+Anyone can sign up and order one of your sensing machines.
+When a new customer signs up, you assemble a new machine with a sensor, SBC, and power supply.
+
+Before shipping the sensor machine to your new client, you connect the machine to the Viam app and configure it.
+To manage all your company's air quality sensing machines together, you create one organization called Pollution Monitoring Made Simple.
+Inside that organization, you create a location for each customer.
+You have some individual customers, for example Antonia, who have a sensor machine in their home, or perhaps one inside and one outside.
+You have other customers who are businesses, for example RobotsRUs, who have two offices, one in New York and one in Oregon, with multiple sensor machines in each.
+RobotsRUs wants to separate their sensor data by physical location, so you create a location for RobotsRUs and then create sub-locations to group their New York sensor machines and their Oregon machines.
+
+When you grant Antonia access to her location, she will be able to view data from the air sensors at her home.
+When you grant RobotsRUs access to their location, they will be able to view data from all of their sub-locations, or they can choose to spin up a dashboard showing data from only one sub-location at a time.
+You, as the organization owner, will be able to manage any necessary configuration changes for all air sensing machines in all locations created within the Pollution Monitoring Made Simple organization.
+
+{{}}
+
+### Organize your fleet
+
+For this tutorial, we will walk through how to set up your fleet based on the example above.
+You can choose to manage your fleet of machines differently based on what makes sense for your use case; if you're only configuring one or two sensors for personal use, feel free to add all your machines to one location and skip to the [next section](#connect-your-machines-to-the-viam-app).
+
+1. Navigate to the [Viam app](https://app.viam.com) in a web browser.
+ Create an account and log in.
+1. Click the dropdown in the upper-right corner of the **FLEET** page and use the **+** button to create a new organization for your air quality machine company.
+ Name the organization and click **Create**.
+1. Click **FLEET** in the upper-left corner of the page and click **LOCATIONS**.
+ A new location called `First Location` is automatically generated for you.
+ Rename it so you can use it for Antonia's machines:
+
+ Use the **...** menu next to edit the location name to `Antonia's Home`, then click **Save**.
+
+1. Now, create a separate location for RobotsRUs:
+
+ On the left side of the **LOCATIONS** page, click the **Add location** button.
+ Type in `RobotsRUs` and click **Add**.
+
+1. Add sub-locations to the RobotsRUs location to group the machines at each of their offices:
+
+ Add a new location called `Oregon Office` using the same **Add location** button.
+ Then, find the **New parent location** dropdown on the Oregon Office page.
+ Select **RobotsRUs** and click **Change**.
+
+ Repeat to add the New York office: Add a new location called `New York Office`, then change its parent location to **RobotsRUs**.
+
+ {{}}
+
+ In the next section, you'll add machines to the locations.
+
+## Connect your machines to the Viam app
+
+With your organizational structure in place, let's add some machines:
+
+1. Connect your first single-board computer to power.
+ For this tutorial, we'll treat this as the machine for our first customer, Antonia.
+ If the computer does not already have a Viam-compatible operating system installed, follow the [Platform Requirements section of the Installation Guide](/installation/viam-server-setup/#platform-requirements) to install a compatible operating system.
+ You _do not_ need to follow the "Install `viam-server`" section; you will do that in the next step!
+
+1. Enable serial communication so that the SBC can communicate with the air quality sensor.
+ For example, if you are using a Raspberry Pi, SSH to it and [enable serial communication in `raspi-config`](/installation/prepare/rpi-setup/#enable-communication-protocols).
+
+1. Click **Antonia's Home** in the left navigation menu to navigate to that location's page.
+ In the **New machine** field near the top-right corner of the screen, type in a name for the machine, such as `Home Air Quality Sensor`, and click **Add machine**.
+
+1. You'll be taken to the machine details page and prompted to set up your machine part.
+ Click **View setup instructions**.
+ You can find these instructions later if you need them by clicking the part status indicator (which currently reads **Awaiting setup**).
+
+1. Follow the **Set up your machine part** instructions to install `viam-server` on the machine and connect it to the Viam app.
+ `viam-server` is the binary that runs on the single-board computer (SBC), providing functionality including sensor data collection and connection to the Viam app.
+
+ The setup page will indicate when the machine is successfully connected.
+
+1. If Antonia has more than one air sensing machine, add a new machine to her location and set it up in the same way.
+
+This is how you set up one machine.
+If you are following along for the RobotsRUs business from our example, create additional machines in each sub-location, that is, in the `Oregon Office` location and in the `New York Office` location.
+
+## Set up your hardware
+
+{{% alert title="Note" color="note" %}}
+If this were a real company and you were shipping air sensing machines to customers, you would have the customer plug in power to the machine wherever they are setting it up.
+Since you already installed `viam-server`, once a customer connects the machine to power and sets up wifi, the machine will automatically re-connect to the Viam app and pull any configuration updates.
+{{% /alert %}}
+
+For each sensing machine:
+
+1. Connect the PM sensor to a USB port on the machine's SBC.
+
+1. Position your sensing machines in strategic locations, and connect them to power.
+ Here are some ideas for where to place sensing machines:
+
+ - At home:
+ - In an outdoor location protected from weather, such as under the eaves of your home
+ - In the kitchen, where cooking can produce pollutants
+ - Anywhere you spend lots of time indoors and want to measure exposure to pollutants
+ - At work:
+ - At your desk to check your exposure throughout the day
+ - Near a door or window to see whether pollutants are leaking in
+
+## Configure your air quality sensors
+
+You need to [configure](/configure/) your hardware so that each of your machines can communicate with its attached air quality [sensor](/components/sensor/).
+
+No matter how many sensing machines you use, you can configure them efficiently by using a reusable configuration block called a _{{< glossary_tooltip term_id="fragment" text="fragment" >}}_.
+Fragments are a way to share and manage identical machine configurations across multiple machines.
+Instead of going through all the configuration steps for each machine, you'll start by configuring just one machine and create a fragment based on that machine's configuration.
+Then, you'll add the fragment to each of your machines.
+With all your machines configured using the same fragment, if you need to update the config in the future, you can just update the fragment and all machines will automatically get the update.
+
+{{< alert title="Note" color="note" >}}
+If this was a real company, adding the fragment to each individual machine would quickly become tiring.
+We're showing you how to do this manually as a learning device.
+Once you understand how to configure machines and use fragments, you can use [Provisioning](/fleet/provision/) to automatically set up your devices.
+{{< /alert >}}
+
+### Configure your first machine
+
+#### Configure the sensor
+
+1. Navigate to the **CONFIGURE** tab of the machine details page in the [Viam app](https://app.viam.com) for your first machine.
+2. Click the **+** (Create) button and click **Component** from the dropdown.
+ Click **sensor**, then search for `sds011` and click **sds001:v1** from the results.
+3. Click **Add module**.
+ This adds the {{< glossary_tooltip term_id="module" text="module" >}} that provides the sensor model that supports the specific hardware we are using for this tutorial.
+
+ ![The Add Module button that appears after you click the model name.](/tutorials/air-quality-fleet/add-sensor-module.png)
+
+4. Give the sensor a name like `PM_sensor` and click **Create**.
+5. In the newly created **PM_sensor** card, replace the contents of the attributes box (the empty curly braces `{}`) with the following:
+
+ ```json {class="line-numbers linkable-line-numbers"}
+ {
+ "usb_interface": ""
+ }
+ ```
+
+6. Now you need to figure out which port your sensor is connected to on your board.
+ SSH to your board and run the following command:
+
+ ```sh{class="command-line" data-prompt="$"}
+ ls /dev/serial/by-id
+ ```
+
+ This should output a list of one or more USB devices attached to your board, for example `usb-1a86_USB_Serial-if00-port0`.
+ If the air quality sensor is the only device plugged into your board, you can be confident that the only device listed is the correct one.
+ If you have multiple devices plugged into different USB ports, you may need to choose one path and test it, or unplug something, to figure out which path to use.
+
+ Now that you have found the identifier, put the full path to the device into your config, for example:
+
+ ```json {class="line-numbers linkable-line-numbers"}
+ {
+ "usb_interface": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0"
+ }
+ ```
+
+7. Save the config.
+ Your machine config should now resemble the following:
+
+ ![Configure tab showing PM sensor and the sensor module configured.](/tutorials/air-quality-fleet/configured-sensor.png)
+
+#### Configure data capture and sync
+
+You have configured the sensor so the board can communicate with it, but sensor data is not yet being saved anywhere.
+Viam's [data management service](/services/data/) lets you capture data locally from each sensor and then sync it to the cloud where you can access historical sensor data and see trends over time.
+Once you configure the rest of your sensing machines, you'll be able to remotely access data from all sensors in all locations, and when you're ready, you can give customers [access](/cloud/rbac/) to the data from the sensors in their locations.
+
+Configure data capture and sync as follows:
+
+1. Click the **+** (Create) button and click **Service** from the dropdown.
+2. Click **data management**.
+3. Give your data manager a name such as the auto-populated name `data_manager-1` and click **Create**.
+4. Toggle **Syncing** to the on position.
+ Set the sync interval to `0.05` minutes so that data syncs to the cloud every 3 seconds.
+ You can change the interval if you like, just don't make it too long or you will have to wait a long time before you see your data!
+5. Let's add a tag to all your data so that you can query data from all your air quality sensors more easily in later steps.
+ In the **Tags** field, type `air-quality` and click **+ Tag: air-quality** when it appears to create a new tag.
+ This tag will now automatically be applied to all data collected by this data manager.
+6. Now the data management service is available to any components on your machine, and you can set up data capture on the sensor:
+7. On your **PM_sensor** card, click **Add method**.
+8. From the **Type** dropdown, select **Readings**.
+9. Set the **Frequency** to `0.1` readings per second.
+ This will capture air quality data once every ten seconds.
+ It is useful to capture data frequently for testing purposes, but you can always change this frequency later since you probably don't need to capture data this frequently all day forever.
+10. Save the config.
+
+### Create a fragment
+
+{{% alert title="Note" color="note" %}}
+If you are only using one air quality sensing machine for this tutorial, you do not need to create or use fragments, since fragments are useful only when configuring multiple machines.
+You can skip to [Test your sensors](#test-your-sensors).
+{{% /alert %}}
+
+While you configured your machine with the builder UI, the Viam app generated a JSON configuration file with all your parameters.
+This is the file that tells `viam-server` what resources are available to it and how everything is connected.
+Click **JSON** in the upper-left corner of the **CONFIGURE** tab to view the generated JSON file.
+You can manually edit this file instead of using the builder UI if you are familiar with JSON.
+
+In any case, now that the JSON is generated, you are ready to create a {{< glossary_tooltip term_id="fragment" text="fragment" >}}:
+
+1. Select and copy the entire contents of the JSON config.
+2. Navigate to the **FLEET** page and go to the [**FRAGMENTS** tab](https://app.viam.com/fragments).
+3. Click **Create fragment** and change your fragment's name by clicking on it. We used the name `air-sensing-machine`.
+4. Replace the empty curly braces `{}` with the config you copied from your machine.
+5. Click **Save**.
+6. Now, you can actually delete the entire config from your machine!
+ In the next section, you will replace it with the fragment you just created so that it gets updated alongside all your other machines when you update the fragment in the future.
+
+ Navigate back to your machine's **CONFIGURE** tab, select **JSON** mode, and delete the entire contents of the config.
+ When you try to save, you'll get an invalid JSON error because it can't be empty.
+ Put in a set of curly braces `{}` and then save the config successfully.
+
+### Add the fragment to all your machines
+
+Add the fragment you just created to each of your machines including the first one:
+
+1. Click the **+** button, then click **Insert fragment** in the dropdown menu.
+2. Search for and click the name of your fragment, for example `air-sensing-machine`.
+
+ ![The insert fragment UI.](/tutorials/air-quality-fleet/add-fragment.png)
+
+3. Click **Insert fragment**.
+ The module, sensor, and data manager will appear in your config.
+4. Save the config.
+5. Repeat these steps on the machine details page for each of your air quality sensing machines.
+
+## Test your sensors
+
+Now that all your hardware is configured, it's a good idea to make sure readings are being gathered by the sensors and sent to the cloud before proceeding with the tutorial.
+For each machine:
+
+1. Go to the machine details page in the [Viam app](https://app.viam.com.) and navigate to the **CONTROL** tab.
+2. Within the **Sensors** section, click **Get Readings** for the **PM_sensor**.
+ If the sensor software and hardware is working, you should see values populate the **Readings** column.
+
+ ![The sensor readings on the control tab.](/tutorials/air-quality-fleet/get-readings.png)
+
+ If you do not see readings, check the **LOGS** tab for errors, double-check that serial communication is enabled on the single board computer, and check that the `usb_interface` path is correctly specified (click below).
+
+ {{< expand "Click here for usb_interface troubleshooting help" >}}
+
+If you only have one USB device plugged into each of your boards, the `usb_interface` value you configured in the sensor config is likely (conveniently) the same for all of your machines.
+If not, you can use [fragment overwrite](/fleet/fragments/#modify-the-config-of-a-machine-that-uses-a-fragment) to modify the value on any machine for which it is different:
+
+1. If you're not getting sensor readings from a given machine, check the path of the USB port using the same [process by which you found the first USB path](#usb-path).
+2. If the path to your sensor on one machine is different from the one you configured in the fragment, add a fragment overwrite to the config of that machine to change the path without needing to remove the entire fragment.
+ Follow the [instructions to add a fragment overwrite](/fleet/fragments/#modify-the-config-of-a-machine-that-uses-a-fragment) to your machine's config, using the following JSON template:
+
+ ```json {class="line-numbers linkable-line-numbers"}
+ "fragment_mods": [
+ {
+ "fragment_id": "",
+ "mods": [
+ {
+ "$set": {
+ "components.PM_sensor.attributes.usb_interface": ""
+ }
+ }
+ ]
+ }
+ ],
+ ```
+
+ Replace the values with your fragment ID and with the USB path you identify.
+ If you named your sensor something other than `PM_sensor`, change the sensor name in the template above.
+
+3. Repeat this process for each machine that needs a different `usb_interface` value.
+ If you have lots of machines with one `usb_interface` value, and lots of machines with a second one, you might consider duplicating the fragment, editing that value, and using that second fragment instead of the first one for the applicable machines, rather than using a fragment overwrite for each of the machines.
+ You have options.
+
+ {{< /expand >}}
+
+## Test data sync
+
+Next, check that data is being synced from your sensors to the cloud:
+
+1. Open your [**DATA** page](https://app.viam.com/data).
+2. Click the **Sensors** tab within the data page.
+3. If you have sensor data coming from machines unrelated to this project, use the filters on the left side of the page to view data from only your air quality sensors.
+ Click the **Tags** dropdown and select the `air-quality` tag you applied to your data.
+ You can also use these filters to show the data from one of your air quality sensors at a time by typing a machine name into the **Machine name** box and clicking **Apply** in the lower-left corner.
+
+ ![The sensor readings that have synced to the DATA page.](/tutorials/air-quality-fleet/synced-data.png)
+
+Once you've confirmed that data is being collected and synced correctly, you're ready to start building a dashboard to display the data.
+If you'd like to graph your data using a Grafana dashboard, try our [Visualize Data with Grafana tutorial](/tutorials/services/visualize-data-grafana/).
+If you'd like to create your own customizable dashboard using the Viam TypeScript, continue with this tutorial.
+
+## Code your custom TypeScript dashboard
+
+The [Viam TypeScript SDK](https://ts.viam.dev/) allows you to build custom web interfaces to interact with your machines.
+For this project, you'll use it to build a page that displays air quality sensor data for a given location.
+You'll host the website locally on your personal computer, and view the interface in a web browser on that computer.
+
+As you'll find out in the [authentication step](#authenticate-your-code-to-your-viam-app-location), you can set each customer up with credentials to access the data from only their location, or you can create a dashboard showing data from all sensors in your entire organization.
+
+![The air quality dashboard you'll build. This one has PM2.5 readings from two different sensor machines displayed, and a key with categories of air quality.](/tutorials/air-quality-fleet/two-sensors.png)
+
+### Set up your TypeScript project
+
+Complete the following steps on your laptop or desktop.
+You don't need to install or edit anything else on your machine's single-board computer (aside from `viam-server` which you already did); you'll be running the TypeScript code from your personal computer.
+
+1. Make sure you have the latest version of [Node.JS](https://nodejs.org/en) installed on your computer.
+1. Install the Viam TypeScript SDK by running the following command in your terminal:
+
+ ```sh {class="command-line" data-prompt="$"}
+ npm install --save @viamrobotics/sdk
+ ```
+
+1. Create a directory on your laptop or desktop for your project.
+ Name it aqi-dashboard.
+
+1. Create a file in your aqi-dashboard folder and name it package.json.
+ The package.json file holds necessary metadata about your project.
+ Paste the following contents into it:
+
+ ```json {class="line-numbers linkable-line-numbers"}
+ {
+ "name": "air-quality-dashboard",
+ "description": "A dashboard for visualizing data from air quality sensors.",
+ "scripts": {
+ "start": "esbuild ./main.ts --bundle --outfile=static/main.js --servedir=static --format=esm",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "esbuild": "*"
+ },
+ "dependencies": {
+ "@viamrobotics/sdk": "^0.13.0",
+ "bson": "^6.6.0"
+ }
+ }
+ ```
+
+{{% alert title="Fun fact" color="info" %}}
+The `--format=esm` flag in the `"start"` script is important because the ECMAScript module format is necessary to support the BSON dependency this project uses for data query formatting.
+If you don't know what the proceeding sentence means, don't worry about it; just copy-paste the JSON above and it'll work.
+{{% /alert %}}
+
+### Authenticate your code to your Viam app location
+
+Your TypeScript code requires an API key to establish a connection to your machines.
+You can set up credentials to access data from all the sensor machines in your organization, or from just one location.
+These API keys only need [**Operator** permissions](/cloud/rbac/).
+
+In our example you could create a dashboard for Antonia with an API key to see the data from her location, and create a separate dashboard for RobotsRUs with a different API key to access the data from their location.
+If RobotsRUs wanted to separate their dashboards by sub-locations, you could set up API keys for RobotsRUs to access data for each of their sub-locations separately, or you could modify the example code to filter data by location name.
+
+You can then either deploy each dashboard on a web server you manage, or add a web server on one machine per customer that hosts the dashboard for the respective customer so that they can access their data on their local network.
+We leave this step to the reader.
+
+The following instructions describe how to set up an API key for one location.
+
+1. Create another file inside the aqi-dashboard folder and name it main.ts.
+ Paste the following code into main.ts:
+
+ ```typescript {class="line-numbers linkable-line-numbers"}
+ // Air quality dashboard
+
+ import * as VIAM from "@viamrobotics/sdk";
+ import { BSON } from "bson";
+
+ async function main() {
+ const opts: VIAM.ViamClientOptions = {
+ credentials: {
+ // Replace "" (including brackets) with your machine's api key
+ type: "api-key",
+ payload: "",
+ // Replace "" (including brackets) with your machine's api key id
+ authEntity: "",
+ },
+ };
+
+ const orgID: string = ""; // Replace
+ const locationID: string = ""; // Replace
+
+ //
+
+ //
+ }
+
+ //
+
+ main().catch((error) => {
+ console.error("encountered an error:", error);
+ });
+ ```
+
+1. Now you need to get the API key and the {{< glossary_tooltip term_id="organization" text="organization" >}} and {{< glossary_tooltip term_id="location" text="location" >}} IDs to replace the placeholder strings in the code you just pasted.
+
+ In the [Viam app](https://app.viam.com), navigate to the location page for the location containing your air quality machines.
+
+ ![The location secret with a Copy button next to it.](/tutorials/air-quality-fleet/loc-secret-button.png)
+
+ Copy the **Location ID** and paste it into your code in place of ``, so that the line resembles `const orgID: string = "abcde12345"`.
+
+1. Use the dropdown menu in the upper-right corner of the page to navigate to your organization settings page.
+ Copy the **Organization ID** found under **Details** near the top of the page.
+ Paste it in place of `` in your code.
+
+1. Under the **API Keys** heading, click **Generate Key**.
+
+1. Name your key something such as `air-sensors-key`.
+
+1. Select **Resource** and choose the location you have all your air quality sensing machines in.
+
+1. Set the **Role** to **Owner**, then click **Generate key**.
+
+1. Copy the ID and corresponding key you just created and paste them in place of `` and `` in your code.
+ For example, you'll now have something of the form
+
+ ```json {class="line-numbers linkable-line-numbers"}
+ authEntity: '1234abcd-123a-987b-1234567890abc',
+ payload: 'abcdefg987654321abcdefghi'
+ ```
+
+ {{% snippet "secret-share.md" %}}
+
+### Add functionality to your code
+
+1. Now that you have the API key and org and location IDs, you are ready to add code that establishes a connection from the computer running the code to the Viam Cloud where the air quality sensor data is stored.
+ You'll create a Viam `dataClient` instance which accesses all the data in your location, and then query this data to get only the data tagged with the `air-quality` tag you applied with your data service configuration.
+ The following code also queries the data for a list of the machines that have collected air quality data so that later, you can make a dashboard that has a place for the latest data from each of them.
+
+ Paste the following code into the main function of your main.ts script, directly after the `locationID` line, in place of `// `:
+
+ ```typescript {class="line-numbers linkable-line-numbers"}
+ // Instantiate data_client and get all
+ // data tagged with "air-quality" from your location
+ const client = await VIAM.createViamClient(opts);
+ const myDataClient = client.dataClient;
+ const query = {
+ $match: {
+ tags: "air-quality",
+ location_id: locationID,
+ organization_id: orgID,
+ },
+ };
+ const match = { $group: { _id: "$robot_id" } };
+ // Get a list of all the IDs of machines that have collected air quality data
+ const BSONQueryForMachineIDList = [
+ BSON.serialize(query),
+ BSON.serialize(match),
+ ];
+ let machineIDs: any = await myDataClient?.tabularDataByMQL(
+ orgID,
+ BSONQueryForMachineIDList,
+ );
+ // Get all the air quality data
+ const BSONQueryForData = [BSON.serialize(query)];
+ let thedata: any = await myDataClient?.tabularDataByMQL(
+ orgID,
+ BSONQueryForData,
+ );
+ ```
+
+1. For this project, your dashboard will display the average of the last five readings from each air sensor.
+ You need a function to calculate that average.
+ The data returned by the query is not necessarily returned in order, so this function must put the data in order based on timestamps before averaging the last five readings.
+
+ Paste the following code into main.ts after the end of your main function, in place of `// `:
+
+ ```typescript {class="line-numbers linkable-line-numbers"}
+ // Get the average of the last few readings from a given sensor
+ async function getLastFewAv(alltheData: any[], machineID: string) {
+ // Get just the data from this machine
+ let thedata = new Array();
+ for (const entry of alltheData) {
+ if (entry.robot_id == machineID) {
+ thedata.push({
+ PM25: entry.data.readings["pm_2_5"],
+ time: entry.time_received,
+ });
+ }
+ }
+
+ // Sort the air quality data from this machine
+ // by timestamp
+ thedata = thedata.sort(function (a, b) {
+ let x = a.time.toString();
+ let y = b.time.toString();
+ if (x < y) {
+ return -1;
+ }
+ if (x > y) {
+ return 1;
+ }
+ return 0;
+ });
+
+ // Add up the last 5 readings collected.
+ // If there are fewer than 5 readings, add all of them.
+ let x = 5; // The number of readings to average over
+ if (x > thedata.length) {
+ x = thedata.length;
+ }
+ let total = 0;
+ for (let i = 1; i <= x; i++) {
+ const reading: number = thedata[thedata.length - i].PM25;
+ total += reading;
+ }
+ // Return the average of the last few readings
+ return total / x;
+ }
+ ```
+
+1. Now that you've defined the function to sort and average the data for each machine, you're done with all the `dataClient` code.
+ The final piece you need to add to this script is a way to create some HTML to display data from each machine in your dashboard.
+
+ Paste the following code into the main function of main.ts, in place of `// `:
+
+ ```typescript {class="line-numbers linkable-line-numbers"}
+ // Instantiate the HTML block that will be returned
+ // once everything is appended to it
+ let htmlblock: HTMLElement = document.createElement("div");
+
+ // Display the relevant data from each machine to the dashboard
+ for (const mach of machineIDs) {
+ let insideDiv: HTMLElement = document.createElement("div");
+ let avgPM: number = await getLastFewAv(thedata, mach._id);
+ // Color-code the dashboard based on air quality category
+ let level: string = "blue";
+ switch (true) {
+ case avgPM < 12.1: {
+ level = "good";
+ break;
+ }
+ case avgPM < 35.5: {
+ level = "moderate";
+ break;
+ }
+ case avgPM < 55.5: {
+ level = "unhealthy-sensitive";
+ break;
+ }
+ case avgPM < 150.5: {
+ level = "unhealthy";
+ break;
+ }
+ case avgPM < 250.5: {
+ level = "very-unhealthy";
+ break;
+ }
+ case avgPM >= 250.5: {
+ level = "hazardous";
+ break;
+ }
+ }
+ // Create the HTML output for this machine
+ insideDiv.className = "inner-div " + level;
+ insideDiv.innerHTML =
+ "
";
+ htmlblock.appendChild(insideDiv);
+ }
+
+ // Output a block of HTML with color-coded boxes for each machine
+ return document.getElementById("insert-readings").replaceWith(htmlblock);
+ ```
+
+The full code is available for reference on [GitHub](https://github.com/viam-labs/air-quality-fleet/blob/main/main.ts).
+
+### Style your dashboard
+
+You have completed the main TypeScript file that gathers and sorts the data.
+Now, you'll create a page to display the data.
+
+{{% alert title="Tip" color="tip" %}}
+The complete code is available on [GitHub](https://github.com/viam-labs/air-quality-fleet) as a reference.
+{{% /alert %}}
+
+1. Create a folder called static inside your aqi-dashboard folder.
+ Inside the static folder, create a file called index.html.
+ This file specifies the contents of the webpage that you will see when you run your code.
+ Paste the following into index.html:
+
+ ```{class="line-numbers linkable-line-numbers" data-line="11"}
+
+
+
+
+
+
+
+
+
Air Quality Dashboard
+
+
+
+
PM 2.5 readings
+
The following are averages of the last few readings from each machine:
+
+
+
Loading data...
+ It may take a few moments for the data to load.
+ Do not refresh page.
+
+
+
+
Key:
+
Good air quality
+
Moderate
+
Unhealthy for sensitive groups
+
Unhealthy
+
Very unhealthy
+
Hazardous
+
+
+ After the data has loaded, you can refresh the page for the latest readings.
+
+
+
+
+ ```
+
+{{% alert title="Fun fact" color="info" %}}
+Line 11, highlighted above, is where the HTML output of the TypeScript file main.ts will get pulled in.
+
+TypeScript is a superset of JavaScript with added functionality, and it transpiles to JavaScript, which is why your file is called main.ts even though line 11 indicates `src="main.js"`.
+If you look at line 5 of package.json, you can see that `./main.ts` builds out to `static/main.js`.
+{{% /alert %}}
+
+1. Now you'll create a style sheet to specify the fonts, colors, and spacing of your dashboard.
+ Create a new file inside your static folder and name it style.css.
+1. Paste the following into style.css:
+
+ ```{class="line-numbers linkable-line-numbers"}
+ body {
+ font-family: Helvetica;
+ margin-left: 20px;
+ }
+
+ div {
+ background-color: whitesmoke;
+ }
+
+ h1 {
+ color: black;
+ }
+
+ h2 {
+ font-family: Helvetica;
+ }
+
+ .inner-div {
+ font-family: monospace;
+ border: .2px solid;
+ background-color: lightblue;
+ padding: 20px;
+ margin-top: 10px;
+ max-width: 320px;
+ font-size: large;
+ }
+
+ .key {
+ max-width: 200px;
+ padding: 0px 5px 5px;
+ }
+
+ .key p {
+ padding: 4px;
+ margin: 0px;
+ }
+
+ .good {
+ background-color: lightgreen;
+ }
+
+ .moderate {
+ background-color: yellow;
+ }
+
+ .unhealthy-sensitive {
+ background-color: orange;
+ }
+
+ .unhealthy {
+ background-color: red;
+ }
+
+ .very-unhealthy {
+ background-color: violet;
+ }
+
+ .hazardous {
+ color: white;
+ background-color: purple;
+ }
+
+ #main {
+ max-width:600px;
+ padding:10px 30px 10px;
+ }
+ ```
+
+ Feel free to adjust any of the colors, margins, fonts, and other specifications in style.css based on your preferences.
+
+## Full tutorial code
+
+You can find all the code in the [GitHub repo for this tutorial](https://github.com/viam-labs/air-quality-fleet).
+
+## Run the code
+
+1. In a command prompt terminal, navigate to your aqi-dashboard directory.
+ Run the following command to start up your air quality dashboard:
+
+ ```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
+ npm start
+ ```
+
+ ![Terminal window with the command 'npm start' run inside the aqi-dashboard folder. The output says 'start' and then 'esbuild' followed by the esbuild string from the package.json file you configured. Then there's 'Local:' followed by a URL and 'Network:' followed by a different URL.](/tutorials/air-quality-fleet/terminal-url.png)
+
+1. The terminal should output a line such as `Local: http://127.0.0.1:8000/`.
+ Copy the URL the terminal displays and paste it into the address bar in your web browser.
+ The data may take up to approximately 5 seconds to load, then you should see air quality data from all of your sensors.
+ If the dashboard does not appear, right-click the page, select **Inspect**, and check for errors in the console.
+
+ ![Air quality dashboard in a web browser with PM2.5 readings from three different sensor machines displayed.](/tutorials/air-quality-fleet/three-sensor-dash.png)
+
+ Great work.
+ You've learned how to configure a fleet of machines, sync their data to one place, and pull that data into a custom dashboard using TypeScript.
+
+
+
+## Next steps
+
+Now that you can monitor your air quality, you can try to improve it and see if your efforts are effective.
+You might try putting an air filter in your home or office and comparing the air quality data before you start running the filter with air quality after you have run the filter for a while.
+Or, try sealing gaps around doors, and check whether your seal is working by looking at your dashboard.
+
+You could set up a text or email alert when your air quality passes a certain threshold.
+For instructions on setting up an email alert, see the [Monitor Helmet Usage tutorial](/tutorials/projects/helmet/) as an example.
+For an example of setting up text alerts, see the [Detect a Person and Send a Photo tutorial](/tutorials/projects/send-security-photo/).
+
+For another example of a custom TypeScript interface, check out the [Claw Game tutorial](/tutorials/projects/claw-game/).
+Instead of displaying data, the claw game interface has buttons to control a robotic arm.
+
+In this tutorial we covered configuring a fleet of machines using fragments, but to automate the setup process further, you can [use the Viam Agent to provision machines](/fleet/provision/).
+
+{{< cards >}}
+{{% card link="/fleet/provision/" %}}
+{{% card link="/tutorials/services/visualize-data-grafana/" %}}
+{{% card link="/tutorials/projects/helmet/" %}}
+{{< /cards >}}
diff --git a/docs/dev/tools/tutorials/control/flutter-app.md b/docs/dev/tools/tutorials/control/flutter-app.md
new file mode 100644
index 0000000000..9219e4f378
--- /dev/null
+++ b/docs/dev/tools/tutorials/control/flutter-app.md
@@ -0,0 +1,790 @@
+---
+title: "Build a Flutter App that Integrates with Viam"
+linkTitle: "Build a Flutter App"
+type: "docs"
+description: "Use Viam's Flutter SDK to build a custom mobile app to show your machines and their components."
+videos: ["/tutorials/flutter-app/demo.webm", "/tutorials/flutter-app/demo.mp4"]
+videoAlt: "An example Viam-integrated Flutter app."
+tags: ["sdk", "flutter"]
+authors: ["Clint Purser"]
+languages: ["flutter"]
+viamresources: []
+platformarea: ["core"]
+images: ["/tutorials/flutter-app/preview.gif"]
+level: "Intermediate"
+date: "2024-01-17"
+cost: "0"
+---
+
+
+
+
+
+ {{}}
+
+
+
+Flutter is Google's user interface toolkit for building applications for mobile, web, and desktop from a single codebase.
+If you're looking to monitor and control individual machines with the same functionality you have on the [**CONTROL** tab](/fleet/control/), you can use the general-purpose [Viam mobile app](/fleet/control/#control-interface-in-the-viam-mobile-app) rather than creating your own.
+If you need custom functionality or a custom interface, you can use Viam's [Flutter SDK](https://flutter.viam.dev/) to build a custom app to interact with your machines that run on Viam.
+
+This tutorial guides you through creating a mobile app that shows your machines and their components.
+As you work through this project you will learn the following:
+
+- Flutter development basics
+- How to trigger app behavior when a user presses a button
+- The basics of using Viam's Flutter SDK
+
+## Requirements
+
+You do not need any hardware for this tutorial other than a computer running macOS or a 64-bit Linux operating system.
+
+This tutorial assumes you already have a machine [configured](/configure/) on the [Viam app](https://app.viam.com).
+
+## Set up your Flutter development environment
+
+This tutorial uses [Visual Studio Code](https://code.visualstudio.com/download) (VS Code) as the development environment (IDE), and uses the VS Code [Flutter extension](https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter) to generate sample project code.
+You can use a different editor, but it will be much easier to follow along using VS Code.
+
+### Platform compatibility
+
+Flutter can compile and run on many different operating systems.
+For this tutorial, you will be developing for iOS.
+In other words, iOS is your development _target_.
+
+You can always run your app on another platform later by configuring the code specific to that target.
+
+### Install Flutter
+
+Install Flutter according to [the Flutter documentation](https://docs.flutter.dev/get-started/install).
+Those instructions include installation of various tools and extensions for different development targets.
+For this walkthrough, you only need to install the following:
+
+- Flutter SDK
+- Visual Studio Code with the [Flutter extension](https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter)
+- [Xcode](https://developer.apple.com/xcode/), which is required for developing for iOS
+ - When prompted, do install Cocoapods.
+ You need it to support the iOS simulator.
+
+{{% alert title="Flutter version" color="note" %}}
+We recommend using Flutter 3.19.6, as this sample app was tested with this version.
+`fvm` is a useful tool for targeting specific flutter versions.
+You can run `fvm use 3.19.6` in the terminal before building your sample app to target Flutter 3.19.6.
+{{% /alert %}}
+
+## Start creating code
+
+### Create your Flutter project
+
+1. Launch VS Code.
+ Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) by pressing `Ctrl+Shift+P` or `Shift+Cmd+P`, depending on your system.
+
+2. Start typing "flutter new."
+ Click the **Flutter: New Project** command when it populates.
+
+{{}}
+
+3. Click **Application**, then choose a folder in which to create your project.
+4. Give your project a name, for example, smart_machine_app.
+ Naming it smart_machine_app will make it slightly easier to follow along in later steps.
+
+{{}}
+
+When you hit **Enter**, Flutter auto-generates a project folder with a useful starter project.
+VS Code automatically opens it.
+
+If you don't change any of the code files, you'll have a counter app with a button that adds one to the total each time you press it.
+That's not going to be very helpful for interacting with your fleet of machines, so in the next steps, you'll edit three of these automatically-created files to start building out a Viam-integrated app.
+
+### Edit the YAML configuration files
+
+1. In the VS Code file explorer, find and open the pubspec.yaml file.
+ This file specifies your app's metadata including its current version and dependencies.
+
+2. Delete the contents of your pubspec.yaml file and replace them with the following configuration which, among others, specifies the `viam_sdk` as a dependency for your project:
+
+ ```yaml {class="line-numbers linkable-line-numbers"}
+ name: smart_machine_app
+ description: "A Flutter app that integrates with Viam."
+
+ publish_to: "none" # Remove this line if you wish to publish to pub.dev
+
+ version: 1.0.0+1
+
+ environment:
+ sdk: ">=3.2.3 <4.0.0"
+
+ dependencies:
+ flutter:
+ sdk: flutter
+ flutter_dotenv: ^5.1.0
+ image: ^4.0.17
+ cupertino_icons: ^1.0.2
+ viam_sdk: ^0.0.20
+
+ dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ flutter_lints: ^2.0.0
+
+ flutter:
+ uses-material-design: true
+ ```
+
+ {{% alert title="Note" color="note" %}}
+
+ If you named your app something other than `smart_machine_app`, change the `name` value in the first line of the pubspec.yaml file to the name you gave your app during setup.
+
+ {{% /alert %}}
+
+3. Next, open the analysis_options.yaml configuration file.
+ This file specifies how strictly Flutter should enforce best practices in your code when it checks for things like syntax errors.
+ For this tutorial, you will use a less strict analyzer configuration to start, but you can always tune this later.
+ If you later publish an actual production app, you will likely want to increase the strictness of the analyzer before sharing your app with others.
+
+4. Replace the contents of the analysis_options.yaml file with the following:
+
+ ```yaml {class="line-numbers linkable-line-numbers"}
+ include: package:flutter_lints/flutter.yaml
+
+ linter:
+ rules:
+ avoid_print: false
+ prefer_const_constructors_in_immutables: false
+ prefer_const_constructors: false
+ prefer_const_literals_to_create_immutables: false
+ prefer_final_fields: false
+ unnecessary_breaks: true
+ use_key_in_widget_constructors: false
+ ```
+
+### Configure iOS-specific code
+
+Now you'll update some configurations in the iOS-specific code to support the [Viam Flutter SDK](https://flutter.viam.dev/).
+
+1. Open ios/Podfile.
+ If Podfile does not exist in that directory, generate it by running `flutter pub get` in the root directory of your app.
+ If the `flutter pub get` command returns an error, you may need to [upgrade the Flutter SDK](https://docs.flutter.dev/release/upgrade).
+
+ At the top of the file you will see the following lines:
+
+ ```dart {class="line-numbers linkable-line-numbers"}
+ # Uncomment this line to define a global platform for your project
+ # platform :ios, '11.0'
+ ```
+
+ Uncomment the line and change it to use version 17.0:
+
+ ```dart {class="line-numbers linkable-line-numbers"}
+ # Uncomment this line to define a global platform for your project
+ platform :ios, '13.0'
+ ```
+
+2. Open ios/Runner/Info.plist.
+ It will look something like this:
+
+ {{}}
+
+3. Insert the following code into the first line after the ``.
+ These lines are [required to establish WebRTC and local device mDNS connections](https://github.com/viamrobotics/viam-flutter-sdk?tab=readme-ov-file#update-infoplist).
+
+ ```xml {class="line-numbers linkable-line-numbers"}
+ NSLocalNetworkUsageDescription
+ Smart Machine App requires access to your device's local network to connect to your devices.
+ NSBonjourServices
+
+ _rpc._tcp
+
+ ```
+
+ {{}}
+
+ The file should now look like the following:
+
+ {{}}
+
+### Edit the main file
+
+1. Open the lib/main.dart file.
+
+2. Replace the contents of this file with the following code, which creates the scaffold of your app's login screen:
+
+ ```dart {class="line-numbers linkable-line-numbers"}
+ import 'package:flutter/material.dart';
+ import 'package:flutter_dotenv/flutter_dotenv.dart';
+
+ void main() async {
+ // await dotenv.load(); // <-- This loads your API key; will un-comment later
+ runApp(MyApp());
+ }
+
+ class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Smart Machine App',
+ theme: ThemeData(
+ colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
+ ),
+ home: MyHomePage(),
+ );
+ }
+ }
+
+ class MyHomePage extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text('Smart Machine App'),
+ SizedBox(height: 16),
+ ElevatedButton(onPressed: null, child: Text('Login')),
+ ],
+ ),
+ ),
+ );
+ }
+ }
+
+
+ ```
+
+ If you chose a name other than `Smart Machine App` for your project, edit lines 15 and 32 with your own app title.
+
+### Launch the app
+
+You now have enough of your new app coded to be able to build and test a rendering of it.
+
+Follow the steps below to build and preview the current state of your app.
+
+1. Open lib/main.dart.
+ In the bottom right corner of VS Code, find the button that shows the current target device.
+ Click the button to change your target device.
+ Make sure that you have your target device selected before you continue.
+
+ {{}}
+
+2. With lib/main.dart still open, find the "Start Debugging" button in the upper right corner of the VS Code window.
+ Click the button to build and render your app.
+
+ {{}}
+
+ A window should open up, displaying a rendering of your smart machine app:
+
+ {{}}
+
+## Add app navigation
+
+### Add a new screen
+
+Great work so far!
+Your app is successfully running, with a single screen and an inactive button.
+Next, you will add a new screen that pulls in some information from your {{< glossary_tooltip term_id="organization" text="organization" >}} in the Viam app.
+This new screen will be accessed from the login button.
+
+In the VS Code file explorer on the left-hand side, right click lib/ and click **New File**, then name the new file home_screen.dart.
+
+Paste the following code into the home_screen.dart file you just created:
+
+```dart {class="line-numbers linkable-line-numbers"}
+import 'package:flutter/material.dart';
+import 'package:flutter_dotenv/flutter_dotenv.dart';
+import 'package:viam_sdk/protos/app/app.dart';
+import 'package:viam_sdk/viam_sdk.dart';
+
+class HomeScreen extends StatefulWidget {
+ const HomeScreen({super.key});
+
+ @override
+ State createState() => _HomeScreenState();
+}
+
+class _HomeScreenState extends State {
+ late Viam _viam;
+ late Organization _organization;
+ List _locations = [];
+ bool _loading = true;
+
+ @override
+ void initState() {
+ _getData();
+ super.initState();
+ }
+
+ void _getData() async {
+ try {
+ _viam = await Viam.withApiKey(dotenv.env['API_KEY_ID']?? '', dotenv.env['API_KEY']?? '');
+ _organization = (await _viam.appClient.listOrganizations()).first;
+ _locations = await _viam.appClient.listLocations(_organization.id);
+
+ // in Flutter, setState tells the UI to rebuild the widgets whose state has changed,
+ // this is how you change from showing a loading screen to a list of values
+ setState(() {
+ _loading = false;
+ });
+ } catch (e) {
+ print(e);
+ }
+ }
+
+ /// This method will navigate to a specific [Location].
+ void _navigateToLocation(Location location) {
+ // Navigator.of(context)
+ // .push(MaterialPageRoute(builder: (_) => LocationScreen(_viam, location)));
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Locations')),
+ // If the list is loading, show a loading indicator.
+ // Otherwise, show a list of [Locations]s.
+ body: _loading
+ ? Center(
+ child: const CircularProgressIndicator.adaptive(),
+ )
+ : // Build a list from the [_locations] state.
+ ListView.builder(
+ itemCount: _locations.length,
+ itemBuilder: (_, index) {
+ final location = _locations[index];
+ return ListTile(
+ title: Text(location.name),
+ onTap: () => _navigateToLocation(location),
+ trailing: const Icon(Icons.chevron_right),
+ );
+ },
+ ),
+ );
+ }
+}
+```
+
+### Get the Viam API key
+
+Notice in the file the following line:
+
+```dart {class="line-numbers linkable-line-numbers" data-start="28"}
+_viam = await Viam.withApiKey(dotenv.env['API_KEY_ID']?? '', dotenv.env['API_KEY']?? '');
+```
+
+This line in the code defines how your Flutter app authenticates to the Viam platform, by referencing two environment variables that together comprise your Viam API key.
+
+Follow the steps below to get your API key and create an environment variables file to store them in:
+
+1. In your project folder, create a file to store your API keys.
+ Name it .env.
+ Copy and paste these two lines into the file:
+
+ ```sh {class="line-numbers linkable-line-numbers"}
+ API_KEY_ID="PASTE YOUR API KEY ID HERE"
+ API_KEY="PASTE YOUR API KEY HERE"
+ ```
+
+2. Go to the [Viam app](https://app.viam.com) and log in.
+
+3. Click the organization dropdown menu on the right side of the top banner.
+ If you're not already in the organization you want to connect to, click the correct organization name to navigate to it.
+
+ {{}}
+
+4. Click the organization dropdown menu again and click **Settings**.
+
+5. Scroll to the **API Keys** section.
+ You can find and use an existing API key for your smart machine, or you can create a new one for this application.
+ To create a new one:
+
+ 1. Click **Generate key**.
+ 2. Give the key a name like "flutter-app-my-org-name."
+ 3. Click the **Resource** dropdown and select your organization.
+ 4. Set **Role** to **Owner**.
+ 5. Click **Generate key**.
+ 6. Find your new key at the bottom of the list.
+
+6. Use the copy buttons next to the API key ID and API key to copy each of them and paste them into your .env file.
+
+{{< readfile "/static/include/snippet/secret-share.md" >}}
+
+7. In your lib/main.dart, find line 5:
+
+ ```dart
+ void main() async {
+ // await dotenv.load(); // <-- This loads your API key; will un-comment later
+ runApp(MyApp());
+ }
+ ```
+
+ Now that you have a .env file to load, un-comment that line so it loads the file.
+ Your `main()` function should look like this:
+
+ ```dart
+ void main() async {
+ await dotenv.load(); // <-- This loads your API key
+ runApp(MyApp());
+ }
+ ```
+
+8. Reopen your pubspec.yaml file and paste the following two lines at the end of it, inside the `flutter:` section.
+ Listing the .env among your app's assets lets the app access the file.
+
+ ```yaml
+ assets:
+ - .env
+ ```
+
+ The last few lines of your pubspec.yaml file should now look like this:
+
+ ```yaml
+ flutter:
+ uses-material-design: true
+ assets:
+ - .env
+ ```
+
+### Connect the login button to the home screen
+
+In VS Code, reopen main.dart.
+
+Add the following line to the imports at the top of the file:
+
+```dart {class="line-numbers linkable-line-numbers"}
+import 'home_screen.dart';
+```
+
+Change `ElevatedButton` in the `Column` to the following:
+
+```dart {class="line-numbers linkable-line-numbers" data-start="35"}
+ ElevatedButton(
+ onPressed: () => Navigator.of(context)
+ .push(MaterialPageRoute(builder: (_) => HomeScreen())),
+ child: Text('Login'),
+ ),
+```
+
+Run the mobile application simulator again to see how your changes have taken effect.
+Now, when you tap the login button, the app uses the API key to get the list of locations in your organization.
+It displays the names of the locations on a new screen:
+
+{{}}
+
+## Add more screens
+
+### Add a location screen
+
+At this point, you have an app that displays a list of {{< glossary_tooltip term_id="location" text="locations" >}}, but nothing happens when you tap a location name.
+In this step you will add functionality so that tapping a location name brings you to the list of {{< glossary_tooltip term_id="machine" text="smart machines" >}} in that location.
+
+In VS Code create a new file in the same folder as main.dart and home_screen.dart.
+Name it location_screen.dart.
+
+Paste the following code into the file:
+
+```dart {class="line-numbers linkable-line-numbers"}
+import 'package:flutter/material.dart';
+import 'package:viam_sdk/protos/app/app.dart';
+import 'package:viam_sdk/viam_sdk.dart';
+
+import 'robot_screen.dart';
+
+class LocationScreen extends StatefulWidget {
+ /// The authenticated Viam instance.
+ /// See previous screens for more details.
+ final Viam _viam;
+
+ /// The [Location] to show details for
+ final Location location;
+
+ const LocationScreen(this._viam, this.location, {super.key});
+
+ @override
+ State createState() => _LocationScreenState();
+}
+
+class _LocationScreenState extends State {
+ /// Similar to previous screens, start with [_isLoading] to true.
+ bool _isLoading = true;
+
+ /// A list of [Robot]s available in this [Location].
+ List robots = [];
+
+ @override
+ void initState() {
+ super.initState();
+ // Call our own _initState method to initialize our state.
+ _initState();
+ }
+
+ /// This method will get called when the widget initializes its state.
+ /// It exists outside the overridden [initState] function since it's async.
+ Future _initState() async {
+ // Using the authenticated [Viam] client received as a parameter,
+ // you can obtain a list of smart machines (robots) within this location.
+ final robots = await widget._viam.appClient.listRobots(widget.location.id);
+ setState(() {
+ // Once you have the list of robots, you can set the state.
+ this.robots = robots;
+ _isLoading = false;
+ });
+ }
+
+ void _navigateToRobot(Robot robot) {
+ Navigator.of(context).push(
+ MaterialPageRoute(builder: (_) => RobotScreen(widget._viam, robot)));
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text(widget.location.name),
+ ),
+ // If the list is loading, show a loading indicator.
+ // Otherwise, show a list of [Robot]s.
+ body: _isLoading
+ ? const CircularProgressIndicator.adaptive()
+ : // Build a list from the [locations] state.
+ ListView.builder(
+ itemCount: robots.length,
+ itemBuilder: (_, index) {
+ final robot = robots[index];
+ return ListTile(
+ title: Text(robot.name),
+ onTap: () => _navigateToRobot(robot),
+ trailing: const Icon(Icons.chevron_right),
+ );
+ }),
+ );
+ }
+}
+
+```
+
+### Add a robot screen
+
+Create a new file named robot_screen.dart and paste the following into the file:
+
+```dart {class="line-numbers linkable-line-numbers"}
+/// This is the screen that shows the resources available on a robot (or smart machine).
+/// It takes in a Viam app client instance, as well as a robot client.
+/// It then uses the Viam client instance to create a connection to that robot client.
+/// Once the connection is established, you can view the resources available
+/// and send commands to them.
+
+import 'package:flutter/material.dart';
+import 'package:viam_sdk/protos/app/app.dart';
+import 'package:viam_sdk/viam_sdk.dart';
+
+class RobotScreen extends StatefulWidget {
+ final Viam _viam;
+ final Robot robot;
+
+ const RobotScreen(this._viam, this.robot, {super.key});
+
+ @override
+ State createState() => _RobotScreenState();
+}
+
+class _RobotScreenState extends State {
+ /// Similar to previous screens, start with [_isLoading] to true.
+ bool _isLoading = true;
+
+ /// This is the [RobotClient], which allows you to access
+ /// all the resources of a Viam Smart Machine.
+ /// This differs from the [Robot] provided to us in the widget constructor
+ /// in that the [RobotClient] contains a direct connection to the Smart Machine
+ /// and its resources. The [Robot] object simply contains information about
+ /// the Smart Machine, but is not actually connected to the machine itself.
+ ///
+ /// This is initialized late because it requires an asynchronous
+ /// network call to establish the connection.
+ late RobotClient client;
+
+ @override
+ void initState() {
+ super.initState();
+ // Call our own _initState method to initialize our state.
+ _initState();
+ }
+
+ @override
+ void dispose() {
+ // You should always close the [RobotClient] to free up resources.
+ // Calling [RobotClient.close] will clean up any tasks and
+ // resources created by Viam
+ if (_isLoading == false) {
+ client.close();
+ }
+ super.dispose();
+ }
+
+ /// This method will get called when the widget initializes its state.
+ /// It exists outside the overridden [initState] function since it's async.
+ Future _initState() async {
+ // Using the authenticated [Viam] the received as a parameter,
+ // the app can obtain a connection to the Robot.
+ // There is a helpful convenience method on the [Viam] instance for this.
+ final robotClient = await widget._viam.getRobotClient(widget.robot);
+ setState(() {
+ client = robotClient;
+ _isLoading = false;
+ });
+ }
+
+ /// A computed variable that returns the available [ResourceName]s of
+ /// this robot in an alphabetically sorted list.
+ List get _sortedResourceNames {
+ return client.resourceNames..sort((a, b) => a.name.compareTo(b.name));
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: Text(widget.robot.name)),
+ body: _isLoading
+ ? const Center(child: CircularProgressIndicator.adaptive())
+ : ListView.builder(
+ itemCount: client.resourceNames.length,
+ itemBuilder: (_, index) {
+ final resourceName = _sortedResourceNames[index];
+ return ListTile(
+ title: Text(resourceName.name),
+ subtitle: Text(
+ '${resourceName.namespace}:${resourceName.type}:${resourceName.subtype}'),
+ );
+ }));
+ }
+}
+
+```
+
+### Connect the screens together
+
+Now that you have the code for the screens in place, you can enable navigation between them.
+
+Connect the home screen to the locations screen by un-commenting the following two lines in home_screen.dart:
+
+```dart {class="line-numbers linkable-line-numbers" data-line="3-4" data-start="42"}
+ /// This method will navigate to a specific [Location]. <-- Leave this commented!
+ void _navigateToLocation(Location location) {
+ Navigator.of(context) // <-- Un-comment this
+ .push(MaterialPageRoute(builder: (_) => LocationScreen(_viam, location))); // <-- And un-comment this
+ }
+```
+
+Add the following import to the top of the file:
+
+```dart {class="line-numbers linkable-line-numbers"}
+import 'location_screen.dart';
+```
+
+The whole home_screen.dart should now look like this:
+
+```dart {class="line-numbers linkable-line-numbers"}
+import 'package:flutter/material.dart';
+import 'package:flutter_dotenv/flutter_dotenv.dart';
+import 'package:viam_sdk/protos/app/app.dart';
+import 'package:viam_sdk/viam_sdk.dart';
+
+import 'location_screen.dart'; // <---- Added import
+
+class HomeScreen extends StatefulWidget {
+ const HomeScreen({super.key});
+
+ @override
+ State createState() => _HomeScreenState();
+}
+
+class _HomeScreenState extends State {
+
+ late Viam _viam;
+ late Organization _organization;
+ List _locations = [];
+ bool _loading = true;
+
+ @override
+ void initState() {
+ _getData();
+ super.initState();
+ }
+
+ void _getData() async {
+ try {
+ _viam = await Viam.withApiKey(dotenv.env['API_KEY_ID']?? '', dotenv.env['API_KEY']?? '');
+ _organization = (await _viam.appClient.listOrganizations()).first;
+ _locations = await _viam.appClient.listLocations(_organization.id);
+
+ // In Flutter, setState tells the UI to rebuild the widgets whose state has changed,
+ // this is how you change from showing a loading screen to a list of values
+ setState(() {
+ _loading = false;
+ });
+ } catch (e) {
+ print(e);
+ }
+ }
+
+ /// This method will navigate to a specific [Location].
+ void _navigateToLocation(Location location) {
+ Navigator.of(context).push( // <-- uncommented
+ MaterialPageRoute(builder: (_) => LocationScreen(_viam, location)));
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(title: const Text('Locations')),
+ // If the list is loading, show a loading indicator.
+ // Otherwise, show a list of [Locations]s.
+ body: _loading
+ ? Center(
+ child: const CircularProgressIndicator.adaptive(),
+ )
+ : // Build a list from the [_locations] state.
+ ListView.builder(
+ itemCount: _locations.length,
+ itemBuilder: (_, index) {
+ final location = _locations[index];
+ return ListTile(
+ title: Text(location.name),
+ onTap: () => _navigateToLocation(location),
+ trailing: const Icon(Icons.chevron_right),
+ );
+ }));
+ }
+}
+```
+
+Try running your app.
+Now, when you tap a location, you'll see a list of the smart machines in that location.
+When you tap one of them (if it is currently live), you'll see a list of that machine's {{< glossary_tooltip term_id="resource" text="resources" >}}:
+
+{{}}
+
+## Next steps
+
+Nice work!
+You have successfully made a Flutter app integrated with Viam!
+
+At this point you could customize the robot screen to have more functionality to control the machine or to show data from the robot in neat ways.
+The Viam Flutter SDK GitHub repo contains [more example apps](https://github.com/viamrobotics/viam-flutter-sdk/tree/main/example) for your reference.
+
+You can also stylize the look and feel of your app to match your brand.
+Look around [the Flutter documentation](https://docs.flutter.dev/) to learn how.
+
+If you're planning to release your app for general use, you will need to add an authentication flow to your app instead of adding API keys as environment variables.
+If you need assistance with this, reach out to us on our [Discord](https://discord.gg/viam) and we’ll be happy to help.
+
+When you’re ready to publish your app to the app stores you can follow these articles from Flutter on the subject:
+
+- [iOS](https://docs.flutter.dev/deployment/ios)
+- [Android](https://docs.flutter.dev/deployment/android)
diff --git a/docs/dev/tools/tutorials/control/gamepad.md b/docs/dev/tools/tutorials/control/gamepad.md
new file mode 100644
index 0000000000..f868734d91
--- /dev/null
+++ b/docs/dev/tools/tutorials/control/gamepad.md
@@ -0,0 +1,236 @@
+---
+title: "Drive a Rover (like SCUTTLE or Yahboom) Using a Gamepad"
+linkTitle: "Drive a Rover with a Gamepad"
+type: "docs"
+description: "Drive a wheeled rover with a Bluetooth gamepad that has a dongle."
+videos:
+ [
+ "/tutorials/videos/scuttle-gamepad-preview.webm",
+ "/tutorials/videos/scuttle-gamepad-preview.mp4",
+ ]
+videoAlt: "Drive a Scuttle Robot with a Bluetooth gamepad."
+images: ["/tutorials/videos/scuttle-gamepad-preview.gif"]
+aliases:
+ - "/tutorials/scuttle-gamepad/"
+ - "/tutorials/scuttlebot/scuttle-gamepad/"
+ - "/tutorials/control/scuttle-gamepad/"
+tags: ["base", "scuttle", "gamepad"]
+authors: []
+languages: []
+viamresources: ["base", "input_controller", "base_remote_control"]
+platformarea: ["core"]
+level: "Intermediate"
+date: "2022-08-10"
+updated: "2024-04-17"
+cost: 575
+---
+
+By the end of this tutorial, you'll be able to drive your rover around like an RC car.
+
+{{< alert title="Learning Goals" color="info" >}}
+
+After following this tutorial, you will be able to use the input controller component to control your machine using a gamepad.
+
+{{< /alert >}}
+
+## Requirements
+
+You will need the following hardware to complete this tutorial:
+
+- A wheeled rover, configured with a [base component](/components/base/) on the [Viam app](https://app.viam.com/).
+ This tutorial uses a [SCUTTLE rover](https://www.scuttlerobot.org/shop/) as an example but you can complete this tutorial using a [Yahboom 4WD Smart Robot](https://category.yahboom.net/collections/robotics/products/4wdrobot) or an entirely different rover.
+ - For a tutorial on configuring your rover, see [Configure a Rover](/tutorials/configure/configure-rover/).
+- [EasySMX ESM-9101 Wireless Controller](https://www.amazon.com/Wireless-Controller-EasySMX-ESM-9101-Gamepad/dp/B07F1NLGW2?th=1) or a similar gamepad and dongle.
+ This is the controller that comes with the SCUTTLE rover.
+ You can also use an 8BitDo controller with additional setup.
+
+{{