Basic concepts
Field
A field describes the entire field operation in the system add-on web app. It exists out of shapefiles with the Coordinate Reference system (CRS) WGS84 or UTM.
A field includes:
traject
: A trajectory is mandatory when executing a field operation. The shapefile is of the shape type Linestring.geofence
: A geofence is also mandatory when executing a field operation. The shapefile is of the shape type polygon.tasks
: Tasks are optional and describe the robot’s actions at specific locations. The following task types existhitch: The hitch is activated (lowered) when a polygon of the task map contains the hitch centre.
continuous: The section is activated when it intersects with a polygon of the task map. A particular type of this is a cardan task, which activates the Power Take Off (PTO) when intersecting the polygon (s) in the task map.
intermittent: The section is activated when it contains a point on the task map.
discrete: The discrete action (mostly a measurement) is performed when the section is the closest to the point of action on the task map.

Figure 1. Task types
Platform
The platform abstracts the robot’s capabilities and includes information such as dimensions, the number and position of the hitches, the vehicle configuration, etc.
The settings.json
file describes the platform configuration and can be edited in the system add-on web app JSON editor.
settings.json
file of the CIMAT robot{
"name": "cimat",
"robot": {
"width": 1.5,
"length": 3.8,
"wheel_diameter": 0.7,
"transform": {
"T": [
0,
-1.0029,
-1.93
],
"R": [
0,
0,
0
]
}
},
"auto_velocity": {
"min": 0.2,
"max": 1.7
},
"nav_modes": [
{
"id": 1,
"name": "pp 90\u00b0 turn"
},
{
"id": 2,
"name": "pp 180\u00b0 turn"
},
{
"id": 3,
"name": "pure pp"
},
{
"id": 4,
"name": "pp rollback"
},
{
"id": 5,
"name": "external"
}
],
"auto_modes": [
{
"id": 1,
"name": "auto"
}
],
"hitches": [
{
"id": 2,
"name": "FB",
"min": 10,
"max": 65,
"types": [
"hitch",
"continuous",
"discrete",
"intermittent"
],
"transform": {
"T": [
0,
0.3314,
-1.3831
],
"R": [
0,
0,
0
]
},
"link_length": 0.601
},
{
"id": 4,
"name": "RB",
"min": 10,
"max": 58,
"types": [
"hitch",
"continuous",
"discrete",
"intermittent"
],
"transform": {
"T": [
0,
-2.45,
-1.2
],
"R": [
0,
0,
0
]
},
"link_length": 0.55
}
],
"gps": {
"device": "serial",
"utm_zone": 31,
"usb_port": "/dev/septentrio0",
"ntrip_server": "flepos.vlaanderen.be",
"ntrip_mountpoint": "<mountpoint>",
"ntrip_uname": "<username>",
"ntrip_pwd": "<password>",
"antenna_rotation": -90,
"transform": {
"T": [
-0.68064,
0,
0
],
"R": [
0,
0,
0
]
}
}
}
The fields in the settings.json
file are:
name
: The name of the robot platformrobot
: The robot platform configuration2.1. The dimensions of the robot platform (
width
,height
,wheel_diameter
)2.2.
transform
: The translation (in meters) and rotation in Euler angles (degrees) of the different robot components to the antenna reference point on the robot. The robot reference point is measured from the ground on and is used by the navigation algorithms, to calculate the robots position in respect to the trajectory.For a 4WD4WS robot vehicle configuration, the robot reference coincides with its geometric center.
For an Ackerman robot, the robot reference coincides with the centre of mass. In the case this does not equal the robot center, this transformation is written under the
transform_center
field of therobot
configuration object.

