Create a new module
Viam provides built-in support for a variety of different components and services, as well as a registry full of modules created by other users. If no existing modules support your specific use case, you can write your own custom modular resources by creating a module, and either upload it to the Viam Registry to share it publicly, or deploy it to your machine as a local module without uploading it to the registry.
Follow the instructions below to learn how to write a new module using your preferred language and its corresponding Viam SDK, and then deploy it to your machines.
In this page
Note: viam-micro-server modules
viam-micro-server
works differently from the RDK (and viam-server
), so creating modular resources for it is different from the process described on this page.
Refer to the Micro-RDK Module Template on GitHub for information on how to create custom resources for your viam-micro-server
machine.
You will need to recompile and flash your ESP32 yourself instead of using Viam’s prebuilt binary and installer.
Tip
For a simplified step-by-step guide, see Create a Hello World module.
You can also watch this guide to creating a vision service module:
Write a module
Generally, to write a module, you will complete the following steps:
- Choose a Viam API to implement in your model.
- Write your new model definition code to map all the capabilities of your model to the API.
- Write an entry point (main program) file that registers your model with the Viam SDK and starts it up.
- Compile or package the model definition file or files, main program file, and any supporting files into a single executable file (a module) that can be run by
viam-server
.
While you can certainly combine the resource model definition and the main program code into a single file if desired (for example, a single main.py
program that includes both the model definition and the main()
program that uses it), this guide will use separate files for each.
Choose an API to implement in your model
Look through the component APIs and service API and find the API that best fits your use case. Each API contains various methods which you will need to define in your module:
- One or more methods specific to that API, such as the servo component’s
Move
andGetPosition
methods. - Inherited
ResourceBase
methods such asDoCommand
andClose
, common to all Viam resource APIs. - (For some APIs) Other inherited methods, for example all actuator APIs such as the motor API and servo API inherit
IsMoving
andStop
.
Note
If you want to write a module to add support to a new type of component or service that is relatively unique, consider using the generic API for your resource type to build your own API:
- If you are working with a component that doesn’t fit into any of the existing component APIs, you can use the generic component to build your own component API.
- If you are designing a service that doesn’t fit into any of the existing service APIs, you can use the generic service to build your own service API.
- It is also possible to define an entirely new API, but this is even more advanced than using
generic
.
Most module use cases, however, benefit from implementing an existing API instead of generic
.
Valid API identifiers
Each existing component or service API has a unique identifier in the form of a colon-delimited triplet. You will use this API namespace triplet when creating your new model, to indicate which API it uses.
The API namespace triplet is the same for all built-in and modular models that implement a given API.
For example, every model of motor built into Viam, as well as every custom model of motor provided by a module, all use the same API namespace triplet rdk:component:motor
to indicate that they implement the motor API.
The three pieces of the API namespace triplet are as follows:
namespace
:rdk
type
:component
subtype
: any one of these component proto files, for examplemotor
if you are creating a new model of motor
namespace
:rdk
type
:service
subtype
: any one of these service proto files, for examplevision
if you are creating a new model of vision service
Name your new resource model
In addition to determining which existing API namespace triplet to use when creating your module, you need to decide on a separate triplet unique to your model.
A resource model is identified by a unique name, called the model namespace triplet, using the format: namespace:repo-name:model-name
, where:
namespace
is the namespace of your organization.- For example, if your organization uses the
acme
namespace, your models must all begin withacme
, likeacme:repo-name:mybase
. If you do not intend to upload your module to the Viam Registry, you do not need to use your organization’s namespace as your model’s namespace. - The
viam
namespace is reserved for models provided by Viam.
- For example, if your organization uses the
repo-name
is the code repository (GitHub repo) that houses your module code.- Ideally, your
repo-name
should describe the common functionality provided across the model or models of that module.
- Ideally, your
model-name
is the name of the new resource model that your module will provide.
For example, if your organization namespace is acme
, and you have written a new base implementation named mybase
which you have pushed to a repository named my-custom-base-repo
, you would use the namespace acme:my-custom-base-repo:mybase
for your model.
More requirements:
- Your model triplet must be all-lowercase.
- Your model triplet may only use alphanumeric (
a-z
and0-9
), hyphen (-
), and underscore (_
) characters.
Determine the model name you want to use based on these requirements, then proceed to the next section.
Write your new resource model definition
In this step, you will code the logic that is unique to your model.
Tip (optional)
If you are using Python or Golang, use the viam module generate
CLI command to generate the scaffolding for a module with one resource model.
For a step-by-step guide that uses the CLI module generator, see Create a Hello World module.
Follow the instructions below to define the capabilities provided by your model, for the language you are using to write your module code:
Note: Pin numbers
If your module references pin numbers, you should use physical board pin numbers, not GPIO (BCM) numbers, to maintain consistency across resources from different sources.
First, inspect the built-in class provided by the resource API that you are extending.
For example, if you wanted to add support for a new base component to Viam (the component that represents the central physical platform of your machine, to which all other components are connected), you would start by looking at the built-in Base
component class, which is defined in the Viam Python SDK in the following file:
Resource Model File | Description |
---|---|
src/viam/components/base/base.py | Defines the built-in Base class, which includes several built-in methods such as move_straight() . |
Tip
You can view the other built-in component classes in similar fashion.
For example, the Camera
class is defined in camera.py and the Sensor
class is defined in sensor.py.
The same applies to service APIs.
For example, the MLModel
class for the ML Model service is defined in mlmodel.py.
Take note of the methods defined as part of the class API, such as move_straight()
for the Base
class.
Your new resource model must either:
- implement all of the methods that the corresponding resource API provides, or
- explicitly raise a
NotImplementedError()
in the body of functions you do not want to implement or putpass
.
Otherwise, your new class will not instantiate.
Next, create a file that will define your new resource model.
This file will inherit from the existing class for your resource type, implement each built-in method for that class (or raise a NotImplementedError()
for it), and define any new functionality you want to include as part of your model.
For example, the following file, my_base.py
:
- defines a new model
acme:my-custom-base-repo:mybase
by implementing a newMyBase
class, which inherits from the built-in classBase
. - defines a new constructor
new_base()
and a new methodvalidate_config()
. - does not implement several built-in methods, including
get_properties()
andset_velocity()
, but instead raises aNotImplementedError
error in the body of those functions. This prevents these methods from being used by new base components that use this modular resource, but meets the requirement that all built-in methods either be defined or raise aNotImplementedError()
error, to ensure that the newMyBase
class successfully instantiates.
When implementing built-in methods from the Viam Python SDK in your model, be sure your implementation of those methods returns any values designated in the built-in function’s return signature, typed correctly.
For example, the is_moving()
implementation in the example code above returns a bool
value, which matches the return value of the built-in is_moving()
function as defined in the Viam Python SDK in the file base.py
.
For more information on the base component API methods used in this example, see the following resources:
First, inspect the built-in package provided by the resource API that you are extending.
For example, if you wanted to add support for a new base component to Viam (the component that represents the central physical platform of your machine, to which all other components are connected), you would start by looking at the built-in base
component package, which is defined in the Viam Go SDK in the following file:
Resource Model File | Description |
---|---|
components/base/base.go | Defines the built-in base package, which includes several built-in methods such as MoveStraight() . |
Tip
You can view the other built-in component packages in similar fashion.
For example, the camera
package is defined in camera.go and the sensor
package is defined in sensor.go.
The same applies to service APIs.
For example, the mlmodel
package for the ML Model service is defined in mlmodel.go.
Take note of the methods defined as part of the package API, such as MoveStraight()
for the base
package.
Your new resource model must either:
- implement all of the methods that the corresponding resource API provides, or
- explicitly return an
errUnimplemented
error in the body of functions you do not want to implement.
Otherwise, your new package will not instantiate.
Next, create a file that will define your new resource model.
This file will inherit from the existing package for your resource type, implement - or return an errUnimplemented
error for - each built-in method for that package, and define any new functionality you want to include as part of your model.
For example, the following file, mybase.go
:
- defines a new model
acme:my-custom-base-repo:mybase
by implementing a newmybase
package, which inherits from the built-in packagebase
. - defines a new constructor
newBase()
and a new methodValidate()
. - does not implement several built-in methods, including
MoveStraight()
andSetVelocity()
, but instead returns anerrUnimplemented
error in the body of those methods. This prevents these methods from being used by new base components that use this modular resource, but meets the requirement that all built-in methods either be defined or return anerrUnimplemented
error, to ensure that the newmybase
package successfully instantiates.
Note
For an example featuring a sensor, see MCP3004-8.
For additional examples use the modular resources search to search for examples of the model you are implementing, and click on the model’s link to be able to browse its code.
When implementing built-in methods from the Viam Go SDK in your model, be sure your implementation of those methods returns any values designated in the built-in method’s return signature, typed correctly.
For example, the SetPower()
implementation in the example code above returns a multierr
value (as provided by the multierr
package), which allows for transparently combining multiple Go error
return values together.
This matches the error
return type of the built-in SetPower()
method as defined in the Viam Go SDK in the file base.go
.
For more information on the base component API methods used in this example, see the following resources:
First, inspect the built-in class provided by the resource API that you are extending. In the C++ SDK, all built-in classes are abstract classes.
For example, if you wanted to add support for a new base component to Viam (the component that represents the central physical platform of your machine, to which all other components are connected), you would start by looking at the built-in Base
component class, which is defined in the Viam C++ SDK in the following files:
Resource Model File | Description |
---|---|
components/base/base.hpp | Defines the API of the built-in Base class, which includes the declaration of several purely virtual built-in functions such as move_straight() . |
components/base/base.cpp | Provides implementations of the non-purely virtual functionality defined in base.hpp . |
Tip
You can view the other built-in component classes in similar fashion.
For example, the API of the built-in Camera
class is defined in camera.hpp and its non-purely virtual functions are declared in camera.cpp, while the API of the built-in Sensor
class is defined in sensor.hpp and its non-purely virtual functions are declared in sensor.cpp.
The same applies to service APIs.
For example, the API of the built-in MLModelService
class for the ML Model service is defined in mlmodel.hpp and its non-purely virtual functions declared in mlmodel.cpp.
Take note of the functions defined as part of the class API, such as move_straight()
for the Base
class.
Your new resource model must either:
- define all pure virtual methods that the corresponding resource API provides, or
- explicitly
throw
aruntime_error
in the body of functions you do not want to implement.
Otherwise, your new class will not instantiate.
For example, if your model implements the base
class, you would either need to implement the move_straight()
virtual method, or throw
a runtime_error
in the body of that function.
However, you would not need to implement the resource_registration()
function, as it is not a virtual method.
Next, create your header file (.hpp
) and source file (.cpp
), which together define your new resource model.
The header file defines the API of your class, and includes the declaration of any purely virtual functions, while the source file includes implementations of the functionality of your class.
For example, the files below define the new MyBase
class and its constituent functions:
- The
my_base.hpp
header file defines the API of theMyBase
class, which inherits from the built-inBase
class. It defines a new methodvalidate()
, but does not implement several built-in functions, includingmove_straight()
andset_velocity()
, instead it raises aruntime_error
in the body of those functions. This prevents these functions from being used by new base components that use this modular resource, but meets the requirement that all built-in functions either be defined orthrow
aruntime_error
error, to ensure that the newMyBase
class successfully instantiates. - The
my_base.cpp
source file contains the function and object definitions used by theMyBase
class.
Note that the model triplet itself, acme:my-custom-base-repo:mybase
in this example, is defined in the entry point (main program) file main.cpp
, which is described in the next section.
When implementing built-in functions from the Viam C++ SDK in your model, be sure your implementation of those functions returns any values designated in the built-in function’s return signature, typed correctly.
For example, the set_power()
implementation in the example code above returns three values of type Vector3
, Vector3
, AttributeMap
, which matches the return values of the built-in set_power()
function as defined in the Viam C++ SDK in the file base.hpp
.
For more information on the base component API methods used in these examples, see the following resources:
For more C++ module examples of varying complexity,see the C++ SDK examples
directory.
Write an entry point (main program) file
A main entry point file starts the module, and adds the resource model.
Follow the instructions below for the language you are using to write your module code:
Create a
- imports the custom model
- defines a
main()
function that registers the model with the Python SDK - creates and starts the module
For example, the following main.py
file serves as the entry point file for the MyBase
custom model.
It imports the MyBase
model from the my_base.py
file that provides it, and defines a main()
function that registers it.
Create a
- imports the custom model
- defines a
main()
function that registers the model with the Viam Go SDK - creates and starts the module
For example, the following main.go
file serves as the entry point file for the mybase
custom model.
It imports the mybase
model from the my_base.go
file that provides it, and defines a main()
function that registers it.
Create a
- imports the custom model implementation and definitions
- includes a
main()
function that registers the model with the Viam C++ SDK - creates and starts the module
For example, the following main.cpp
file serves as the entry point file for the mybase
custom model.
It imports the mybase
model implementation from the my_base.hpp
file that provides it, declares the model triplet acme:my-custom-base-repo:mybase
, and defines a main()
function that registers it.
(Optional) Configure logging
If desired, you can configure your module to output log messages to the Viam app. Log messages sent to the Viam app appear under the LOGS tab for your machine in an easily-parsable and searchable manner.
Log messages generated when your machine is offline are queued, and sent together when your machine connects to the internet once more.
Add the following code to your module code to enable logging to the Viam app, depending on the language you using to code your module. You can log in this fashion from the model definition file or files, the entry point (main program) file, or both, depending on your logging needs:
Tip
The example code shown above under Write your new resource model definition includes the requisite logging code already.
To enable your Python module to write resource-level log messages to the Viam app, add the following lines to your code:
# Within some method, log information:
self.logger.debug("debug info")
self.logger.info("info")
self.logger.warn("warning info")
self.logger.error("error info")
self.logger.exception("error info", exc_info=True)
self.logger.critical("critical info")
Resource-level logs are recommended instead of global logs for modular resources, because they make it easier to determine which component or service an error is coming from. Resource-level error logs appear in the ERROR LOGS section of each resource’s configuration card in the app.
Note
In order to see resource-level debug logs when using your modular resource, you’ll either need to run viam-server
with the -debug
option or configure your machine or individual resource to display debug logs.
To enable your Go module to write log messages to the Viam app, add the following lines to your code:
// In your import() block, import the logging package:
import(
...
"go.viam.com/rdk/logging"
)
// Alter your component to hold a logger
type component struct {
...
logger logging.Logger
}
// Then, alter your component's constructor to save the logger:
func init() {
registration := resource.Registration[resource.Resource, *Config]{
Constructor: func(ctx context.Context, deps resource.Dependencies, conf resource.Config, logger logging.Logger) (resource.Resource, error) {
...
return &component {
...
logger: logger
}, nil
},
}
resource.RegisterComponent(...)
}
// Finally, when you need to log, use the functions on your component's logger:
fn (c *component) someFunction(ctx context.Context, a int) {
// Log with severity info:
c.logger.CInfof(ctx, "performing some function with a=%v", a)
// Log with severity debug (using value wrapping):
c.logger.CDebugw(ctx, "performing some function", "a" ,a)
// Log with severity warn:
c.logger.CWarnw(ctx, "encountered warning for component", "name", c.Name())
// Log with severity error without a parameter:
c.logger.CError(ctx, "encountered an error")
}
viam-server
automatically gathers all output sent to the standard output (STDOUT
) in your C++ code and forwards it to the Viam app when a network connection is available.
We recommend that you use a C++ logging library to assist with log message format and creation, such as the Boost trivial logger:
#include <boost/log/trivial.hpp>
Compile or package your module
The final step to creating a new module is to create an executable file that viam-server
can use to run your module on demand.
This executable file:
- runs your module when executed
- takes a local UNIX socket as a command line argument
- exits cleanly when sent a termination signal
Depending on the language you are using to code your module, you may have options for how you create your executable file:
The recommended approach for Python is to use PyInstaller
to compile your module into a packaged executable: a standalone file containing your program, the Python interpreter, and all of its dependencies.
When packaged in this fashion, you can run the resulting executable on your desired target platform or platforms without needing to install additional software or manage dependencies manually.
To create a packaged executable:
First, create a Python virtual environment in your module’s directory to ensure your module has access to any required libraries. Be sure you are within your Python virtual environment for the rest of these steps: your terminal prompt should include the name of your virtual environment in parentheses.
Create a
requirements.txt
file containing a list of all the dependencies your module requires. For example, arequirements.txt
file with the following contents ensures that the Viam Python SDK (viam-sdk
), PyInstaller (pyinstaller
), and the Google API Python client (google-api-python-client
) are installed:viam-sdk pyinstaller google-api-python-client
Add additional dependencies for your module as needed. See the pip
requirements.txt
file documentation for more information.Install the dependencies listed in your
requirements.txt
file within your Python virtual environment using the following command:python -m pip install -r requirements.txt -U
Then compile your module, adding the Google API Python client as a hidden import:
python -m PyInstaller --onefile --hidden-import="googleapiclient" src/main.py
If you need to include any additional data files to support your module, specify them using the
--add-data
flag:python -m PyInstaller --onefile --hidden-import="googleapiclient" --add-data src/arm/my_arm_kinematics.json:src/arm/ src/main.py
By default, the output directory for the packaged executable is
dist , and the name of the executable is derived from the name of the input script (in this case, main).
We recommend you use PyInstaller with the build-action
GitHub action which provides a simple cross-platform build setup for multiple platforms: x86 and Arm Linux distributions, and MacOS.
Follow the instructions to Update an existing module using a GitHub action to add the build configuration to your machine.
With this approach, you can make a build script like the following to
build your module, and configure the resulting executable ("entrypoint"
:
#!/bin/bash
set -e
sudo apt-get install -y python3-venv
python3 -m venv .venv
. .venv/bin/activate
pip3 install -r requirements.txt
python3 -m PyInstaller --onefile --hidden-import="googleapiclient" src/main.py
tar -czvf dist/archive.tar.gz dist/main
This script automates the process of setting up a Python virtual environment on a Linux arm64 machine, installing dependencies, packaging the Python module into a standalone executable using PyInstaller, and then compressing the resulting executable into a tarball. For more examples of build scripts see Update an existing module using a GitHub action.
Note
PyInstaller does not support relative imports in entrypoints (imports starting with .
).
If you get "ImportError: attempted relative import with no known parent package"
, set up a stub entrypoint as described on GitHub.
In addition, PyInstaller does not support cross-compiling: you must compile your module on the target architecture you wish to support.
For example, you cannot run a module on a Linux arm64
system if you compiled it using PyInstaller on a Linux amd64
system.
Viam makes this easy to manage by providing a build system for modules.
Follow these instructions to automatically build for each system your module can support using Viam’s CLI.
Create a run.sh
shell script that creates a new Python virtual environment, ensures that the package dependencies your module requires are installed, and runs your module.
This is the recommended approach for modules written in Python:
Create a
requirements.txt
file containing a list of all the dependencies your module requires. For example, arequirements.txt
file with the following contents ensures that the Viam Python SDK (viam-sdk
) is installed:viam-sdk
Add additional dependencies for your module as needed. See the pip
requirements.txt
file documentation for more information.Add a shell script that creates a new virtual environment, installs the dependencies listed in
requirements.txt
, and runs the module entry point filemain.py
:#!/bin/sh cd `dirname $0` # Create a virtual environment to run our code VENV_NAME="venv" PYTHON="$VENV_NAME/bin/python" python3 -m venv $VENV_NAME $PYTHON -m pip install -r requirements.txt -U # remove -U if viam-sdk should not be upgraded whenever possible # Be sure to use `exec` so that termination signals reach the python process, # or handle forwarding termination signals manually exec $PYTHON <your-src-dir-if-inside>/main.py $@
Make your shell script executable by running the following command in your terminal:
sudo chmod +x <your-file-path-to>/run.sh
Using a virtual environment together with a requirements.txt
file and a run.sh
file that references it ensures that your module has access to any packages it requires during runtime.
If you intend to share your module with other users, or to deploy it to a fleet of machines, this approach handles dependency resolution for each deployment automatically, meaning that there is no need to explicitly determine and install the Python packages your module requires to run on each machine that installs your module.
See prepare a Python virtual environment for more information.
Use the nuitka
Python compiler to compile your module into a single executable file:
In order to use Nuitka, you must install a supported C compiler on your machine.
Then, create a Python virtual environment in your module’s directory to ensure your module has access to any required libraries. Be sure you are within your Python virtual environment for the rest of these steps: your terminal prompt should include the name of your virtual environment in parentheses.
Create a
requirements.txt
file containing a list of all the dependencies your module requires. For example, arequirements.txt
file with the following contents ensures that the Viam Python SDK (viam-sdk
) and Nuitka (nuitka
) are installed:viam-sdk nuitka
Add additional dependencies for your module as needed. See the pip
requirements.txt
file documentation for more information.Install the dependencies listed in your
requirements.txt
file within your Python virtual environment using the following command:python -m pip install -r requirements.txt -U
Then, compile your module using Nuitka with the following command:
python -m nuitka --onefile src/main.py
If you need to include any additional data files to support your module, specify them using the
--include-data-files
flag:python -m nuitka --onefile --include-data-files=src/arm/my_arm_kinematics.json src/main.py
Compiling your Python module in this fashion ensures that your module has access to any packages it requires during runtime. If you intend to share your module with other users, or to deploy it to a fleet of machines, this approach “bundles” your module code together with its required dependencies, making your module highly-portable across like architectures.
However, used in this manner, Nuitka does not support relative imports (imports starting with .
).
In addition, Nuitka does not support cross-compiling: you can only compile your module on the target architecture you wish to support if using the Nutika approach.
If you want to cross-compile your module, consider using a different local compilation method, or the module build start
command to build your module on a cloud build host, which supports building for multiple platforms.
For example, you cannot run a module on a Linux arm64
system if you compiled it using Nuitka on a Linux amd64
system.
Use Go to compile your module into a single executable:
- Navigate to your module directory in your terminal.
- Run
go build
to compile your entry point (main program) filemain.go and all other.go files in the directory, building your module and all dependencies into a single executable file. - Run
ls
in your module directory to find the executable, which should have the same name as the module directory.
Compiling your Go module also generates the go.mod
and go.sum
files that define dependency resolution in Go.
See the Go compilation documentation for more information.
Create a
Create a
CMakeLists.txt file in your module directory to instruct the compiler how to compile your module. For example, the following basic configuration downloads the C++ SDK and handles compile-time linking for a module namedmy-base
:cmake_minimum_required(VERSION 3.7 FATAL_ERROR) project(my-base LANGUAGES CXX) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) include(FetchContent) FetchContent_Declare( viam-cpp-sdk GIT_REPOSITORY https://github.com/viamrobotics/viam-cpp-sdk.git GIT_TAG main # SOURCE_DIR ${CMAKE_SOURCE_DIR}/../viam-cpp-sdk CMAKE_ARGS -DVIAMCPPSDK_USE_DYNAMIC_PROTOS=ON FIND_PACKAGE_ARGS ) FetchContent_MakeAvailable(viam-cpp-sdk) FILE(GLOB sources *.cpp) add_executable(my-base ${sources}) target_link_libraries(my-base PRIVATE viam-cpp-sdk::viamsdk)
Create a
run.sh file in your module directory to wrap the executable and perform basic sanity checks at runtime.The following example shows a simple configuration that runs a module named
my-base
:#!/usr/bin/env bash # bash safe mode set -euo pipefail cd $(dirname $0) exec ./my-base $@
Use C++ to compile and obtain a single executable for your module:
Create a new
build directory within your module directory:mkdir build cd build
Build and compile your module:
cmake .. -G Ninja ninja all ninja install
Run
ls
in your module’sbuild directory to find the compiled executable, which should have the same name as the module directory (my-base
in these examples):
For more information on building a module in C++, see the C++ SDK Build Documentation.
(Optional) Create a README
To provide usage instructions for any modular resources in your module, you should create a
Test your module locally
Tip
If you would like to test your module locally against a target platform other than your development machine before uploading it, you can follow the steps for Iterative module development to verify that any code changes you have made work as expected on your target platform.
To use a local module on your machine, first make sure any physical hardware implemented in your module is connected to your machine’s computer. Add the module to your machine’s config, then add the component or service it implements:
Navigate to the CONFIGURE tab of your machine’s page in the Viam app.
Click the + (Create) icon next to your machine part in the left-hand menu and select Local module, then Local module.
Enter a Name for this instance of your module.
Enter the module’s Executable path. This path must be the absolute path on your machine’s filesystem to either:
- the module’s executable file, such as
run.sh
or a compiled binary. - a packaged tarball of your module, ending in
.tar.gz
or.tgz
. If you are providing a tarball file in this field, be sure that your packaged tarball contains your module’smeta.json
file within it.
- the module’s executable file, such as
Then, click the Create button, and click Save in the upper right corner to save your config.
Still on your machine’s CONFIGURE tab, click the + (Create) icon next to your machine part in the left-hand menu.
Select Local module, then select Local component or Local service.
Select or enter the model namespace triplet of your modular resource’s model.
Select the type of modular resource provided by your module, such as a camera, from the dropdown menu.
Enter a name for this instance of your modular resource. This name must be different from the module name.
Click Create to create the modular resource provided by the local module.
Once you’ve added your local module using steps 1-5, you can repeat steps 6-11 to add as many additional instances of your modular resource as you need.
Upload your module to the modular resource registry
Once you are satisfied with the state of your module, you can upload your module to the Viam Registry to:
- share your module with other Viam users
- deploy your module to a fleet of machines from a central interface
See How to Upload a Module for instructions.
Deploy your module to more machines
You have now created a module, and are ready to deploy it to a fleet of machines. There are two ways to deploy a module:
- Through the Viam Registry: Once you have uploaded your new module to the Viam Registry, add the module to one or more machines in the Viam app. You can also choose to configure automated uploads for new module versions through a continuous integration (CI) workflow, using a GitHub Action if desired, greatly simplifying how you push changes to your module to the registry as you make them.
- As a local module (without uploading it to the Viam app), as you did in the Test your module locally step above. This is a great way to test, but if you’d like to use the module on more machines it’s easiest to add it to the registry either publicly or privately.
Often, developers first test their new module by deploying it as a local module to a test machine. With a local installation, you can test your module in a controlled environment to confirm that it functions as expected, and make changes to your module as needed.
Next steps
For instructions on how to update or delete modules you’ve created, see the following how-to guide:
To read more about module development at Viam, check out these tutorials that create modules:
Have questions, or want to meet other people working on robots? Join our Community Discord.
If you notice any issues with the documentation, feel free to file an issue or edit this file.
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!