carla-driver-interface 2.0.0__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/PKG-INFO +41 -1
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/README.md +40 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/pyproject.toml +1 -1
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/pyproject.toml.orig +1 -1
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/carla_driver_pb2.py +19 -11
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/carla_driver_pb2.pyi +25 -0
- carla_driver_interface-2.2.0/src/carla_driver_interface/_proto/carla_driver_pb2_grpc.py +85 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/cli.py +8 -2
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/driver.py +30 -0
- carla_driver_interface-2.2.0/src/carla_driver_interface/inprocess.py +709 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/protocol.py +9 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/server.py +38 -8
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/service.py +50 -2
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/testing.py +23 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/LICENSE +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/__init__.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/__init__.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/common_pb2.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/common_pb2.pyi +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/egodriver_pb2.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/egodriver_pb2.pyi +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/egodriver_pb2_grpc.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/sensorsim_pb2.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/_proto/sensorsim_pb2.pyi +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/alpasim.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/contract.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/geometry.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/hdmap.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/policies/__init__.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/policies/constant_speed.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/policies/route_follower.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/polyline.py +0 -0
- {carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carla-driver-interface
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Both ends of alpasim's egodriver gRPC contract: serve a driving policy, or drive one without CARLA
|
|
5
5
|
Author: Masaya Kataoka
|
|
6
6
|
Author-email: Masaya Kataoka <ms.kataoka@gmail.com>
|
|
@@ -76,6 +76,17 @@ world's map as files (`ctx.map`) and every traffic light resolved into that map'
|
|
|
76
76
|
elements (`ctx.stop_lines()`, `carla_driver_interface.hdmap`). CARLA ground truth arrives
|
|
77
77
|
in `ctx.renderer_data` (`None` when an alpasim runtime drives the policy).
|
|
78
78
|
|
|
79
|
+
A policy can also work the ego's turn indicators: `DriveResult(..., turn_indicator=TurnIndicator.ENABLE_LEFT)`
|
|
80
|
+
(`carla_driver_interface.driver.TurnIndicator`). The values are Autoware's
|
|
81
|
+
`TurnIndicatorsCommand` ones (`DISABLE` = 1, `ENABLE_LEFT` = 2, `ENABLE_RIGHT` = 3), so a
|
|
82
|
+
classifier over Autoware's recorded signal answers `TurnIndicator(class_index + 1)`. The
|
|
83
|
+
egodriver contract carries only the plan, so the server also serves
|
|
84
|
+
`carla_driver.v0.CarlaVehicleService` on the same port: after each drive a CARLA runtime
|
|
85
|
+
fetches the policy's `VehicleCommand` with `get_vehicle_command`. autoware_carla_scenario
|
|
86
|
+
lights the ego's indicators with it and holds them until a later step sets them again. The default,
|
|
87
|
+
`NO_COMMAND`, changes nothing -- what a policy that never sets it, or predates it, sends.
|
|
88
|
+
An upstream alpasim runtime has nowhere to show them.
|
|
89
|
+
|
|
79
90
|
A camera's mount is `session.cameras[logical_id].rig_to_camera`: the pose of its
|
|
80
91
|
**optical** frame in the rig (x right, y down, z along the optical axis), as alpasim's
|
|
81
92
|
renderers declare it, whichever runtime drives the policy. `geometry.optical_to_body`
|
|
@@ -93,6 +104,35 @@ or, in a test, `FakeLoop("localhost:50051", [FakeCamera()])` from
|
|
|
93
104
|
`LoopResult`). The ego follows the returned plan exactly, so what is tested is the policy
|
|
94
105
|
and the wire, not a controller.
|
|
95
106
|
|
|
107
|
+
## Serving on a Unix socket, or in the runtime's own process
|
|
108
|
+
|
|
109
|
+
A server binds a Unix domain socket when its host names one: `serve --host
|
|
110
|
+
unix:///run/policy.sock` (`build_server(policy, host="unix:///run/policy.sock")`; the
|
|
111
|
+
port is unused). A client dials the same address.
|
|
112
|
+
|
|
113
|
+
A runtime that runs the policy in its own process can skip the socket altogether:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from carla_driver_interface.inprocess import in_process_channel
|
|
117
|
+
from carla_driver_interface.protocol import EgodriverServiceStub
|
|
118
|
+
|
|
119
|
+
# A grpc.Channel; mode="alpasim", as on a server.
|
|
120
|
+
channel = in_process_channel(MyPolicy())
|
|
121
|
+
# The generated stubs, unchanged.
|
|
122
|
+
stub = EgodriverServiceStub(channel)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`InProcessChannel` keeps the contract byte for byte: each request is serialized and parsed
|
|
126
|
+
by the servicer's own deserializer, each response likewise, so both sides see the bytes
|
|
127
|
+
the wire would carry. The servicer is the same `EgodriverServicer`, with a context that
|
|
128
|
+
does what grpc's does (`abort`, `set_code`/`set_details`, an exception as `UNKNOWN`,
|
|
129
|
+
invocation, initial and trailing metadata -- the contract revision is negotiated through
|
|
130
|
+
them), and a failed call is a `grpc.RpcError` with the code and details a server's would
|
|
131
|
+
carry. The test suite runs every wire test over TCP, a Unix socket and this channel and
|
|
132
|
+
compares what the client sees, errors included. Only the socket's own behaviour is
|
|
133
|
+
missing: a call runs on the calling thread, so a deadline is reported, as
|
|
134
|
+
`DEADLINE_EXCEEDED`, when the call returns rather than cutting it short.
|
|
135
|
+
|
|
96
136
|
## Running a policy in alpasim
|
|
97
137
|
|
|
98
138
|
alpasim runs its driver as a container its wizard starts, and its runtime drives it over
|
|
@@ -60,6 +60,17 @@ world's map as files (`ctx.map`) and every traffic light resolved into that map'
|
|
|
60
60
|
elements (`ctx.stop_lines()`, `carla_driver_interface.hdmap`). CARLA ground truth arrives
|
|
61
61
|
in `ctx.renderer_data` (`None` when an alpasim runtime drives the policy).
|
|
62
62
|
|
|
63
|
+
A policy can also work the ego's turn indicators: `DriveResult(..., turn_indicator=TurnIndicator.ENABLE_LEFT)`
|
|
64
|
+
(`carla_driver_interface.driver.TurnIndicator`). The values are Autoware's
|
|
65
|
+
`TurnIndicatorsCommand` ones (`DISABLE` = 1, `ENABLE_LEFT` = 2, `ENABLE_RIGHT` = 3), so a
|
|
66
|
+
classifier over Autoware's recorded signal answers `TurnIndicator(class_index + 1)`. The
|
|
67
|
+
egodriver contract carries only the plan, so the server also serves
|
|
68
|
+
`carla_driver.v0.CarlaVehicleService` on the same port: after each drive a CARLA runtime
|
|
69
|
+
fetches the policy's `VehicleCommand` with `get_vehicle_command`. autoware_carla_scenario
|
|
70
|
+
lights the ego's indicators with it and holds them until a later step sets them again. The default,
|
|
71
|
+
`NO_COMMAND`, changes nothing -- what a policy that never sets it, or predates it, sends.
|
|
72
|
+
An upstream alpasim runtime has nowhere to show them.
|
|
73
|
+
|
|
63
74
|
A camera's mount is `session.cameras[logical_id].rig_to_camera`: the pose of its
|
|
64
75
|
**optical** frame in the rig (x right, y down, z along the optical axis), as alpasim's
|
|
65
76
|
renderers declare it, whichever runtime drives the policy. `geometry.optical_to_body`
|
|
@@ -77,6 +88,35 @@ or, in a test, `FakeLoop("localhost:50051", [FakeCamera()])` from
|
|
|
77
88
|
`LoopResult`). The ego follows the returned plan exactly, so what is tested is the policy
|
|
78
89
|
and the wire, not a controller.
|
|
79
90
|
|
|
91
|
+
## Serving on a Unix socket, or in the runtime's own process
|
|
92
|
+
|
|
93
|
+
A server binds a Unix domain socket when its host names one: `serve --host
|
|
94
|
+
unix:///run/policy.sock` (`build_server(policy, host="unix:///run/policy.sock")`; the
|
|
95
|
+
port is unused). A client dials the same address.
|
|
96
|
+
|
|
97
|
+
A runtime that runs the policy in its own process can skip the socket altogether:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from carla_driver_interface.inprocess import in_process_channel
|
|
101
|
+
from carla_driver_interface.protocol import EgodriverServiceStub
|
|
102
|
+
|
|
103
|
+
# A grpc.Channel; mode="alpasim", as on a server.
|
|
104
|
+
channel = in_process_channel(MyPolicy())
|
|
105
|
+
# The generated stubs, unchanged.
|
|
106
|
+
stub = EgodriverServiceStub(channel)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`InProcessChannel` keeps the contract byte for byte: each request is serialized and parsed
|
|
110
|
+
by the servicer's own deserializer, each response likewise, so both sides see the bytes
|
|
111
|
+
the wire would carry. The servicer is the same `EgodriverServicer`, with a context that
|
|
112
|
+
does what grpc's does (`abort`, `set_code`/`set_details`, an exception as `UNKNOWN`,
|
|
113
|
+
invocation, initial and trailing metadata -- the contract revision is negotiated through
|
|
114
|
+
them), and a failed call is a `grpc.RpcError` with the code and details a server's would
|
|
115
|
+
carry. The test suite runs every wire test over TCP, a Unix socket and this channel and
|
|
116
|
+
compares what the client sees, errors included. Only the socket's own behaviour is
|
|
117
|
+
missing: a call runs on the calling thread, so a deadline is reported, as
|
|
118
|
+
`DEADLINE_EXCEEDED`, when the call returns rather than cutting it short.
|
|
119
|
+
|
|
80
120
|
## Running a policy in alpasim
|
|
81
121
|
|
|
82
122
|
alpasim runs its driver as a container its wizard starts, and its runtime drives it over
|
|
@@ -23,7 +23,7 @@ from . import egodriver_pb2 as alpasim__grpc_dot_v0_dot_egodriver__pb2
|
|
|
23
23
|
from . import sensorsim_pb2 as alpasim__grpc_dot_v0_dot_sensorsim__pb2
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"carla_driver/v0/carla_driver.proto\x12\x0f\x63\x61rla_driver.v0\x1a\x1c\x61lpasim_grpc/v0/common.proto\x1a\x1f\x61lpasim_grpc/v0/egodriver.proto\x1a\x1f\x61lpasim_grpc/v0/sensorsim.proto\"\xce\x01\n\x0c\x43\x61rlaWeather\x12\x12\n\ncloudiness\x18\x01 \x01(\x02\x12\x15\n\rprecipitation\x18\x02 \x01(\x02\x12\x1e\n\x16precipitation_deposits\x18\x03 \x01(\x02\x12\x16\n\x0ewind_intensity\x18\x04 \x01(\x02\x12\x19\n\x11sun_azimuth_angle\x18\x05 \x01(\x02\x12\x1a\n\x12sun_altitude_angle\x18\x06 \x01(\x02\x12\x13\n\x0b\x66og_density\x18\x07 \x01(\x02\x12\x0f\n\x07wetness\x18\x08 \x01(\x02\"\xa7\x01\n\x0f\x43\x61rlaActorState\x12\x10\n\x08track_id\x18\x01 \x01(\t\x12\x0f\n\x07type_id\x18\x02 \x01(\t\x12(\n\x12pose_local_to_aabb\x18\x03 \x01(\x0b\x32\x0c.common.Pose\x12\x1a\n\x04\x61\x61\x62\x62\x18\x04 \x01(\x0b\x32\x0c.common.AABB\x12+\n\rdynamic_state\x18\x05 \x01(\x0b\x32\x14.common.DynamicState\"\xb6\x03\n\x11\x43\x61rlaRendererData\x12\x1d\n\x15snapshot_timestamp_us\x18\x01 \x01(\x06\x12\x10\n\x08\x66rame_id\x18\x02 \x01(\x04\x12\x10\n\x08map_name\x18\x03 \x01(\t\x12.\n\x07weather\x18\x04 \x01(\x0b\x32\x1d.carla_driver.v0.CarlaWeather\x12=\n\x11\x65go_traffic_light\x18\x05 \x01(\x0e\x32\".carla_driver.v0.TrafficLightState\x12$\n\x1c\x65go_traffic_light_distance_m\x18\x06 \x01(\x02\x12\x17\n\x0fspeed_limit_mps\x18\x07 \x01(\x02\x12\x30\n\x06\x61\x63tors\x18\x08 \x03(\x0b\x32 .carla_driver.v0.CarlaActorState\x12*\n\x05lidar\x18\n \x03(\x0b\x32\x1b.carla_driver.v0.LidarSweep\x12\x0e\n\x06map_id\x18\x0b \x01(\t\x12\x35\n\x0etraffic_lights\x18\x0c \x03(\x0b\x32\x1d.carla_driver.v0.TrafficLightJ\x04\x08\t\x10\nR\x05lanes\"\x88\x01\n\x0cTrafficLight\x12\x14\n\x0copendrive_id\x18\x01 \x01(\t\x12\x31\n\x05state\x18\x02 \x01(\x0e\x32\".carla_driver.v0.TrafficLightState\x12/\n\x0bstop_points\x18\x03 \x03(\x0b\x32\x1a.carla_driver.v0.StopPoint\"g\n\tStopPoint\x12\x0f\n\x07road_id\x18\x01 \x01(\x05\x12\x12\n\nsection_id\x18\x02 \x01(\x05\x12\x0f\n\x07lane_id\x18\x03 \x01(\x05\x12$\n\x0eposition_local\x18\x04 \x01(\x0b\x32\x0c.common.Vec3\"\x83\x01\n\nLidarSweep\x12\x12\n\nlogical_id\x18\x01 \x01(\t\x12\x14\n\x0ctimestamp_us\x18\x02 \x01(\x06\x12\"\n\x0crig_to_lidar\x18\x03 \x01(\x0b\x32\x0c.common.Pose\x12\x12\n\nnum_points\x18\x04 \x01(\r\x12\x13\n\x0bpoints_xyzi\x18\x05 \x01(\x0c\"\xb9\x01\n\x13\x43\x61rlaDriveDebugInfo\x12\x13\n\x0bpolicy_name\x18\x01 \x01(\t\x12\x19\n\x11inference_seconds\x18\x02 \x01(\x02\x12\x42\n\x07scalars\x18\x03 \x03(\x0b\x32\x31.carla_driver.v0.CarlaDriveDebugInfo.ScalarsEntry\x1a.\n\x0cScalarsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01:\x02\x38\x01\"\x92\x02\n\x15\x43\x61rlaDriveSessionInfo\x12,\n\x04\x62\x61se\x18\x01 \x01(\x0b\x32\x1e.egodriver.DriveSessionRequest\x12\x10\n\x08map_name\x18\x02 \x01(\t\x12\x15\n\rscenario_name\x18\x03 \x01(\t\x12\x16\n\x0e\x66ixed_delta_us\x18\x04 \x01(\x06\x12\x1a\n\x12policy_timestep_us\x18\x05 \x01(\x06\x12\x1a\n\x12rear_axle_offset_m\x18\x06 \x01(\x02\x12R\n\x07\x63\x61meras\x18\x07 \x03(\x0b\x32\x41.nre.grpc.protos.sensorsim.AvailableCamerasReturn.AvailableCamera\"\x8d\x01\n\x0b\x43ompatEntry\x12\x0c\n\x04\x61rea\x18\x01 \x01(\t\x12\x19\n\x11\x61lpasim_behaviour\x18\x02 \x01(\t\x12\x17\n\x0f\x63\x61rla_behaviour\x18\x03 \x01(\t\x12+\n\x05level\x18\x04 \x01(\x0e\x32\x1c.carla_driver.v0.CompatLevel\x12\x0f\n\x07symbols\x18\x05 \x03(\t\"\xc4\x01\n\x11\x43\x61rlaCompatReport\x12&\n\x1e\x63\x61rla_driver_interface_version\x18\x01 \x01(\t\x12\x18\n\x10\x61lpasim_grpc_rev\x18\x02 \x01(\t\x12>\n\x18\x61lpasim_grpc_api_version\x18\x03 \x01(\x0b\x32\x1c.common.VersionId.APIVersion\x12-\n\x07\x65ntries\x18\x04 \x03(\x0b\x32\x1c.carla_driver.v0.CompatEntry*\xcb\x01\n\x11TrafficLightState\x12\x1f\n\x1bTRAFFIC_LIGHT_STATE_UNKNOWN\x10\x00\x12\x1c\n\x18TRAFFIC_LIGHT_STATE_NONE\x10\x01\x12\x1b\n\x17TRAFFIC_LIGHT_STATE_RED\x10\x02\x12\x1e\n\x1aTRAFFIC_LIGHT_STATE_YELLOW\x10\x03\x12\x1d\n\x19TRAFFIC_LIGHT_STATE_GREEN\x10\x04\x12\x1b\n\x17TRAFFIC_LIGHT_STATE_OFF\x10\x05*\xb6\x01\n\x0b\x43ompatLevel\x12\x1c\n\x18\x43OMPAT_LEVEL_UNSPECIFIED\x10\x00\x12\x16\n\x12\x43OMPAT_LEVEL_EXACT\x10\x01\x12\x18\n\x14\x43OMPAT_LEVEL_PARTIAL\x10\x02\x12\x1b\n\x17\x43OMPAT_LEVEL_STRUCTURAL\x10\x03\x12\x1e\n\x1a\x43OMPAT_LEVEL_UNIMPLEMENTED\x10\x04\x12\x1a\n\x16\x43OMPAT_LEVEL_EXTENSION\x10\x05\
|
|
26
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"carla_driver/v0/carla_driver.proto\x12\x0f\x63\x61rla_driver.v0\x1a\x1c\x61lpasim_grpc/v0/common.proto\x1a\x1f\x61lpasim_grpc/v0/egodriver.proto\x1a\x1f\x61lpasim_grpc/v0/sensorsim.proto\"\xce\x01\n\x0c\x43\x61rlaWeather\x12\x12\n\ncloudiness\x18\x01 \x01(\x02\x12\x15\n\rprecipitation\x18\x02 \x01(\x02\x12\x1e\n\x16precipitation_deposits\x18\x03 \x01(\x02\x12\x16\n\x0ewind_intensity\x18\x04 \x01(\x02\x12\x19\n\x11sun_azimuth_angle\x18\x05 \x01(\x02\x12\x1a\n\x12sun_altitude_angle\x18\x06 \x01(\x02\x12\x13\n\x0b\x66og_density\x18\x07 \x01(\x02\x12\x0f\n\x07wetness\x18\x08 \x01(\x02\"\xa7\x01\n\x0f\x43\x61rlaActorState\x12\x10\n\x08track_id\x18\x01 \x01(\t\x12\x0f\n\x07type_id\x18\x02 \x01(\t\x12(\n\x12pose_local_to_aabb\x18\x03 \x01(\x0b\x32\x0c.common.Pose\x12\x1a\n\x04\x61\x61\x62\x62\x18\x04 \x01(\x0b\x32\x0c.common.AABB\x12+\n\rdynamic_state\x18\x05 \x01(\x0b\x32\x14.common.DynamicState\"\xb6\x03\n\x11\x43\x61rlaRendererData\x12\x1d\n\x15snapshot_timestamp_us\x18\x01 \x01(\x06\x12\x10\n\x08\x66rame_id\x18\x02 \x01(\x04\x12\x10\n\x08map_name\x18\x03 \x01(\t\x12.\n\x07weather\x18\x04 \x01(\x0b\x32\x1d.carla_driver.v0.CarlaWeather\x12=\n\x11\x65go_traffic_light\x18\x05 \x01(\x0e\x32\".carla_driver.v0.TrafficLightState\x12$\n\x1c\x65go_traffic_light_distance_m\x18\x06 \x01(\x02\x12\x17\n\x0fspeed_limit_mps\x18\x07 \x01(\x02\x12\x30\n\x06\x61\x63tors\x18\x08 \x03(\x0b\x32 .carla_driver.v0.CarlaActorState\x12*\n\x05lidar\x18\n \x03(\x0b\x32\x1b.carla_driver.v0.LidarSweep\x12\x0e\n\x06map_id\x18\x0b \x01(\t\x12\x35\n\x0etraffic_lights\x18\x0c \x03(\x0b\x32\x1d.carla_driver.v0.TrafficLightJ\x04\x08\t\x10\nR\x05lanes\"\x88\x01\n\x0cTrafficLight\x12\x14\n\x0copendrive_id\x18\x01 \x01(\t\x12\x31\n\x05state\x18\x02 \x01(\x0e\x32\".carla_driver.v0.TrafficLightState\x12/\n\x0bstop_points\x18\x03 \x03(\x0b\x32\x1a.carla_driver.v0.StopPoint\"g\n\tStopPoint\x12\x0f\n\x07road_id\x18\x01 \x01(\x05\x12\x12\n\nsection_id\x18\x02 \x01(\x05\x12\x0f\n\x07lane_id\x18\x03 \x01(\x05\x12$\n\x0eposition_local\x18\x04 \x01(\x0b\x32\x0c.common.Vec3\"\x83\x01\n\nLidarSweep\x12\x12\n\nlogical_id\x18\x01 \x01(\t\x12\x14\n\x0ctimestamp_us\x18\x02 \x01(\x06\x12\"\n\x0crig_to_lidar\x18\x03 \x01(\x0b\x32\x0c.common.Pose\x12\x12\n\nnum_points\x18\x04 \x01(\r\x12\x13\n\x0bpoints_xyzi\x18\x05 \x01(\x0c\"\xb9\x01\n\x13\x43\x61rlaDriveDebugInfo\x12\x13\n\x0bpolicy_name\x18\x01 \x01(\t\x12\x19\n\x11inference_seconds\x18\x02 \x01(\x02\x12\x42\n\x07scalars\x18\x03 \x03(\x0b\x32\x31.carla_driver.v0.CarlaDriveDebugInfo.ScalarsEntry\x1a.\n\x0cScalarsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01:\x02\x38\x01\"]\n\x0eVehicleCommand\x12\x13\n\x0btime_now_us\x18\x01 \x01(\x06\x12\x36\n\x0eturn_indicator\x18\x02 \x01(\x0e\x32\x1e.carla_driver.v0.TurnIndicator\"-\n\x15VehicleCommandRequest\x12\x14\n\x0csession_uuid\x18\x01 \x01(\t\"\x92\x02\n\x15\x43\x61rlaDriveSessionInfo\x12,\n\x04\x62\x61se\x18\x01 \x01(\x0b\x32\x1e.egodriver.DriveSessionRequest\x12\x10\n\x08map_name\x18\x02 \x01(\t\x12\x15\n\rscenario_name\x18\x03 \x01(\t\x12\x16\n\x0e\x66ixed_delta_us\x18\x04 \x01(\x06\x12\x1a\n\x12policy_timestep_us\x18\x05 \x01(\x06\x12\x1a\n\x12rear_axle_offset_m\x18\x06 \x01(\x02\x12R\n\x07\x63\x61meras\x18\x07 \x03(\x0b\x32\x41.nre.grpc.protos.sensorsim.AvailableCamerasReturn.AvailableCamera\"\x8d\x01\n\x0b\x43ompatEntry\x12\x0c\n\x04\x61rea\x18\x01 \x01(\t\x12\x19\n\x11\x61lpasim_behaviour\x18\x02 \x01(\t\x12\x17\n\x0f\x63\x61rla_behaviour\x18\x03 \x01(\t\x12+\n\x05level\x18\x04 \x01(\x0e\x32\x1c.carla_driver.v0.CompatLevel\x12\x0f\n\x07symbols\x18\x05 \x03(\t\"\xc4\x01\n\x11\x43\x61rlaCompatReport\x12&\n\x1e\x63\x61rla_driver_interface_version\x18\x01 \x01(\t\x12\x18\n\x10\x61lpasim_grpc_rev\x18\x02 \x01(\t\x12>\n\x18\x61lpasim_grpc_api_version\x18\x03 \x01(\x0b\x32\x1c.common.VersionId.APIVersion\x12-\n\x07\x65ntries\x18\x04 \x03(\x0b\x32\x1c.carla_driver.v0.CompatEntry*\xcb\x01\n\x11TrafficLightState\x12\x1f\n\x1bTRAFFIC_LIGHT_STATE_UNKNOWN\x10\x00\x12\x1c\n\x18TRAFFIC_LIGHT_STATE_NONE\x10\x01\x12\x1b\n\x17TRAFFIC_LIGHT_STATE_RED\x10\x02\x12\x1e\n\x1aTRAFFIC_LIGHT_STATE_YELLOW\x10\x03\x12\x1d\n\x19TRAFFIC_LIGHT_STATE_GREEN\x10\x04\x12\x1b\n\x17TRAFFIC_LIGHT_STATE_OFF\x10\x05*\x8b\x01\n\rTurnIndicator\x12\x1d\n\x19TURN_INDICATOR_NO_COMMAND\x10\x00\x12\x1a\n\x16TURN_INDICATOR_DISABLE\x10\x01\x12\x1e\n\x1aTURN_INDICATOR_ENABLE_LEFT\x10\x02\x12\x1f\n\x1bTURN_INDICATOR_ENABLE_RIGHT\x10\x03*\xb6\x01\n\x0b\x43ompatLevel\x12\x1c\n\x18\x43OMPAT_LEVEL_UNSPECIFIED\x10\x00\x12\x16\n\x12\x43OMPAT_LEVEL_EXACT\x10\x01\x12\x18\n\x14\x43OMPAT_LEVEL_PARTIAL\x10\x02\x12\x1b\n\x17\x43OMPAT_LEVEL_STRUCTURAL\x10\x03\x12\x1e\n\x1a\x43OMPAT_LEVEL_UNIMPLEMENTED\x10\x04\x12\x1a\n\x16\x43OMPAT_LEVEL_EXTENSION\x10\x05\x32u\n\x13\x43\x61rlaVehicleService\x12^\n\x13get_vehicle_command\x12&.carla_driver.v0.VehicleCommandRequest\x1a\x1f.carla_driver.v0.VehicleCommandb\x06proto3')
|
|
27
27
|
|
|
28
28
|
_globals = globals()
|
|
29
29
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -32,10 +32,12 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
32
32
|
DESCRIPTOR._options = None
|
|
33
33
|
_globals['_CARLADRIVEDEBUGINFO_SCALARSENTRY']._options = None
|
|
34
34
|
_globals['_CARLADRIVEDEBUGINFO_SCALARSENTRY']._serialized_options = b'8\001'
|
|
35
|
-
_globals['_TRAFFICLIGHTSTATE']._serialized_start=
|
|
36
|
-
_globals['_TRAFFICLIGHTSTATE']._serialized_end=
|
|
37
|
-
_globals['
|
|
38
|
-
_globals['
|
|
35
|
+
_globals['_TRAFFICLIGHTSTATE']._serialized_start=2300
|
|
36
|
+
_globals['_TRAFFICLIGHTSTATE']._serialized_end=2503
|
|
37
|
+
_globals['_TURNINDICATOR']._serialized_start=2506
|
|
38
|
+
_globals['_TURNINDICATOR']._serialized_end=2645
|
|
39
|
+
_globals['_COMPATLEVEL']._serialized_start=2648
|
|
40
|
+
_globals['_COMPATLEVEL']._serialized_end=2830
|
|
39
41
|
_globals['_CARLAWEATHER']._serialized_start=152
|
|
40
42
|
_globals['_CARLAWEATHER']._serialized_end=358
|
|
41
43
|
_globals['_CARLAACTORSTATE']._serialized_start=361
|
|
@@ -52,10 +54,16 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
52
54
|
_globals['_CARLADRIVEDEBUGINFO']._serialized_end=1535
|
|
53
55
|
_globals['_CARLADRIVEDEBUGINFO_SCALARSENTRY']._serialized_start=1489
|
|
54
56
|
_globals['_CARLADRIVEDEBUGINFO_SCALARSENTRY']._serialized_end=1535
|
|
55
|
-
_globals['
|
|
56
|
-
_globals['
|
|
57
|
-
_globals['
|
|
58
|
-
_globals['
|
|
59
|
-
_globals['
|
|
60
|
-
_globals['
|
|
57
|
+
_globals['_VEHICLECOMMAND']._serialized_start=1537
|
|
58
|
+
_globals['_VEHICLECOMMAND']._serialized_end=1630
|
|
59
|
+
_globals['_VEHICLECOMMANDREQUEST']._serialized_start=1632
|
|
60
|
+
_globals['_VEHICLECOMMANDREQUEST']._serialized_end=1677
|
|
61
|
+
_globals['_CARLADRIVESESSIONINFO']._serialized_start=1680
|
|
62
|
+
_globals['_CARLADRIVESESSIONINFO']._serialized_end=1954
|
|
63
|
+
_globals['_COMPATENTRY']._serialized_start=1957
|
|
64
|
+
_globals['_COMPATENTRY']._serialized_end=2098
|
|
65
|
+
_globals['_CARLACOMPATREPORT']._serialized_start=2101
|
|
66
|
+
_globals['_CARLACOMPATREPORT']._serialized_end=2297
|
|
67
|
+
_globals['_CARLAVEHICLESERVICE']._serialized_start=2832
|
|
68
|
+
_globals['_CARLAVEHICLESERVICE']._serialized_end=2949
|
|
61
69
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -24,6 +24,13 @@ class TrafficLightState(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
|
24
24
|
TRAFFIC_LIGHT_STATE_GREEN: _ClassVar[TrafficLightState]
|
|
25
25
|
TRAFFIC_LIGHT_STATE_OFF: _ClassVar[TrafficLightState]
|
|
26
26
|
|
|
27
|
+
class TurnIndicator(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
28
|
+
__slots__ = ()
|
|
29
|
+
TURN_INDICATOR_NO_COMMAND: _ClassVar[TurnIndicator]
|
|
30
|
+
TURN_INDICATOR_DISABLE: _ClassVar[TurnIndicator]
|
|
31
|
+
TURN_INDICATOR_ENABLE_LEFT: _ClassVar[TurnIndicator]
|
|
32
|
+
TURN_INDICATOR_ENABLE_RIGHT: _ClassVar[TurnIndicator]
|
|
33
|
+
|
|
27
34
|
class CompatLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
28
35
|
__slots__ = ()
|
|
29
36
|
COMPAT_LEVEL_UNSPECIFIED: _ClassVar[CompatLevel]
|
|
@@ -38,6 +45,10 @@ TRAFFIC_LIGHT_STATE_RED: TrafficLightState
|
|
|
38
45
|
TRAFFIC_LIGHT_STATE_YELLOW: TrafficLightState
|
|
39
46
|
TRAFFIC_LIGHT_STATE_GREEN: TrafficLightState
|
|
40
47
|
TRAFFIC_LIGHT_STATE_OFF: TrafficLightState
|
|
48
|
+
TURN_INDICATOR_NO_COMMAND: TurnIndicator
|
|
49
|
+
TURN_INDICATOR_DISABLE: TurnIndicator
|
|
50
|
+
TURN_INDICATOR_ENABLE_LEFT: TurnIndicator
|
|
51
|
+
TURN_INDICATOR_ENABLE_RIGHT: TurnIndicator
|
|
41
52
|
COMPAT_LEVEL_UNSPECIFIED: CompatLevel
|
|
42
53
|
COMPAT_LEVEL_EXACT: CompatLevel
|
|
43
54
|
COMPAT_LEVEL_PARTIAL: CompatLevel
|
|
@@ -158,6 +169,20 @@ class CarlaDriveDebugInfo(_message.Message):
|
|
|
158
169
|
scalars: _containers.ScalarMap[str, float]
|
|
159
170
|
def __init__(self, policy_name: _Optional[str] = ..., inference_seconds: _Optional[float] = ..., scalars: _Optional[_Mapping[str, float]] = ...) -> None: ...
|
|
160
171
|
|
|
172
|
+
class VehicleCommand(_message.Message):
|
|
173
|
+
__slots__ = ("time_now_us", "turn_indicator")
|
|
174
|
+
TIME_NOW_US_FIELD_NUMBER: _ClassVar[int]
|
|
175
|
+
TURN_INDICATOR_FIELD_NUMBER: _ClassVar[int]
|
|
176
|
+
time_now_us: int
|
|
177
|
+
turn_indicator: TurnIndicator
|
|
178
|
+
def __init__(self, time_now_us: _Optional[int] = ..., turn_indicator: _Optional[_Union[TurnIndicator, str]] = ...) -> None: ...
|
|
179
|
+
|
|
180
|
+
class VehicleCommandRequest(_message.Message):
|
|
181
|
+
__slots__ = ("session_uuid",)
|
|
182
|
+
SESSION_UUID_FIELD_NUMBER: _ClassVar[int]
|
|
183
|
+
session_uuid: str
|
|
184
|
+
def __init__(self, session_uuid: _Optional[str] = ...) -> None: ...
|
|
185
|
+
|
|
161
186
|
class CarlaDriveSessionInfo(_message.Message):
|
|
162
187
|
__slots__ = ("base", "map_name", "scenario_name", "fixed_delta_us", "policy_timestep_us", "rear_axle_offset_m", "cameras")
|
|
163
188
|
BASE_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Generated by scripts/compile_protos.py -- do not edit.
|
|
2
|
+
#
|
|
3
|
+
# Sources: NVlabs/alpasim@6870924 and
|
|
4
|
+
# hakuturu583/carla_driver_interface@af1dcd3 (both Apache-2.0)
|
|
5
|
+
# Regenerate with: uv run python scripts/compile_protos.py
|
|
6
|
+
|
|
7
|
+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
|
8
|
+
"""Client and server classes corresponding to protobuf-defined services."""
|
|
9
|
+
import grpc
|
|
10
|
+
|
|
11
|
+
from . import carla_driver_pb2 as carla__driver_dot_v0_dot_carla__driver__pb2
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CarlaVehicleServiceStub(object):
|
|
15
|
+
"""Served beside `egodriver.EgodriverService`, on the same port. A runtime
|
|
16
|
+
that never calls it loses nothing but the command; a policy server that
|
|
17
|
+
does not serve it (carla-driver-interface < 2.1) answers UNIMPLEMENTED,
|
|
18
|
+
which a runtime reads as "no command".
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, channel):
|
|
22
|
+
"""Constructor.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
channel: A grpc.Channel.
|
|
26
|
+
"""
|
|
27
|
+
self.get_vehicle_command = channel.unary_unary(
|
|
28
|
+
'/carla_driver.v0.CarlaVehicleService/get_vehicle_command',
|
|
29
|
+
request_serializer=carla__driver_dot_v0_dot_carla__driver__pb2.VehicleCommandRequest.SerializeToString,
|
|
30
|
+
response_deserializer=carla__driver_dot_v0_dot_carla__driver__pb2.VehicleCommand.FromString,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CarlaVehicleServiceServicer(object):
|
|
35
|
+
"""Served beside `egodriver.EgodriverService`, on the same port. A runtime
|
|
36
|
+
that never calls it loses nothing but the command; a policy server that
|
|
37
|
+
does not serve it (carla-driver-interface < 2.1) answers UNIMPLEMENTED,
|
|
38
|
+
which a runtime reads as "no command".
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def get_vehicle_command(self, request, context):
|
|
42
|
+
"""The command the policy decided with its latest drive in the session.
|
|
43
|
+
"""
|
|
44
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
45
|
+
context.set_details('Method not implemented!')
|
|
46
|
+
raise NotImplementedError('Method not implemented!')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def add_CarlaVehicleServiceServicer_to_server(servicer, server):
|
|
50
|
+
rpc_method_handlers = {
|
|
51
|
+
'get_vehicle_command': grpc.unary_unary_rpc_method_handler(
|
|
52
|
+
servicer.get_vehicle_command,
|
|
53
|
+
request_deserializer=carla__driver_dot_v0_dot_carla__driver__pb2.VehicleCommandRequest.FromString,
|
|
54
|
+
response_serializer=carla__driver_dot_v0_dot_carla__driver__pb2.VehicleCommand.SerializeToString,
|
|
55
|
+
),
|
|
56
|
+
}
|
|
57
|
+
generic_handler = grpc.method_handlers_generic_handler(
|
|
58
|
+
'carla_driver.v0.CarlaVehicleService', rpc_method_handlers)
|
|
59
|
+
server.add_generic_rpc_handlers((generic_handler,))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# This class is part of an EXPERIMENTAL API.
|
|
63
|
+
class CarlaVehicleService(object):
|
|
64
|
+
"""Served beside `egodriver.EgodriverService`, on the same port. A runtime
|
|
65
|
+
that never calls it loses nothing but the command; a policy server that
|
|
66
|
+
does not serve it (carla-driver-interface < 2.1) answers UNIMPLEMENTED,
|
|
67
|
+
which a runtime reads as "no command".
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def get_vehicle_command(request,
|
|
72
|
+
target,
|
|
73
|
+
options=(),
|
|
74
|
+
channel_credentials=None,
|
|
75
|
+
call_credentials=None,
|
|
76
|
+
insecure=False,
|
|
77
|
+
compression=None,
|
|
78
|
+
wait_for_ready=None,
|
|
79
|
+
timeout=None,
|
|
80
|
+
metadata=None):
|
|
81
|
+
return grpc.experimental.unary_unary(request, target, '/carla_driver.v0.CarlaVehicleService/get_vehicle_command',
|
|
82
|
+
carla__driver_dot_v0_dot_carla__driver__pb2.VehicleCommandRequest.SerializeToString,
|
|
83
|
+
carla__driver_dot_v0_dot_carla__driver__pb2.VehicleCommand.FromString,
|
|
84
|
+
options, channel_credentials,
|
|
85
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
{carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/cli.py
RENAMED
|
@@ -56,7 +56,11 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
56
56
|
|
|
57
57
|
serve = commands.add_parser("serve", help="serve a policy over gRPC")
|
|
58
58
|
_add_policy_arguments(serve, os.environ.get(POLICY_ENV, "route_follower"))
|
|
59
|
-
serve.add_argument(
|
|
59
|
+
serve.add_argument(
|
|
60
|
+
"--host",
|
|
61
|
+
default="0.0.0.0",
|
|
62
|
+
help="address to bind, or a Unix socket (unix:///path/policy.sock; --port unused)",
|
|
63
|
+
)
|
|
60
64
|
serve.add_argument("--port", type=int, default=50051)
|
|
61
65
|
serve.add_argument("--cruise-speed", type=float, default=None, help="m/s")
|
|
62
66
|
serve.add_argument(
|
|
@@ -76,7 +80,9 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
76
80
|
demo = commands.add_parser(
|
|
77
81
|
"demo", help="drive a policy server through the CARLA-free fake loop"
|
|
78
82
|
)
|
|
79
|
-
demo.add_argument(
|
|
83
|
+
demo.add_argument(
|
|
84
|
+
"--driver", default="localhost:50051", help="policy host:port, or unix:///path"
|
|
85
|
+
)
|
|
80
86
|
demo.add_argument("--steps", type=int, default=100)
|
|
81
87
|
demo.add_argument("--step", type=float, default=0.1, help="seconds per drive call")
|
|
82
88
|
demo.add_argument("--camera-width", type=int, default=FakeCamera.width)
|
{carla_driver_interface-2.0.0 → carla_driver_interface-2.2.0}/src/carla_driver_interface/driver.py
RENAMED
|
@@ -23,6 +23,7 @@ import io
|
|
|
23
23
|
import threading
|
|
24
24
|
from abc import ABC, abstractmethod
|
|
25
25
|
from dataclasses import dataclass, field
|
|
26
|
+
from enum import IntEnum
|
|
26
27
|
from typing import Dict, List, Optional, Union
|
|
27
28
|
|
|
28
29
|
import numpy as np
|
|
@@ -46,6 +47,7 @@ __all__ = [
|
|
|
46
47
|
"LidarFrame",
|
|
47
48
|
"SensorFrame",
|
|
48
49
|
"SessionState",
|
|
50
|
+
"TurnIndicator",
|
|
49
51
|
]
|
|
50
52
|
|
|
51
53
|
|
|
@@ -142,6 +144,13 @@ class SessionState:
|
|
|
142
144
|
#: Latest recorded ground truth in the rig frame, when the runtime sends one.
|
|
143
145
|
ground_truth_in_rig: Optional[Trajectory] = None
|
|
144
146
|
drive_count: int = 0
|
|
147
|
+
#: The turn indicators the policy commanded with its latest drive, and that
|
|
148
|
+
#: drive's ``time_now_us`` (``CarlaVehicleService.get_vehicle_command``);
|
|
149
|
+
#: ``NO_COMMAND`` and 0 before the first drive.
|
|
150
|
+
turn_indicator: "TurnIndicator" = field(
|
|
151
|
+
default_factory=lambda: TurnIndicator.NO_COMMAND
|
|
152
|
+
)
|
|
153
|
+
turn_indicator_time_us: int = 0
|
|
145
154
|
|
|
146
155
|
#: Guards mutation from concurrent gRPC handler threads.
|
|
147
156
|
lock: threading.Lock = field(default_factory=threading.Lock, repr=False)
|
|
@@ -196,6 +205,22 @@ class DriveContext:
|
|
|
196
205
|
return self.map.stop_lines(self.renderer_data.traffic_lights)
|
|
197
206
|
|
|
198
207
|
|
|
208
|
+
class TurnIndicator(IntEnum):
|
|
209
|
+
"""What a policy asks of the ego's turn indicators (``DriveResult.turn_indicator``).
|
|
210
|
+
|
|
211
|
+
The values are ``autoware_vehicle_msgs/TurnIndicatorsCommand``'s, and the wire's
|
|
212
|
+
(``carla_driver.v0.TurnIndicator``, in ``VehicleCommand``): a classifier over Autoware's recorded
|
|
213
|
+
DISABLE / LEFT / RIGHT signal maps its class ``i`` to ``TurnIndicator(i + 1)``.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
#: Say nothing: the runtime leaves the indicators as they are.
|
|
217
|
+
NO_COMMAND = 0
|
|
218
|
+
#: Both indicators off.
|
|
219
|
+
DISABLE = 1
|
|
220
|
+
ENABLE_LEFT = 2
|
|
221
|
+
ENABLE_RIGHT = 3
|
|
222
|
+
|
|
223
|
+
|
|
199
224
|
@dataclass
|
|
200
225
|
class DriveResult:
|
|
201
226
|
"""What a policy returns.
|
|
@@ -211,6 +236,11 @@ class DriveResult:
|
|
|
211
236
|
debug_scalars: Dict[str, float] = field(default_factory=dict)
|
|
212
237
|
#: Alternative plans considered, in the rig frame.
|
|
213
238
|
sampled_trajectories_in_rig: List[Trajectory] = field(default_factory=list)
|
|
239
|
+
#: The turn indicators to show, held by the runtime until a later result
|
|
240
|
+
#: sets them; ``NO_COMMAND`` changes nothing. A CARLA runtime fetches it
|
|
241
|
+
#: (``CarlaVehicleService.get_vehicle_command``); an upstream alpasim runtime
|
|
242
|
+
#: has no indicators to show.
|
|
243
|
+
turn_indicator: TurnIndicator = TurnIndicator.NO_COMMAND
|
|
214
244
|
|
|
215
245
|
|
|
216
246
|
class BaseDriver(ABC):
|