1 # Copyright (c) 2019-2020 NVIDIA CORPORATION. All rights reserved.
3 @page dwx_vehicleio_plugins VehicleIO Plugins
6 @note SW Release Applicability: This tutorial is applicable to modules in both **NVIDIA DriveWorks** and **NVIDIA DRIVE Software** releases.
8 @section vehicleIO_plugin_overview VehicleIO Plugins Overview
10 The VehicleIO Plugin back-end enables writing fully customized drive-by-wire
11 abstraction that will be represented as a @ref vehicleio_mainsection interface
12 for the rest of the software stack.
14 @section vehicleIO_plugin_implementation Implementing Custom VehicleIO Plugin
16 A VehicleIO plugin in DriveWorks requires implementing a set of pre-defined
17 functions. The declarations of these functions are located in
18 `dw/control/vehicleio/plugins/VehicleIODriver.h`.
20 In this tutorial, we are going to implement a simple drive-by-wire system that
21 is responsible for steering wheel angle. See \ref dwx_vehicleio_plugin_sample
22 for the corresponding sample code.
26 In essence, our plugin is a dynamically loaded shared library, and the core
27 @ref vehicleio_mainsection module will first call `_dwVehicleIODriver_initialize()`
28 function of this library, which should prepare all objects and state that is needed
29 for the plugin to function:
32 dwStatus _dwVehicleIODriver_initialize()
35 dwStatus result = DW_SUCCESS;
37 dwContextParameters sdkParams = {};
38 dwInitialize(&gSdk, DW_VERSION, &sdkParams);
40 status = dwCANInterpreter_buildFromDBC(&gIntp, ("AutonomousVehicleCANSignals.dbc"), gSdk);
41 checkError(result, status, "cannot create DBC-based CAN message interpreter");
47 Above, `dwCANInterpreter_buildFromDBC()` function initializes an interpreter
48 object that will be useful to work with our DBC file. See \ref
49 dwx_canbus_message_sample for more information about CAN interpreter usage.
51 When using the plugin with, for example, \ref dwx_vehicleio_sample, in order
52 for VehicleIO core to load the plugin, Rig file should specify "custom"
61 "parent-sensor": "can:vehicle:custom",
62 "custom-lib": "../../../bin/libsample_vehicleio_plugin.so"
67 "name": "can:vehicle:custom",
68 "parameter": "file=can-vio-generic.bin",
69 "protocol": "can.virtual",
71 "nominalSensor2Rig": { "quaternion": [ 0.0, 0.0, 0.0, 1.0 ], "t": [ 0.0, 0.0, 0.0 ] },
72 "sensor2Rig": { "quaternion": [ 0.0, 0.0, 0.0, 1.0 ], "t": [ 0.0, 0.0, 0.0 ] }
79 Full example of Rig file is available in
80 `data/samples/vehicleio/rig-plugin.json`, and exact commands how to run the
81 VehicleIO sample with the plugin is available at \ref dwx_vehicleio_plugin_sample.
85 When plugin is no longer needed, VehicleIO core will call
86 `_dwVehicleIODriver_release()` method, which is an opportunity for the module
87 to cleanup any created objects and state:
90 dwStatus _dwVehicleIODriver_release()
92 dwCANInterpreter_release(gIntp);
98 ## CAN messages consumption
100 CAN messages represent the input to the module, which plugin must parse and
101 update its state, if needed. VehicleIO core will call plugin's
102 `_dwVehicleIODriver_consume()` function when there is a new message to consume:
105 dwStatus _dwVehicleIODriver_consume(const dwCANMessage* msg, dwVehicleIOState* state)
108 dwStatus result = DW_SUCCESS;
110 status = dwCANInterpreter_consume(msg, gIntp);
111 checkError(result ,status, "consume message failed");
112 parseSteeringReport(state);
118 In the example above, we simply parse current steering angle report using our
122 static void parseSteeringReport(dwVehicleIOState* state)
126 status = dwCANInterpreter_getNumberSignals(&num, gIntp);
128 if (status == DW_SUCCESS && num > 0)
131 dwTime_t timestamp = 0;
134 for (uint32_t i = 0; i < num; ++i)
136 if (dwCANInterpreter_getSignalName(&name, i, gIntp) == DW_SUCCESS)
138 if (dwCANInterpreter_getf32(&value, ×tamp, i, gIntp) == DW_SUCCESS)
140 if (0 == strcmp(name, GENERIC_ID_STEERING_WHEEL_ANGLE_REPORT))
141 state->steeringWheelAngle = value;
142 else if (0 == strcmp(name, GENERIC_ID_STEERING_WHEEL_TORQUE_REPORT))
143 state->steeringWheelTorque = value;
144 else if (0 == strcmp(name, GENERIC_ID_STEERING_WHEEL_SPEED_REPORT))
145 state->speed = value;
153 ## CAN messages generation
155 CAN messages are also the output of the module, thus when VehicleIO is
156 requested to send a command, the core module will relay the request to the
157 plugin, issuing two calls: `_dwVehicleIODriver_sendCommand()` and
158 `_dwVehicleIODriver_sendMiscCommand()`. Each of the function should encode
159 command arguments into CAN messages and send via a provided sensor handle:
162 dwStatus _dwVehicleIODriver_sendCommand(const dwVehicleIOCommand* cmd,
163 dwSensorHandle_t sensor)
165 dwCANMessage msgCAN{};
167 dwStatus result = DW_SUCCESS;
169 status = dwCANInterpreter_createMessageFromName(&msgCAN, GENERIC_MSG_STEERING_CMD, gIntp);
170 checkError(result, status, "create steering message failed");
172 status = encodeSteering(msgCAN, cmd);
173 checkError(result, status, "encode steering failed");
175 status = dwSensorCAN_sendMessage(&msgCAN, 1000000, sensor);
176 checkError(result, status, "send steering failed");
181 dwStatus _dwVehicleIODriver_sendMiscCommand(const dwVehicleIOMiscCommand*,
184 return DW_NOT_IMPLEMENTED;
188 If certain type of commands are not relevant, the plugin is permitted to return
189 `DW_NOT_IMPLEMENTED` status, as was shown in
190 `_dwVehicleIODriver_sendMiscCommand()` above.
192 And as in previous section, we use CAN interpreter to encode commands into CAN
196 static dwStatus encodeSteering(dwCANMessage& msgCAN, const dwVehicleIOCommand* cmd)
199 dwStatus result = DW_SUCCESS;
201 status = dwCANInterpreter_encodef32(cmd->steeringWheelAngle,
202 GENERIC_ID_STEERING_WHEEL_ANGLE_COMMAND,
204 checkError(result, status, "encode steering angle failed");
206 status = dwCANInterpreter_encodei32(cmd->steeringValid,
207 GENERIC_ID_STEERING_WHEEL_ANGLE_COMMAND_VALID,
209 checkError(result, status, "encode steering valid failed");
211 status = dwCANInterpreter_encodef32(cmd->steeringSpeed,
212 GENERIC_ID_STEERING_WHEEL_STEER_SPEED,
214 checkError(result, status, "encode steering speed failed");
216 status = dwCANInterpreter_encodei32(cmd->clearFaults ? true : false,
217 GENERIC_ID_STEERING_WHEEL_STEER_CLEAR_FAULT,
219 checkError(result, status, "encode steering clear fault failed");
224 ## Building plugin as a dynamic library
226 The plugin code must be compiled into a dynamic library.
228 Firstly, we should create a folder under `samples` called `vehicleio_plugin` and create a `CMakeLists.txt` under this folder:
231 project(sample_vehicleio_plugin C CXX)
240 ${Driveworks_LIBRARIES}
243 add_library(${PROJECT_NAME} SHARED ${SOURCES})
244 target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBRARIES})
245 set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Samples")
247 get_property(TARGET_PACKAGE GLOBAL PROPERTY TARGET_PACKAGE)
248 install(TARGETS ${PROJECT_NAME}
249 COMPONENT dw-samples-${TARGET_PACKAGE} # targeted package (dw / dav / ..)
250 DESTINATION ${SDK_SAMPLE_DESTINATION}
253 sdk_add_sample(${PROJECT_NAME})
256 Run `cmake` and the preferred build system to compile the library. This will generate a `libsample_vehicleio_plugin.so`.
258 See \ref dwx_vehicleio_plugin_sample for more details.