DriveWorks SDK Reference
3.0.4260 Release
For Test and Development only

/dvs/git/dirty/gitlab-master_av/dw/sdk/doc/tutorials/vehicleioPlugins/dwx_vehicleioPlugins.md
Go to the documentation of this file.
1 # Copyright (c) 2019-2020 NVIDIA CORPORATION. All rights reserved.
2 
3 @page dwx_vehicleio_plugins VehicleIO Plugins
4 @tableofcontents
5 
6 @note SW Release Applicability: This tutorial is applicable to modules in both **NVIDIA DriveWorks** and **NVIDIA DRIVE Software** releases.
7 
8 @section vehicleIO_plugin_overview VehicleIO Plugins Overview
9 
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.
13 
14 @section vehicleIO_plugin_implementation Implementing Custom VehicleIO Plugin
15 
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`.
19 
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.
23 
24 ## Initialization
25 
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:
30 
31 ```{.cpp}
32 dwStatus _dwVehicleIODriver_initialize()
33 {
34  dwStatus status;
35  dwStatus result = DW_SUCCESS;
36 
37  dwContextParameters sdkParams = {};
38  dwInitialize(&gSdk, DW_VERSION, &sdkParams);
39 
40  status = dwCANInterpreter_buildFromDBC(&gIntp, ("AutonomousVehicleCANSignals.dbc"), gSdk);
41  checkError(result, status, "cannot create DBC-based CAN message interpreter");
42 
43  return result;
44 }
45 ```
46 
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.
50 
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"
53 VehicleIO node:
54 
55 ```
56 {
57  "rig": {
58  "vehicleio": [
59  {
60  "type": "custom",
61  "parent-sensor": "can:vehicle:custom",
62  "custom-lib": "../../../bin/libsample_vehicleio_plugin.so"
63  }
64  ],
65  "sensors": [
66  {
67  "name": "can:vehicle:custom",
68  "parameter": "file=can-vio-generic.bin",
69  "protocol": "can.virtual",
70  "properties": null,
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 ] }
73  }
74  ]
75  }
76 }
77 ```
78 
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.
82 
83 ## Releasing
84 
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:
88 
89 ```{.cpp}
90 dwStatus _dwVehicleIODriver_release()
91 {
92  dwCANInterpreter_release(gIntp);
93  dwRelease(gSdk);
94  return DW_SUCCESS;
95 }
96 ```
97 
98 ## CAN messages consumption
99 
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:
103 
104 ```{.cpp}
105 dwStatus _dwVehicleIODriver_consume(const dwCANMessage* msg, dwVehicleIOState* state)
106 {
107  dwStatus status;
108  dwStatus result = DW_SUCCESS;
109 
110  status = dwCANInterpreter_consume(msg, gIntp);
111  checkError(result ,status, "consume message failed");
112  parseSteeringReport(state);
113 
114  return result;
115 }
116 ```
117 
118 In the example above, we simply parse current steering angle report using our
119 CAN/DBC interpreter:
120 
121 ```{.cpp}
122 static void parseSteeringReport(dwVehicleIOState* state)
123 {
124  dwStatus status;
125  uint32_t num;
126  status = dwCANInterpreter_getNumberSignals(&num, gIntp);
127 
128  if (status == DW_SUCCESS && num > 0)
129  {
130  float32_t value = 0;
131  dwTime_t timestamp = 0;
132  const char* name;
133 
134  for (uint32_t i = 0; i < num; ++i)
135  {
136  if (dwCANInterpreter_getSignalName(&name, i, gIntp) == DW_SUCCESS)
137  {
138  if (dwCANInterpreter_getf32(&value, &timestamp, i, gIntp) == DW_SUCCESS)
139  {
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;
146  }
147  }
148  }
149  }
150 }
151 ```
152 
153 ## CAN messages generation
154 
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:
160 
161 ```{.cpp}
162 dwStatus _dwVehicleIODriver_sendCommand(const dwVehicleIOCommand* cmd,
163  dwSensorHandle_t sensor)
164 {
165  dwCANMessage msgCAN{};
166  dwStatus status;
167  dwStatus result = DW_SUCCESS;
168 
169  status = dwCANInterpreter_createMessageFromName(&msgCAN, GENERIC_MSG_STEERING_CMD, gIntp);
170  checkError(result, status, "create steering message failed");
171 
172  status = encodeSteering(msgCAN, cmd);
173  checkError(result, status, "encode steering failed");
174 
175  status = dwSensorCAN_sendMessage(&msgCAN, 1000000, sensor);
176  checkError(result, status, "send steering failed");
177 
178  return result;
179 }
180 
181 dwStatus _dwVehicleIODriver_sendMiscCommand(const dwVehicleIOMiscCommand*,
182  dwSensorHandle_t)
183 {
184  return DW_NOT_IMPLEMENTED;
185 }
186 ```
187 
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.
191 
192 And as in previous section, we use CAN interpreter to encode commands into CAN
193 messages:
194 
195 ```{.cpp}
196 static dwStatus encodeSteering(dwCANMessage& msgCAN, const dwVehicleIOCommand* cmd)
197 {
198  dwStatus status;
199  dwStatus result = DW_SUCCESS;
200 
201  status = dwCANInterpreter_encodef32(cmd->steeringWheelAngle,
202  GENERIC_ID_STEERING_WHEEL_ANGLE_COMMAND,
203  &msgCAN, gIntp);
204  checkError(result, status, "encode steering angle failed");
205 
206  status = dwCANInterpreter_encodei32(cmd->steeringValid,
207  GENERIC_ID_STEERING_WHEEL_ANGLE_COMMAND_VALID,
208  &msgCAN, gIntp);
209  checkError(result, status, "encode steering valid failed");
210 
211  status = dwCANInterpreter_encodef32(cmd->steeringSpeed,
212  GENERIC_ID_STEERING_WHEEL_STEER_SPEED,
213  &msgCAN, gIntp);
214  checkError(result, status, "encode steering speed failed");
215 
216  status = dwCANInterpreter_encodei32(cmd->clearFaults ? true : false,
217  GENERIC_ID_STEERING_WHEEL_STEER_CLEAR_FAULT,
218  &msgCAN, gIntp);
219  checkError(result, status, "encode steering clear fault failed");
220  return result;
221 }
222 ```
223 
224 ## Building plugin as a dynamic library
225 
226 The plugin code must be compiled into a dynamic library.
227 
228 Firstly, we should create a folder under `samples` called `vehicleio_plugin` and create a `CMakeLists.txt` under this folder:
229 
230 ```
231 project(sample_vehicleio_plugin C CXX)
232 
233 set(SOURCES
234  driverConf.hpp
235  driver.cpp
236 )
237 
238 set(LIBRARIES
239  samples_framework
240  ${Driveworks_LIBRARIES}
241 )
242 
243 add_library(${PROJECT_NAME} SHARED ${SOURCES})
244 target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBRARIES})
245 set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER "Samples")
246 
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}
251 )
252 
253 sdk_add_sample(${PROJECT_NAME})
254 ```
255 
256 Run `cmake` and the preferred build system to compile the library. This will generate a `libsample_vehicleio_plugin.so`.
257 
258 See \ref dwx_vehicleio_plugin_sample for more details.