How to configure ODS
A basic JSON
The configuration example uses the following JSON
for a simple configuration. This configuration expects at least one Head (3D imager) at port 2
.
{
"applications": {
"instances": {
"app0": {
"class": "ods",
"name":"app0",
"ports": [
"port2",
"port6"
],
"state": "CONF"
}
}
}
}
Note
port6
is always part of the “ports” configuration. It refers to the IMU
and is needed for the ODS algorithm to work properly.
The configuration example
#############################################
# Copyright 2021-present ifm electronic, gmbh
# SPDX-License-Identifier: Apache-2.0
#############################################
# %%
import json
import logging
import pathlib
from jsonschema import exceptions as json_exceptions
from jsonschema import validate
from ifm3dpy.device import Error as ifm3dpy_error
from ifm3dpy.device import O3R
logging.basicConfig(
format="%(asctime)s:%(filename)-10s:%(levelname)-8s:%(message)s",
datefmt="%y-%m-%d %H:%M:%S",
level=logging.DEBUG,
)
logger = logging.getLogger(__name__)
def validate_json(schema: dict, config: dict) -> dict:
"""
This function can be used to validate
a configuration before setting it.
Note that ifm3dpy.device.O3R.set() will validate the
requested configuration, but using the jsonschema.validate
function will provide a more verbose validation.
:param config: the configuration to validate
:raises ValidationError: if the validation fails
"""
try:
logger.info(f"Validating configuration: {json.dumps(config, indent=4)}")
validate(config, schema)
except json_exceptions.ValidationError as err:
logger.exception("Error while validating the json schema")
raise err
except json_exceptions.SchemaError as err:
logger.exception("Incorrect json schema")
raise err
return config
def load_config_from_file(config_file: pathlib.Path) -> dict:
"""
Configure the device from a configuration file.
The provided configuration is validated using the schema validator.
:param config_file: path to the configuration file
"""
try:
logger.info(f"Loading configuration from file {config_file}")
with open(pathlib.Path(__file__).parent / config_file, "r") as f:
config = json.load(f)
return config
except OSError as err:
logger.exception("Error while reading configuration file")
raise err
# %%
if __name__ == "__main__":
try:
# If the example python package was build, import the configuration
from ovp8xxexamples import config
IP = config.IP
PORT = config.PORT_3D
except ImportError:
# Otherwise, use default values
print(
"Unable to import the configuration.\nPlease run 'pip install -e .' from the python root directory"
)
print("Defaulting to the default configuration.")
IP = "192.168.0.69"
PORT = "port2"
# Example on how to use the above boilerplate.
o3r = O3R(IP)
#############################################
# Examples on getting configurations snippets
#############################################
logger.info("Example: Getting various components of the VPU configuration...")
for config_path_list in [
[], # Get the full configuration.
# Get a subset of the configuration using JSON pointer
["/device/swVersion/firmware"],
[ # Get multiple subsets of the configuration using JSON pointer
"/device/swVersion/firmware",
"/device/status",
"/ports/port0/info",
],
]:
config_snippet = o3r.get(config_path_list)
logger.info(f"o3r.get({config_path_list}) -> {config_snippet}")
# %%
# ... if a key is unavailable, the resulting snippet will not have that key
logger.info(
"Demonstrating the unpacking of config retrieved from the VPU using a questionable JSON pointer..."
)
try:
config_snippet = o3r.get(["/ports/port5/info"])
logger.info("port5 is present...") # {'ports': {'port5': {...} }}
except ifm3dpy_error as err:
logger.info("port5 is not present...") # {'ports': {'port5':{}}}}
else:
# {'ports': None}
logger.info(
"port5 config unavailable... check diagnostics dump for possible explanation..."
)
#####################################
# Examples on setting configurations
#####################################
logger.info("Example: Setting various components of the VPU configuration...")
# Using the VPU schema is optional but can be useful for pinpointing why a given config snippet would fail to load onto the VPU
schema = o3r.get_schema()
invalid_snippet = {"device": {"info": {"description": 0}}}
try: # This will throw an exception
validate_json(schema, invalid_snippet)
# Failing silently to continue through the examples
o3r.set(invalid_snippet)
except json_exceptions.ValidationError:
pass
# This snippet is expected to be valid
config_snippet = {
"device": {"info": {"description": "I will use this O3R to change the world"}}
}
validate_json(schema, config_snippet)
o3r.set(config_snippet)
# In production, all possible exceptions must be considered but we will not worry about that here.
# Set two configuration fragments at the same time. This schema will not be valid if the specified port is not plugged in and recognized by the VPU
config_snippet = {
"device": {"info": {"name": "my_favorite_o3r"}},
"ports": {PORT: {"info": {"name": "my_favorite_port"}}},
}
try:
validate_json(schema, config_snippet)
o3r.set(config_snippet)
except json_exceptions.ValidationError:
pass
# Before setting an application configuration, erase any previously present app
o3r.reset("/applications")
config_snippet = load_config_from_file("configs/ods_one_head_config.json")
try:
validate_json(schema, config_snippet)
except json_exceptions.ValidationError:
pass
o3r.set(config_snippet)
logger.info("You reached the end of the ODSConfig tutorial!")
# %%
Tip
Resetting the application If issues with the receiving of data or changing the configuration occur, an reset of the application could solve these issues.
from ifm3dpy.device import O3R
o3r = O3R()
o3r.reset("/applications")