Skip to content

Commit 435fa48

Browse files
committed
WIP: added in drivebrain system. need new time paradigm for further development
1 parent 4ae395e commit 435fa48

File tree

9 files changed

+215
-9
lines changed

9 files changed

+215
-9
lines changed

lib/interfaces/README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ message 2346 'Converter temperature error' after the warning time1) (ID32943) ha
128128
- inverter's internal value of (TD) kd
129129
- AKA SERCOS parameter ID102
130130

131-
## VCF Interfaces
131+
## VCF Interface
132132

133133
The VCR is connected over CAN and Ethernet to the VCF. We will use the CAN communication for latency-sensitive communication such as the driver input and controller input sensor signals. The Ethernet link will be used for the non-timing-sensitive data.
134134

@@ -183,3 +183,43 @@ VCF Outputs:
183183
- means that the firmware was flashed while there was changes made that had not been commited
184184
- `char git_short_hash[8]`
185185
- the git hash of the commit that was flashed to the
186+
187+
## Drivebrain Interface
188+
189+
### CAN interface
190+
191+
#### preface
192+
__NOTE__: the following messages that are on the bus are listened to by the drivebrain and are output from other boards (not VCR)
193+
- pedal data CAN packet (VCF)
194+
- inverter data (FL, FR, RL, RR inverters) -> these will be forwarded messages being forwarded by VCR onto the telem CAN line
195+
196+
VCR Outputs:
197+
198+
- VCR suspension data CAN packet:
199+
- `uint16_t rl_load_cell`
200+
- `uint16_t rr_load_cell`
201+
- `uint16_t rl_shock_pot`
202+
- `uint16_t rr_shock_pot`
203+
204+
- VCR status CAN packet:
205+
- vehicle state (oneof: RTD, tractive system enabled, etc.)
206+
- control mode
207+
- VCR
208+
- VCR error state word
209+
- drivebrain timeout, VCF timeout, VCR firmware error, etc.
210+
211+
VCR inputs (sent by drivebrain):
212+
- desired RPMs
213+
- `int16_t fl_rpm`
214+
- `int16_t fr_rpm`
215+
- `int16_t rl_rpm`
216+
- `int16_t rr_rpm`
217+
218+
- torque limits
219+
- __note__: in units of .01nm: 2100 = 21nm, 2150 = 21.5nm
220+
- `int16_t fl_torque_lim`
221+
- `int16_t fr_torque_lim`
222+
- `int16_t rl_torque_lim`
223+
- `int16_t rl_torque_lim`
224+
225+

lib/systems/README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,26 @@ stateDiagram-v2
101101
torq_mode --> err: incorrect user command type OR any inverter error
102102
err --> clear_err: on user request of error reset
103103
clear_err --> not_en_hv: on successful reset of errors (either internally to the drivetrain system or of the inverters themselves)
104-
```
104+
```
105+
106+
## drivebrain controller system
107+
108+
Drivebrain Controller for fail-safe pass-through control of the car
109+
110+
this class is the "controller" that allows for pass-through control as commanded by the drivebrain. It also calculates the latency of the most recent input and checks to see if the most recent input is still valid and has not expired. If the input has expired then it switches over to the fail-safe control mode (MODE0) to allow for safe failing even while the car is driving so that we dont lose hard-braking capabilities.
111+
112+
The controller can clear it's own fault by switching off of this operating mode and then swapping back to this operating mode. The fault clears the first time this controller gets evaluated while switch from the swapped-to mode back to this pass through mode.
113+
- all controllers get evaluated once when being evaluated as a mode to switch to. during this evaluation is when the fault clears.
114+
115+
### latency measurement:
116+
- the latency is measured by the difference in times in received messages from drivebrain over CAN. if the difference is too great, we swap to MODE0 control. it is assumed that the transmission delay is negligible
117+
118+
### config and I/O
119+
config:
120+
- maximum allowed latency
121+
- assigned controller mode (currently defaults to MODE4)
122+
inputs:
123+
- the current car state from which it gets the latest drivebrain input, current controller mode and the stamped drivebrain message data
124+
outputs:
125+
- drivetrain command either from drivebrain or mode0 depending on if an error is present
126+
- getter for the internal state of the drivebrain controller (error present, etc.)