Figure 2. Robot component transformations, expressed relative to the antenna reference
auto_velocity
:min
andmax
velocity of the platform.nav_modes
: The allowed navigation modes. Depending on the robot platforms’ vehicle configuration, different headland turns are possible. The navigation modes determine these headland turns and are shown in Figure 3 with their corresponding ID.90° spinning: When the robot reaches a corner, it rotates around its axis until its orientation matches the direction of the next trajectory line it needs to follow. This basic turning process applies to both regular corners and headland turns.
180° spinning: When the robot reaches a headland turn, it first rotates around its axis until it aligns with the direction of the next row it needs to follow. After aligning with the new row’s trajectory, the robot moves sideways toward the corner where this new row begins. Once it reaches the corner, the robot continues driving along the trajectory line of the new row. The navigation mode 90° spinning is used when the turns are regular corners.
pure pursuit: When the robot encounters a corner, it will navigate the turn by driving in a circular path. The radius of this circle is determined by the turning radius specified in the platform.json configuration file. If the corner is part of a headland turn (where the two rows of the field are closer together than twice the minimum turning radius), the robot will instead drive along a circular arc that connects the two rows. This arc will have the minimum turning radius, allowing the robot to smoothly transition from one row to the next within the limited space.
rollback: When the robot reaches a headland turn, it initially turns by driving in a quarter-circle, using the minimum turning radius specified for the platform. If the robot doesn’t have enough space to align with the next trajectory line, it will move backward to create the necessary space. Once there is enough room, the robot makes another quarter-circle turn with the minimum turning radius, aligning itself with the new trajectory line and continuing on its path.
external: An external controller can take control of the robot’s navigation by updating the navigation_control parameters. This allows the external controller to direct the robot’s movements, overriding the robot’s default navigation system.

