Services and Actions#
This page gives each service and the action of the ROS 2 bridge: the name, the type, the fields and the result codes. The services control the session: the simulation state, lockstep steps, resets, entities, conditions, the episode log and the farm ground truth.
The node sim_bridge offers the interfaces when its parameter control_port is not 0.
Each request goes to one operation of the Simulator Control Channel. The game and ACRES Core answer the same operations.
All names are in the root namespace. They apply to the session, not to one agent.
The standard interfaces are those of the package simulation_interfaces (release 1.4.0 in the conda environment).
The package acres_interfaces adds five services. Messages gives all fields of its types.
| Item | Type | Function |
|---|---|---|
| Python Client | Example | The function call() that the Python examples use. |
| Result Codes | Table | The values of result.result. |
| Supported Features | Table | The features of simulation_interfaces that ACRES has and does not have. |
/get_simulator_features |
Service | Gives the list of the features. |
/get_simulation_state |
Service | Gives the simulation state. |
/set_simulation_state |
Service | Plays, pauses, stops or quits the simulation. |
/step_simulation |
Service | Advances the paused simulation by N physics steps. |
/simulate_steps |
Action | The same, with feedback and a cancel function. |
/reset_simulation |
Service | Starts a new episode. |
/get_entities |
Service | Lists the agents and the spawned entities. |
/get_entity_state |
Service | Gives the pose and the twist of an entity. |
/set_entity_state |
Service | Moves an entity to a pose. |
/spawn_entity |
Service | Adds a prop or a worker. |
/delete_entity |
Service | Removes a spawned entity. |
/get_spawnables |
Service | Lists the entity types that a client can spawn. |
/get_named_poses |
Service | Lists the named places of the tile. |
/acres/set_conditions |
Service | Sets the clock, the weather and the soil water. Type SetConditions. |
/acres/set_vehicle_shift |
Service | Sets the hardware shift of one agent. Type SetVehicleShift. |
/acres/record |
Service | Starts or stops the episode log. Type Record. |
/acres/farm_state |
Service | Gives the ground truth of the fields. Type FarmState. |
/acres/field_query |
Service | Gives the ground truth at one point. Type FieldQuery. |
Conventions#
Python Client#
The Python examples of this page use this node and this function.
import rclpy
rclpy.init()
node = rclpy.create_node("acres_client")
def call(srv_type, name, request):
client = node.create_client(srv_type, name)
client.wait_for_service(timeout_sec=10.0)
future = client.call_async(request)
rclpy.spin_until_future_complete(node, future)
return future.result()
Result Codes#
Each response has a field result of the type simulation_interfaces/msg/Result: the code result.result and the text result.error_message.
The bridge copies the code of the simulator into the response.
| Code | Name | Meaning in ACRES |
|---|---|---|
| 0 | RESULT_FEATURE_UNSUPPORTED |
The simulator does not have the operation, or the request uses a filter that ACRES does not have. |
| 1 | RESULT_OK |
The operation was successful. |
| 2 | RESULT_NOT_FOUND |
No entity or agent has the given name. |
| 3 | RESULT_INCORRECT_STATE |
The simulation is not in the necessary state, for example a step request while the simulation plays. |
| 4 | RESULT_OPERATION_FAILED |
The operation failed. The text gives the cause. |
| 101 and above | Service codes | A code of one service. The row of the service gives it. |
The bridge returns the code 4 when it has no connection to the simulator or when no reply arrives in time.
error_message |
Cause |
|---|---|
the simulator control channel is not connected (game started with -SimControl=5600?) |
The simulator has no control channel on the port, or it is not in operation. |
no reply from the simulator within 30 s |
The simulator did not answer in control_timeout_s. |
the simulator control channel closed |
The connection closed during the request. |
Supported Features#
The service /get_simulator_features returns these feature numbers.
| Number | Name | Interface |
|---|---|---|
| 0 | SPAWNING |
/spawn_entity |
| 1 | DELETING |
/delete_entity |
| 2 | NAMED_POSES |
/get_named_poses |
| 10 | ENTITY_STATE_GETTING |
/get_entity_state |
| 11 | ENTITY_STATE_SETTING |
/set_entity_state |
| 14 | SPAWNABLES |
/get_spawnables |
| 20 | SIMULATION_RESET |
/reset_simulation |
| 22 | SIMULATION_RESET_STATE |
The scope SCOPE_STATE. |
| 23 | SIMULATION_RESET_SPAWNED |
The scope SCOPE_SPAWNED. |
| 24 | SIMULATION_STATE_GETTING |
/get_simulation_state |
| 25 | SIMULATION_STATE_SETTING |
/set_simulation_state |
| 26 | SIMULATION_STATE_PAUSE |
The state STATE_PAUSED. |
| 31 | STEP_SIMULATION_SINGLE |
/step_simulation with one step. |
| 32 | STEP_SIMULATION_MULTIPLE |
/step_simulation with more than one step. |
| 33 | STEP_SIMULATION_ACTION |
/simulate_steps |
ACRES does not have these parts of simulation_interfaces:
| Feature | Not Available |
|---|---|
Reset of the time (SIMULATION_RESET_TIME) |
The physics clock does not go back. A reset starts the episode time again. |
| Entity information, tags, categories and bounds | The services GetEntityInfo, SetEntityInfo, GetEntityBounds and GetEntitiesStates. The filters of /get_entities for categories, tags and bounds. |
| Bounds of named poses | The service GetNamedPoseBounds. |
| Spawn from a resource string | The field resource_string of /spawn_entity. ACRES has no spawn formats (spawn_formats is empty). |
| Spawn of more than one entity | The service SpawnEntities. |
| Worlds | The services LoadWorld, UnloadWorld, GetCurrentWorld and GetAvailableWorlds. |
The control channel has two operations without a ROS 2 service: get_vehicle_shifts and screenshot.
Refer to Simulator Control Channel.
Simulation State#
/get_simulator_features#
Type simulation_interfaces/srv/GetSimulatorFeatures. Gives the features of the simulator and data about the session.
The request has no fields.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
features.features |
integer list | The numbers of the table Supported Features. | ||
features.spawn_formats |
string list | empty | ACRES has no spawn formats. | |
features.custom_info |
string | The text ACRES and a JSON object. |
The JSON object of custom_info has the keys protocol, map, physics_hz, lockstep, headless, seed and episode_id.
Without a connection to the simulator, custom_info is ACRES: and the cause, and the feature list is empty.
/get_simulation_state#
Type simulation_interfaces/srv/GetSimulationState. Gives the state of the simulation. The request has no fields.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
state.state |
integer | 0 = stopped, 1 = playing, 2 = paused. | ||
result |
Result |
Code 1. |
/set_simulation_state#
Type simulation_interfaces/srv/SetSimulationState. Changes the state of the simulation.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
state.state |
integer | The new state. Refer to the table below. |
| State | Name | Effect |
|---|---|---|
| 0 | STATE_STOPPED |
A full reset. Then the world stops. |
| 1 | STATE_PLAYING |
The world advances in real time. |
| 2 | STATE_PAUSED |
The world stops. It advances only on step requests (lockstep). |
| 3 | STATE_QUITTING |
The simulator closes. |
| Code | Meaning |
|---|---|
| 1 | The state changed. |
| 3 | A step request is in progress. |
| 4 | The state is not one of 0, 1, 2 and 3. |
| 101 | ALREADY_IN_TARGET_STATE: the simulation was in this state. |
Each change of the state gives a new message on /sim/episode.
The same request a second time:
Lockstep#
/step_simulation#
Type simulation_interfaces/srv/StepSimulation. Advances the paused simulation by steps physics steps. One step is 1/120 s.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
steps |
integer | steps | 1 |
The number of physics steps. The minimum is 1. |
The service does these operations in this sequence:
- It sends the commands that the bridge received on the command topics to the simulator.
- It sends the step request and waits for the reply of the simulator.
- It waits until the bridge published all data of the steps. A barrier on each channel shows the end of the data.
The response thus arrives after the sensor data and the reports of the steps are on the topics. Lockstep Stepping gives the procedure for a control loop.
| Code | Meaning |
|---|---|
| 1 | The steps are complete and the data is on the topics. |
| 3 | The simulation is not in the paused state, or a different step request is in progress. |
| 4 | steps is less than 1, or a barrier did not arrive in barrier_timeout_s. The text names the channel. |
The time limit of the request is control_timeout_s plus 0.2 s for each step.
A request while the simulation plays:
/simulate_steps#
Type simulation_interfaces/action/SimulateSteps. Advances the paused simulation, with feedback.
The bridge sends the steps to the simulator in groups of 12 steps. A client can cancel the goal between two groups.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
Goal steps |
integer | steps | The number of physics steps. | |
Feedback completed_steps |
integer | steps | The steps that are complete. One message for each 12 steps. | |
Feedback remaining_steps |
integer | steps | The steps that remain. | |
Result result |
Result |
The code and the text. |
The bridge accepts one goal at a time. It rejects a second goal while the first is in progress.
| Status | Code | Meaning |
|---|---|---|
SUCCEEDED |
1 | All steps are complete and the data is on the topics. |
CANCELED |
1 | The client cancelled the goal. The text gives the number of complete steps. |
ABORTED |
3 or 4 | The simulator refused a group of steps, or a barrier did not arrive. |
from rclpy.action import ActionClient
from simulation_interfaces.action import SimulateSteps
client = ActionClient(node, SimulateSteps, "/simulate_steps")
client.wait_for_server(timeout_sec=10.0)
goal = client.send_goal_async(
SimulateSteps.Goal(steps=36),
feedback_callback=lambda m: print(m.feedback.completed_steps))
rclpy.spin_until_future_complete(node, goal)
result = goal.result().get_result_async()
rclpy.spin_until_future_complete(node, result)
print(result.result().result.result.result)
Reset#
/reset_simulation#
Type simulation_interfaces/srv/ResetSimulation. Starts a new episode. The episode number increases by 1.
The simulator sends a new message on /sim/episode.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
scope |
integer | 0 |
A bit field. Refer to the table below. |
| Scope | Name | Effect |
|---|---|---|
| 0 | SCOPE_DEFAULT |
The same as SCOPE_ALL. |
| 1 | SCOPE_TIME |
No effect on the physics clock. The response has the code 1 and a text about this. |
| 2 | SCOPE_STATE |
Each agent goes back to its spawn pose. |
| 4 | SCOPE_SPAWNED |
The simulator removes the spawned entities. |
| 255 | SCOPE_ALL |
All the above. The simulator also removes the marks and the crop damage from all fields. |
To move one vehicle and keep the episode, use the topic /sim/reset. Refer to Topics.
With scope: 0:
Entities#
An entity is an agent or an object that a client added with /spawn_entity. The name of an agent is its entity name.
The poses use the frame world: east, north and up in metres, with the origin at the centre of the tile.
A request can also use the frame utm (UTM zone 16N).
/get_entities#
Type simulation_interfaces/srv/GetEntities. Lists the names of the agents and of the spawned entities.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
filters.filter |
string | empty | A regular expression. The service returns the names that contain a match. | |
filters.categories, filters.tags, filters.bounds |
empty | Not available. A request with one of them gets the code 0. |
| Code | Meaning |
|---|---|
| 1 | The list entities is valid. |
| 0 | The request has a filter for categories, tags or bounds. |
| 4 | The regular expression is not valid. |
/get_entity_state#
Type simulation_interfaces/srv/GetEntityState. Gives the exact pose and twist of one entity.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
entity |
string | The name of the entity. |
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
state.header.frame_id |
string | world |
The frame of the pose and the twist. | |
state.header.stamp |
time | The simulation time of the state. | ||
state.pose |
pose | m | For a vehicle: the pose of base_footprint. |
|
state.twist.linear |
vector | m/s | The velocity in the world frame. |
|
state.twist.angular |
vector | rad/s | The angular rate in the world frame. |
|
state.acceleration |
accel | zero | ACRES does not fill this field. |
The code 2 shows that no entity has the name.
result=simulation_interfaces.msg.Result(result=1, error_message=''),
state=EntityState(
header=Header(stamp=Time(sec=154, nanosec=791674740), frame_id='world'),
pose=Pose(position=Point(x=-38.745806072951815, y=-121.47239796968378, z=0.24291916509505385),
orientation=Quaternion(x=-0.004382870625704527, y=0.0021762894466519356,
z=0.70587158203125, w=0.7083228826522827)),
twist=Twist(linear=Vector3(x=-5.597616545855999e-05, y=3.333876375108957e-06, z=-2.062867133645341e-07),
angular=Vector3(x=1.3538922871703107e-07, y=1.5225332390400581e-06, z=-2.5343013476231135e-05)),
acceleration=Accel(linear=Vector3(x=0.0, y=0.0, z=0.0), angular=Vector3(x=0.0, y=0.0, z=0.0)))
An unknown name:
/set_entity_state#
Type simulation_interfaces/srv/SetEntityState. Moves an entity to a pose.
A vehicle goes to the pose on the ground at the next physics step. The pose is that of base_footprint.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
entity |
string | The name of the entity. | ||
state.header.frame_id |
string | world |
utm or world. All other values mean world. |
|
state.pose.position |
point | m | The position. For a vehicle, the simulator ignores z. For an object, the game uses the given z. |
|
state.pose.orientation |
quaternion | The simulator uses only the yaw. | ||
state.twist.linear |
vector | m/s | zero | The simulator uses the size of x and y as the forward speed of a vehicle. |
The code 2 shows that no entity has the name.
from simulation_interfaces.srv import SetEntityState
request = SetEntityState.Request(entity="polaris")
request.state.header.frame_id = "world"
request.state.pose.position.x = -38.7
request.state.pose.position.y = -130.0
request.state.pose.orientation.z = 0.7071
request.state.pose.orientation.w = 0.7071
reply = call(SetEntityState, "/set_entity_state", request)
print(reply.result.result)
/spawn_entity#
Type simulation_interfaces/srv/SpawnEntity. Adds one object to the world. The field uri selects the object type from the list of /get_spawnables.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
name |
string | The name of the new entity. | ||
allow_renaming |
boolean | false |
When the name is empty or in use, the simulator makes a name: <name>_<number>. |
|
uri |
string | The object type, for example prop:cone. |
||
resource_string |
string | Not available. | ||
entity_namespace |
string | ACRES ignores this field. | ||
initial_pose |
pose with header | m | origin | The pose. The frame is utm or world. With z = 0, the object goes on the ground. |
The response has the field entity_name: the name that the simulator gave to the entity.
| Code | Name | Meaning |
|---|---|---|
| 1 | The entity is in the world. | |
| 4 | The spawn failed. A worker needs a game session with NPC workers or NPC vehicles. | |
| 101 | NAME_NOT_UNIQUE |
The name is in use and allow_renaming is false. |
| 102 | NAME_INVALID |
The name is empty and allow_renaming is false. |
| 103 | UNSUPPORTED_FORMAT |
The uri is not in the list, or the request uses resource_string. |
| 104 | NO_RESOURCE |
uri and resource_string are empty. |
| 107 | MISSING_ASSETS |
The mesh of the object is not in this build of the game. |
from simulation_interfaces.srv import SpawnEntity
request = SpawnEntity.Request(name="cone1", uri="prop:cone")
request.initial_pose.header.frame_id = "world"
request.initial_pose.pose.position.x = -38.7
request.initial_pose.pose.position.y = -120.0
reply = call(SpawnEntity, "/spawn_entity", request)
print(reply.result.result, reply.entity_name)
The same request a second time, and then with allow_renaming: true:
/delete_entity#
Type simulation_interfaces/srv/DeleteEntity. Removes an entity that a client spawned. A client cannot remove an agent.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
entity |
string | The name of the entity. |
| Code | Meaning |
|---|---|
| 1 | The simulator removed the entity. |
| 2 | No spawned entity has the name. |
| 4 | The name is that of an agent (game). ACRES Core returns the code 2 for an agent. |
/get_spawnables#
Type simulation_interfaces/srv/GetSpawnables. Lists the object types for /spawn_entity. ACRES ignores the request field sources.
uri |
Object |
|---|---|
prop:cone |
A traffic cone, 0.7 m high. |
prop:box |
A box of 1 m. |
prop:bale_round |
A round bale with a diameter of 1.5 m. |
prop:bale_square |
A square bale, 2.4 m by 1.2 m by 0.9 m. |
person |
A worker who stands. In the game, the session must have NPC workers or NPC vehicles. |
In ACRES Core, each object is a box that the LiDAR detects. The vehicle does not collide with it.
/get_named_poses#
Type simulation_interfaces/srv/GetNamedPoses. Lists the named places of the tile that are points, in the frame world.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
tags.tags |
string list | empty | The tags to find. Empty = all places. | |
tags.filter_mode |
integer | 0 |
0 = a place with one of the tags. 1 = a place with all tags. |
Each pose of the response has these fields:
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
name |
string | The identifier of the place, for example spawn-icsc-garage. |
||
description |
string | The name of the place for a person. | ||
tags |
string list | The category of the place, and heading when the place has a direction. |
||
pose |
pose | m | The pose in the frame world. A place without a direction points north. |
One pose of the response:
ACRES Services#
/acres/set_conditions#
Type acres_interfaces/srv/SetConditions. Sets the clock, the weather and the soil water, and removes the marks from fields.
The request has four parts. The simulator applies a part only when its flag is true.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
set_clock |
boolean | false |
Applies date and local_hour. |
|
date |
string | The local date, YYYY-MM-DD. |
||
local_hour |
number | h | The local time of day. | |
set_weather |
boolean | false |
Applies weather and rain_mm_h. |
|
weather |
string | clear, fair, overcast, rain, storm or fog. Empty = no change of the sky. |
||
rain_mm_h |
number | mm/h | The rain rate. A negative value = the rate of the preset. | |
set_soil_water |
boolean | false |
Applies soil_wetness to soil_fields. |
|
soil_wetness |
number | 0 = the wilting point, 1 = saturated. For the top layer of the soil. | ||
soil_fields |
integer list | all fields | The field numbers. | |
restore_fields |
boolean | false |
Removes the marks and the crop damage from fields. |
|
fields |
integer list | all fields | The field numbers. |
The response has the field message: a text with the parts that the simulator applied.
The code is 4 when one part failed. The other parts stay applied.
ACRES Core applies the soil water and the restore function. It records the clock and the weather, but they have no effect.
from acres_interfaces.srv import SetConditions
request = SetConditions.Request(
set_weather=True, weather="rain", rain_mm_h=4.0)
request.set_soil_water = True
request.soil_wetness = 0.8
request.soil_fields = [48]
reply = call(SetConditions, "/acres/set_conditions", request)
print(reply.result.result, reply.message)
/acres/set_vehicle_shift#
Type acres_interfaces/srv/SetVehicleShift. Sets the hardware shift of one agent.
A hardware shift is a set of offsets on the actuators and the sensor mounts. It makes a vehicle that differs from its calibration.
The request replaces the shift of the agent. A shift with all values at zero removes it.
The request has one field shift of the type acres_interfaces/msg/VehicleShift:
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
agent |
string | agent 0 | The name of the agent. | |
label |
string | A text for datasets, for example steer+3deg. |
||
steering_offset_deg |
number | deg | 0 |
Polaris: an offset of the steering wheel angle. Maxxum: an offset of the road wheel angle. |
ulc_speed_bias_mps |
number | m/s | 0 |
An offset of the speed that the ULC measures. |
throttle_bias_pct |
number | % | 0 |
An offset of the throttle output. |
brake_bias_bar |
number | bar | 0 |
An offset of the brake output. |
camera_offset_m |
vector | m | zero | An offset of the camera position, in base_footprint. |
camera_offset_rpy_deg |
vector | deg | zero | An offset of the camera roll, pitch and yaw. |
lidar_offset_m |
vector | m | zero | An offset of the LiDAR position. |
lidar_offset_rpy_deg |
vector | deg | zero | An offset of the LiDAR roll, pitch and yaw. |
The code 2 shows that no agent has the name. The episode log records each change on the channel /sim/shifts.
An unknown agent:
/acres/record#
Type acres_interfaces/srv/Record. Starts or stops the Episode Log.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
action |
integer | START = 1, STOP = 2. |
||
path |
path | session folder | START: the MCAP file, as an absolute path. Empty = a file episode-<number>.mcap in the session folder. |
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
path |
path | The file. | ||
messages |
integer | The number of messages in the file at this time. | ||
duration_s |
number | s | STOP: the simulation time of the recording. |
| Code | Meaning |
|---|---|
| 1 | The recording started or stopped. |
| 3 | START while a recording is in progress, or STOP without a recording. |
| 4 | action is not 1 or 2, or the simulator cannot write the file. |
from acres_interfaces.srv import Record
request = Record.Request(action=Record.Request.START,
path="/data/episode.mcap")
reply = call(Record, "/acres/record", request)
print(reply.result.result, reply.path)
reply = call(Record, "/acres/record",
Record.Request(action=Record.Request.STOP))
print(reply.messages, reply.duration_s)
/acres/farm_state#
Type acres_interfaces/srv/FarmState. Gives the ground truth of the fields for the score of a task: the crop damage, the field work and the soil water.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
edge_band_m |
number | m | 0 |
The width of the permitted band along the edge of each field. 0 = no band. |
fields |
integer list | fields with crop or marks | The field numbers, 1 to 59. |
The response has result, a header (frame world, simulation time), the totals crushed_m2 and harvested_kg of the farm, and the list fields.
Each element of fields has the type acres_interfaces/msg/FieldState:
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
field |
integer | The field number. | ||
name |
string | F01 to F59. |
||
crop |
string | corn, soybean, potato or empty. |
||
crop_area_m2 |
number | m² | The area of the crop of the field. | |
crushed_m2 |
number | m² | The crop that vehicles crushed. | |
crushed_in_band_m2 |
number | m² | The part of it in the permitted band. | |
crushed_out_band_m2 |
number | m² | The part of it farther in the field. | |
harvested_m2, tilled_m2, seeded_m2, sprayed_m2 |
number | m² | The areas of the field work. | |
theta_mean |
number | m³/m³ | The mean water content of the soil surface. -1 = no soil cells. | |
pond_mean_m |
number | m | The mean depth of the water on the surface. | |
rut_area_m2 |
number | m² | The area of the cells with a rut deeper than 1 cm. |
The code 4 shows that the session has no farm.
result=simulation_interfaces.msg.Result(result=1, error_message=''),
header=Header(stamp=Time(sec=176, nanosec=825009222), frame_id='world'),
fields=[FieldState(field=48, name='F48', crop='soybean', crop_area_m2=5098.080000000243,
crushed_m2=0.0, crushed_in_band_m2=0.0, crushed_out_band_m2=0.0, harvested_m2=0.0,
tilled_m2=0.0, seeded_m2=0.0, sprayed_m2=0.0, theta_mean=0.37230732510288195,
pond_mean_m=0.0, rut_area_m2=0.0)],
crushed_m2=0.0, harvested_kg=0.0
/acres/field_query#
Type acres_interfaces/srv/FieldQuery. Gives the ground truth at one point of the tile.
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
frame_id |
string | world |
world or utm. |
|
x, y |
number | m | East and north in world, or easting and northing in utm. |
| Name | Type | Unit | Default | Description |
|---|---|---|---|---|
field |
integer | The field number. 0 = not in a field. | ||
surface |
string | soil or hard. |
||
ground_z |
number | m | The height of the ground in the frame world. |
|
theta |
number | m³/m³ | The water content of the soil surface. -1 on a hard surface. | |
pond_m |
number | m | The depth of the water on the surface. | |
rut_m |
number | m | The depth of the rut. | |
worked |
integer | Bit flags: 1 = tilled, 2 = seeded, 4 = sprayed. | ||
crop |
string | The crop of the nearest patch in 1 m. Empty = no crop. | ||
crop_crushed |
number | The crushed part of that patch, 0 to 1. | ||
edge_distance_m |
number | m | The distance to the edge of the field. 0 = not in a field. |