lib/systems/include/TorqueControllerMux.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class TorqueControllerMux
7979
/// @param max_power_limit the max power limit defaults to TC_MUX_DEFAULT_PARAMS::MAX_POWER_LIMIT
8080
/// @param num_motors the number of motors. defaults to 4.
8181
/// @note TC Mux must be created with at least 1 controller.
82-
explicit TorqueControllerMux(std::array<std::function<DrivetrainCommand_s(const VCRData_s &state)>, num_controllers> controller_evals,
82+
explicit TorqueControllerMux(std::array<std::function<DrivetrainCommand_s(const VCRData_s &state, unsigned long eval_millis)>, num_controllers> controller_evals,
8383
std::array<bool, num_controllers> mux_bypass_limits,
8484
float max_change_speed = TC_MUX_DEFAULT_PARAMS::MAX_SPEED_FOR_MODE_CHANGE,
8585
float max_torque_pos_change_delta = TC_MUX_DEFAULT_PARAMS::MAX_TORQUE_DELTA_FOR_MODE_CHANGE,
@@ -106,7 +106,7 @@ class TorqueControllerMux
106106

107107
private:
108108

109-
std::array<std::function<DrivetrainCommand_s(const VCRData_s &state)>, num_controllers> _controller_evals;
109+
std::array<std::function<DrivetrainCommand_s(const VCRData_s &state, unsigned long eval_millis)>, num_controllers> _controller_evals;
110110

111111
std::array<bool, num_controllers> _mux_bypass_limits;
112112

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#ifndef __DRIVEBRAINCONTROLLER_H__
2+
#define __DRIVEBRAINCONTROLLER_H__
3+
4+
#include "controllers/SimpleController.h"
5+
#include "SharedFirmwareTypes.h"
6+
#include <cmath>
7+
8+
// TODO - [ ] need to validate that the times that are apparent in the drivebrain data
9+
// and ensure that they are within tolerence to current sys-tick
10+
11+
// TODO - [ ] if the drivebrain controller is currently the active controller,
12+
// the latency fault should be latching
13+
14+
// meaning that if we fail any of the latency checks while active we cannot clear the timing failure fault
15+
// unless we switch to another controller and back again. in reality, the CAN line or ethernet conditions
16+
// probably wont improve randomly during runtime so it will keep faulting. primarily this is just to make sure
17+
// we dont keep going from latent to not latent while driving and thus the driver gets jittered and the
18+
// drivetrain will keep "powering up" and "powering down"
19+
20+
// TODO - [ ] correctly measure latency between drivebrain and VCR:
21+
//
22+
23+
/*! \brief Drivebrain Controller for fail-safe pass-through control of the car
24+
RESPONSIBILITIES AND DOCUMENTATION
25+
26+
this class is the "controller" that allows for pass-through control as commanded by the drivebrain. It also calculates the
27+
latency of the most recent input and checks to see if the most recent input is still valid and has not expired. If the
28+
input has expired then it switches over to the fail-safe control mode (MODE0) to allow for safe failing even while the car
29+
is driving so that we dont lose hard-braking capabilities.
30+
31+
This class can clear it's own fault by switching off of this operating mode and then swapping back to this operating mode.
32+
The fault clears the first time this controller gets evaluated while switch from the swapped-to mode back to this pass
33+
through mode.
34+
35+
latency measurement:
36+
- the latency is measured by the difference in times in received messages from drivebrain over CAN. if the difference
37+
is too great, we swap to MODE0 control. it is assumed that the transmission delay is negligible
38+
39+
config:
40+
- maximum allowed latency
41+
- assigned controller mode (currently defaults to MODE4)
42+
inputs:
43+
- the current car state from which it gets the latest drivebrain input, current controller mode and the stamped drivebrain
44+
message data
45+
*/
46+
class DrivebrainController
47+
{
48+
public:
49+
50+
/// @brief constructor for the drivebrain controller class
51+
/// @param allowed_latency the allowed latency in milliseconds for which if the most recent packet has a timestamp older than this measure of time we fail safe
52+
/// @param assigned_controller_mode the controller mode that the drivebrain controller is assigned to. is required for evaluating whether or not we are active or not
53+
DrivebrainController(unsigned long allowed_latency,
54+
ControllerMode_e assigned_controller_mode = ControllerMode_e::MODE_4)
55+
: _emergency_control()
56+
{
57+
_last_worst_latency_timestamp = 0;
58+
_worst_latency_so_far = -1;
59+
_params = {allowed_latency, assigned_controller_mode};
60+
}
61+
62+
/// @brief evaluate function for running the business logic
63+
/// @param state the current state of the car
64+
/// @param eval_millis
65+
/// @return torque controller output that gets passed through the TC MUX
66+
DrivetrainCommand_s evaluate(const VCRData_s &state, unsigned long eval_millis);
67+
68+
/// @brief getter for the current status of whether or not the controller has had a timing failure during operation
69+
/// @return bool of status
70+
bool get_timing_failure_status() { return _timing_failure; }
71+
72+
private:
73+
struct
74+
{
75+
unsigned long allowed_latency = {};
76+
ControllerMode_e assigned_controller_mode = {};
77+
} _params;
78+
79+
unsigned long _last_worst_latency_timestamp;
80+
int64_t _worst_latency_so_far;
81+
bool _timing_failure = false;
82+
unsigned long _last_setpoint_millis = -1;
83+
TorqueControllerSimple _emergency_control;
84+
};
85+
86+
#endif // __DRIVEBRAINCONTROLLER_H__

lib/systems/include/controllers/SimpleController.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ class TorqueControllerSimple
3131
{
3232
public:
3333
/// @brief simple TC with tunable F/R torque balance. Accel torque balance can be tuned independently of regen torque balance
34-
TorqueControllerSimple(TorqueControllerSimpleParams_s params)
34+
TorqueControllerSimple(TorqueControllerSimpleParams_s params = TorqueControllerSimpleParams_s())
3535
: _params(params)
3636
{ }
3737
/// @brief calculates torque output based off max torque and simple torque scaling
38-
DrivetrainCommand_s evaluate(const VCRData_s &state);
38+
DrivetrainCommand_s evaluate(const VCRData_s &state, unsigned long eval_millis);
3939

4040
private:
4141
TorqueControllerSimpleParams_s _params;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "controllers/DrivebrainController.h"
2+
#include "SharedFirmwareTypes.h"
3+
#include <cstdint>
4+
5+
DrivetrainCommand_s DrivebrainController::evaluate(const VCRData_s &state, unsigned long eval_millis)
6+
{
7+
8+
9+
10+
auto db_input = state.interface_data.latest_drivebrain_command;
11+
12+
// cases for timing_failure:
13+
// 1 we have not received any messages from the db (timestamped message recvd flag initialized as false in struct def)
14+
bool no_messages_received = (!db_input.recvd);
15+
16+
17+
// 2 if the time between the current VCR eval_millis time and the last millis time that we recvd a drivebrain msg is too high
18+
bool message_too_latent = (::abs((int)(static_cast<int64_t>(eval_millis) - static_cast<int64_t>(db_input.last_recv_millis))) > (int)_params.allowed_latency);
19+
constexpr int64_t debug_timestamp_period_ms = 5000;
20+
if((static_cast<int64_t>(eval_millis) - static_cast<int64_t>(_last_worst_latency_timestamp)) > debug_timestamp_period_ms)
21+
{
22+
_last_worst_latency_timestamp = eval_millis;
23+
_worst_latency_so_far = -1;
24+
}
25+
26+
if( (eval_millis - db_input.last_recv_millis) > _worst_latency_so_far)
27+
{
28+
_worst_latency_so_far = (eval_millis - db_input.last_recv_millis);
29+
}
30+
31+
32+
bool timing_failure = (message_too_latent || no_messages_received);
33+
34+
// only in the case that our speed is low enough (<1 m/s) do we want to clear the fault
35+
36+
bool is_active_controller = state.system_data.tc_mux_status.active_controller_mode == _params.assigned_controller_mode;
37+
38+
if ((!is_active_controller) && (!timing_failure))
39+
{
40+
// timing failure should be false here
41+
_timing_failure = false;
42+
}
43+
44+
DrivetrainCommand_s output;
45+
if (!timing_failure && (!_timing_failure))
46+
{
47+
_last_setpoint_millis = db_input.last_recv_millis;
48+
49+
output = db_input.cmd_data;
50+
}
51+
else
52+
{
53+
_timing_failure = true;
54+
// output.command = {{0.0f}, {0.0f}};
55+
output = _emergency_control.evaluate(state, eval_millis);
56+
}
57+
return output;
58+
}

lib/systems/src/controllers/SimpleController.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "controllers/SimpleController.h"
22

3-
DrivetrainCommand_s TorqueControllerSimple::evaluate(const VCRData_s &state)
3+
DrivetrainCommand_s TorqueControllerSimple::evaluate(const VCRData_s &state, unsigned long eval_millis)
44
{
55
// Both pedals are not pressed and no implausibility has been detected
66
// accelRequest goes between 1.0 and -1.0

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
lib_deps_shared =
1010
https://github.com/hytech-racing/shared_firmware_systems.git#af96a63
11-
https://github.com/hytech-racing/shared_firmware_types.git
11+
https://github.com/hytech-racing/shared_firmware_types.git#feature/db_controls_and_interface
1212
; ../../shared_firmware_types
1313
https://github.com/ssilverman/QNEthernet#v0.26.0
1414
https://github.com/hytech-racing/HT_SCHED

test/test_systems/test_tcmux.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ TEST(TorqueControllerMuxTesting, test_mode0_evaluation)
187187
// static_cast<Controller *>(&simple_launch),
188188
// static_cast<Controller *>(&slip_launch)},
189189
// {false, true, false, false, false});
190-
TorqueControllerMux<1> torque_controller_mux({std::bind(&TorqueControllerSimple::evaluate, std::ref(tc_simple), std::placeholders::_1)}, {false});
190+
TorqueControllerMux<1> torque_controller_mux({std::bind(&TorqueControllerSimple::evaluate, std::ref(tc_simple), std::placeholders::_1, std::placeholders::_2)}, {false});
191191

192192

193193
VCRData_s mode_0_input_state;

0 commit comments

Comments
 (0)