Figure 3. Navigation modes with their navigation id
auto_modes
: The different modes for autonomous navigation.Full auto: The robot operates fully autonomous, with autonomous velocity- and steering control.
Auto steer: The robot only performs autonomous steering, and no autonomous velocity control. This mode provides “steering guidance” functionality.
Auto throttle: The robot only performs autonomous velocity control, and no autonomous steering control. This mode provides “cruise control” functionality.
hitches
: The specifications of the different hitches on the platform.6.1.
id
: hitch id6.2.
name
: name of the hitch6.3.
min
: min height of the hitch (cm)6.4.
max
: max height of the hitch (cm)6.5.
transform
to the hitch hinge (see Figure 2)6.6.
types
: compatible task types with the hitchgps
: The RTK GNSS configuration.7.1.
device
: The device field is set serial for USB devices and socket for network devices.7.2.
utm_zone
: The Universal Transverse Mercator (UTM) projection zone to complete the EPSG:326xx code whereby xx is the UTM zone.7.3.
usb_port
orìp
andport
: These parameters are device interface dependent. For a USB device the device name needs to be provided, and for a socket device the network- ip and port.7.4. NTRIP configuration
ntrip_server
,ntrip_mountpoint
,ntrip_uname
,ntrip_pwd
7.5.
antenna_rotation
: The antenna rotation describes an additional rotation of the antennas around the z-axis (in degrees).0 or 180 if the antennas are in the longitudinal direction of the platform.
90 or -90 if the antennas are in the lateral direction of the platform.
7.6.
transform
: The transform field describes the transformation to the antenna reference (see Figure 2).
Implements
The <implement-name>.json
files describe the implement configuration and can be edited in the system add-on web app JSON editor.
The fields in the <implement-name>.json
file are:
name
: The name of the implement.on_taskmap
: This variable determines whether the task needs to be executed on the task map. If not, the sections can be operated by an add-on or program on another computer. If yes, the sections are operated according to the field configuration.types
: The implement supports several types of operations: continuous, intermittent, and discrete, as illustrated in Figure 2. Some implements can handle multiple types of operations simultaneously. For example, the auto-label implement shown in Listing 2 is designed for data collection using two cameras. The sections are defined by the cameras’ fields of view. A camera can be activated in two scenarios: when the sections overlap with a specified polygon (a continuous task) or when a crop plant enters the field of view (an intermittent task).
{
"name": "auto-label",
"on_taskmap": true,
"types": [
"continuous",
"intermittent"
],
"sections": [
{
"id": "L",
"width": 0.25,
"up": 0.075,
"down": 0.075,
"transform": {
"T": [
0.35,
-0.98,
-0.4
],
"R": [
0,
0,
0
]
}
},
{
"id": "R",
"width": 0.25,
"up": 0.075,
"down": 0.075,
"transform": {
"T": [
-0.35,
-0.98,
-0.4
],
"R": [
0,
0,
0
]
}
}
]
}
sections
: The sections are an array of the geometries and transformations of the implement sections.4.1.
id
: The id of the section (string).4.2. The dimensions
width
,up
,down
in meters.4.3.
transform
: The transformation of the center of the section to the hitch pen, visualized Figure 2.4.4. A section can be repeated over a specified distance by using the
repeats
andoffset
fields. This functionality allows for the configuration of implements with repetitive sections, such as the spray boom described in Listing 3. The spray boom consists of 24 sections, but only the transformation for the first section needs to be defined. Therepeats
andoffset
fields define how these sections are repeated along the boom.
repeats
and offset
fields{
"name": "spray-boom",
"on_taskmap": true,
"types": [
"continuous",
"intermittent"
],
"sections": [
{
"id": "",
"width": 0.15,
"up": 0.05,
"down": 0.05,
"repeats": 24,
"offset": 0.25,
"transform": {
"T": [
3,
-0.98,
-0.4
],
"R": [
0,
0,
0
]
}
}
]
}
Interfaces
The config.json
file describes the system’s Redis variables and the mechatronic/operational layer interface configuration.
You can edit the configuration file in the system add-on web app JSON editor.
config.json
file of the CIMAT robot{
"protocols": {
"snap7": {
"ip": "192.168.1.2",
"rack": 0,
"read_db": 201,
"slot": 1,
"write_db": 200
},
"redis": {
"ip": "127.0.0.1",
"port": 6379
}
},
"variables": {
"plc": {
"control": {
"navigation": "navigation_control",
"hitch_fb": "hitch_control",
"hitch_rb": "hitch_control",
"substate": "substate"
},
"monitor": {
"drive_fl": "drive_monitor",
"wheel_fl": "wheel_monitor",
"drive_fr": "drive_monitor",
"wheel_fr": "wheel_monitor",
"drive_rl": "drive_monitor",
"wheel_rl": "wheel_monitor",
"drive_rr": "drive_monitor",
"wheel_rr": "wheel_monitor",
"imu": "imu_monitor",
"hitch_fb": "hitch_monitor",
"hitch_rb": "hitch_monitor",
"navigation": "navigation_monitor",
"state": "state",
"substate": "substate"
}
},
"pc": {
"gps": "gps",
"simulation": "simulation",
"navigation": "navigation",
"purepursuit": "purepursuit",
"pid_steady_state": "pid",
"pid_rough": "pid",
"path": "path",
"field": "field",
"implement": "implement",
"execution": "execution"
}
}
}
The fields in the config.json
file are:
The
protocols
object defines the protocol configuration.1.1. The
snap7
object provides the mechatronic/operational layer interface parameters:1.1.1. the
ip
address of the PLC1.1.2. the
read_db
andwrite_db
data block (DB), which correspond with the higherLevelMonitor and higherLevelControl1.1.3. the
rack
andslot
of these data blocks1.2 The
redis
object provides the Redis ARTOF interface parameters:1.2.1
ip
andport
: the IP address and port of the Redis serverThe
variables
object defines theplc
andpc
Redis variables on the system.2.1.
plc
variables: These variables are continuously synced between the operational and mechatronic layer.2.1.1 the
monitor
variables are read S7-communication protocol (Snap7) by theRobotPLC
2.1.2 the
control
variables are written S7-communication protocol (Snap7) by theRobotPLC
2.2.
pc
variables are solely used by the operational layer and require no synchronization with the mechatronic layer.
The configuration depends on the platform configuration (vehicle configuration, number of hitches, energy source, etc.).
The types.json
file describes recurrent composite types in the config.json
file.
These types can be nested as can be seen in Listing 5.
types.json
file{
"xyz": {
"x": "float",
"y": "float",
"z": "float"
},
"direction": {
"longitudinal": "float",
"angular": "float",
"lateral": "float"
},
"drive_monitor": {
"power": "float",
"voltage": "float",
"current": "float",
"rpm": "float",
"temperature": "float",
"torque": "float"
},
"wheel_monitor": {
"speed": "float",
"rpm": "float",
"angle": "float"
},
"battery_monitor": {
"soc": "float",
"current": "float",
"voltage": "float",
"power": "float",
"capacity": "float",
"temperature": "float"
},
"fuel_monitor": {
"temperature": "float",
"level": "float",
"volume": "float",
"type": "string"
},
"generator_monitor": {
"temperature": "float",
"rpm": "float",
"fuel": "fuel_monitor"
},
"imu_monitor": {
"acceleration": "xyz",
"rotation": "xyz"
},
"hitch_monitor": {
"busy": "bool",
"height": "float",
"angle": "float",
"feedback_sections": "array[32] of uint8"
},
"state": {
"safe": "bool",
"normal": "bool",
"auto": "bool",
"aware": "bool",
"steer": "bool",
"throttle": "bool",
"error": "bool"
},
"substate": {
"programming": "bool",
"dummy": "bool"
},
"hitch_control": {
"activate": "bool",
"activate_discrete": "bool",
"activate_continuous": "bool",
"activate_cardan": "bool",
"setpoint": "int16",
"activate_sections": "array[32] of uint8"
},
"navigation_control": {
"velocity": "direction",
"sideways": "bool",
"end_reached": "bool",
"heartbeat": "bool"
},
"navigation_monitor": {
"velocity": "direction"
},
"gps": {
"fix": "int",
"hrp_mode": "int",
"ground_speed": "float"
},
"simulation": {
"fix": "int",
"active": "bool",
"auto": "bool",
"factor": "float"
},
"navigation": {
"non_operational_velocity": "float",
"operational_velocity": "float",
"sideways_velocity": "float",
"spinning_velocity": "float",
"max_angular_velocity": "float",
"mode": "int",
"spin_angle": "float",
"turning_radius": "float"
},
"purepursuit": {
"carrot_distance": "float",
"inter_point_distance": "float",
"weight_factor": "float"
},
"pid": {
"p": "float",
"i": "float",
"d": "float",
"integral": "float",
"derivative": "float",
"proportional": "float"
},
"path": {
"orientation": "float",
"deviation": "float"
},
"field": {
"name": "string",
"updated": "bool"
},
"implement": {
"slow_down": "bool",
"disable": "bool"
},
"execution": {
"notification": "string"
}
}
The names of the Redis variables or keys are the composition of the nested object keys. Some examples of how these Redis keys look like are:
plc.monitor.drive_fl.current
, plc.monitor.drive_fr.temperature
, plc.monitor.hitch_fb.feedback_sections.27
, plc.control.navigation.heartbeat
, plc.control.hitch_fb.activate_sections.30
, pc.navigation.turning_radius
, pc.purepursuit.carrot_distance
Redis variables that need configuration are listed in the redis.init.json
file, as shown in the variables
object in Listing 4.
The initialization is only done at system installation. Redis variables are persistent. So these values are preserved on system reboot.
Besides, the redis.init.json
file contains information related to the processes and jobs that need to run.
The latter is discussed in the Jobs section.
redis.init.json
file of the CIMAT robot{
"system": {
"ilvoProcesses": [
{
"Name": "ilvo-navigation",
"Running": true,
"SoftwareUpdate": true,
"CheckHeartbeat": true
},
{
"Name": "ilvo-operation",
"Running": true,
"SoftwareUpdate": true,
"CheckHeartbeat": true
},
{
"Name": "ilvo-simulation",
"Running": true,
"SoftwareUpdate": true,
"CheckHeartbeat": true
},
{
"Name": "ilvo-robot-plc",
"Running": true,
"SoftwareUpdate": true,
"CheckHeartbeat": false
},
{
"Name": "ilvo-gps",
"Running": true,
"SoftwareUpdate": true,
"CheckHeartbeat": false
}
],
"ilvoAddons": [
{
"Name": "system",
"Running": true,
"SoftwareUpdate": true,
"DockerRegistry": {
"username": "artof-ilvo",
"password": "glpat-ZZs4PkN86nbopeXdeGpy",
"serveraddress": "https://gitlab.ilvo.be:5050/v2/"
},
"DockerConfig": {
"Image": "gitlab.ilvo.be:5050/artof-ilvo/addons/system",
"HostConfig": {
"Binds": [
"/var/lib/ilvo:/var/lib/ilvo"
],
"NetworkMode": "host",
"RestartPolicy": {
"Name": "on-failure",
"MaximumRetryCount": 3
}
}
}
},
{
"Name": "node-red",
"Running": true,
"SoftwareUpdate": true,
"DockerRegistry": {
"serveraddress": "https://registry.hub.docker.com/v2/"
},
"DockerConfig": {
"Image": "nodered/node-red",
"HostConfig": {
"Binds": [
"/var/lib/ilvo/node-red:/data",
"/var/lib/ilvo/field:/var/lib/ilvo/field",
"/var/lib/ilvo/implement:/var/lib/ilvo/implement",
"/var/lib/ilvo/config.json:/var/lib/ilvo/config.json",
"/var/lib/ilvo/settings.json:/var/lib/ilvo/settings.json",
"/var/lib/ilvo/types.json:/var/lib/ilvo/types.json"
],
"NetworkMode": "host",
"RestartPolicy": {
"Name": "on-failure",
"MaximumRetryCount": 3
}
}
}
}
]
},
"variables": {
"pc.simulation.fix": 4,
"pc.simulation.factor": 1.0,
"pc.navigation.non_operational_velocity": 1.0,
"pc.navigation.operational_velocity": 1.0,
"pc.navigation.sideways_velocity": 0.2,
"pc.navigation.spinning_velocity": 0.2,
"pc.navigation.max_angular_velocity": 10.0,
"pc.navigation.mode": 1,
"pc.navigation.spin_angle": 25.0,
"pc.navigation.turning_radius": 3.0,
"pc.purepursuit.carrot_distance": 3.5,
"pc.purepursuit.inter_point_distance": 0.1,
"pc.purepursuit.weight_factor": 1.0,
"pc.field.name": "example"
}
}
Jobs
The SystemManager
class is responsible for managing all other processes (Process
) and the add-ons (Addon
) in the operational layer.
A Job
is a higher-level abstraction that implements the common functionality of the Process
and Addon
class.
A Process
is a component managed by the SystemManager
within the operational layer.
These processes are further discussed in the Operational layer section.
An Addon
is an entry for the SystemManager
process, which maintains the system’s add-ons.
The add-on configuration uses the Docker Engine API (1.46) syntax.
These add-ons are further discussed in the Add-ons section.
The redis.init.json
file describes the job configurations at installation.
After installation, the add-on configuration can be adjusted using the system add-on web app.
States
The ARTOF framework continuously updates the state of various platform components in Redis JSON variables, using the GNSS coordinates along with the robot and implement geometry. Each state consists of a position in UTM coordinates and an orientation. Internally, this information is represented as a 4x4 affine transformation matrix, as affines allow for efficient calculations. For easier human readability, the affine matrix is converted into a translation vector (in meters) and an orientation vector (in degrees). This translation vector provides the position, while the orientation vector details the component’s alignment in space.
gps.raw.state
: The GPS raw state provides the UTM position, heading, and roll as measured by the GNSS receiver. This is the state of the dominant GNSS antenna.gps.ref.state
: The GPS raw state is transformed to the center point between the two antennas. This adjusted coordinate is referred to as the GPS reference state.Configuration of
gps
transform
in thesettings.json
file.
robot.ref.state
: The robot reference state, typically located at the robot’s center of mass, serves as the reference point for calculating its relative position to the trajectory. This information is used for the navigation controller.Configuration of
robot
transform
in thesettings.json
file.
robot.center.state
: The geometric centre of the robot is used for visualization.Configuration of
robot
center
in thesettings.json
file.
robot.head.state
: The front of the robot, or the “head,” is utilized by certain navigation controllers that require deviation measurements from a point at the robot’s front.Configuration of
robot
head
in thesettings.json
file.
hitch.states
: The hitch states describe the states of the hitches. This is the state of the hitch hinge.Configuration of
hitches
hitch_<name>
transform
in thesettings.json
file.
implement.states
: The implement states describe the states of the different implements and their sections.Configuration of the
<implement-name>.json
file.