Skip to content

Commit db4730c

Browse files
committed
Add Support for BMS Tiltback
1 parent 1ad13ed commit db4730c

File tree

7 files changed

+260
-7
lines changed

7 files changed

+260
-7
lines changed

Diff for: package.lisp

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
; Set firmware version:
99
(apply ext-set-fw-version (sysinfo 'fw-ver))
1010

11+
(if (>= (+ (first (sysinfo 'fw-ver)) (* (second (sysinfo 'fw-ver)) 0.01)) 6.05) {
12+
(import "src/bms-state.lisp" 'bms-state)
13+
(read-eval-program bms-state)
14+
(spawn bms-state-loop)
15+
})
16+
1117
; Set to 1 to monitor debug variables
1218
(define debug 1)
1319

Diff for: src/bms-state.lisp

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
(def bms-fault-codes '(
2+
(NONE . 0)
3+
(BMS_COMM_TIMEOUT . 1)
4+
(BMS_SOFT_OVER_TEMP . 2)
5+
(BMS_HARD_OVER_TEMP . 3)
6+
(CELL_SOFT_OVER_VOLTAGE . 4)
7+
(CELL_HARD_OVER_VOLTAGE . 5)
8+
(CELL_SOFT_UNDER_VOLTAGE . 6)
9+
(CELL_HARD_UNDER_VOLTAGE . 7)
10+
(CELL_SOFT_OVER_TEMP . 8)
11+
(CELL_HARD_OVER_TEMP . 9)
12+
(CELL_SOFT_UNDER_TEMP . 10)
13+
(CELL_HARD_UNDER_TEMP . 11)
14+
(CELL_SOFT_BALANCE . 12)
15+
(CELL_HARD_BALANCE . 13)
16+
))
17+
(def bms-fault)
18+
(def bms-vmin-limit-start)
19+
(def bms-vmin-limit-end)
20+
(def bms-vmax-limit-start)
21+
(def bms-vmax-limit-end)
22+
(def bms-tmax-limit-start)
23+
(def bms-tmax-limit-end)
24+
(def bms-discharge-tmax-limit-start)
25+
(def bms-discharge-tmax-limit-end)
26+
(def bms-tmin-limit-start 0)
27+
(def bms-tmin-limit-end -10)
28+
(def bms-cell-balance-start 0.05)
29+
(def bms-cell-balance-end 0.1)
30+
(def bms-config-update-time (systime))
31+
32+
(defun bms-set-fault (fault-code set-bit) {
33+
(if (eq fault-code 'NONE) {
34+
(setq bms-fault 0u32)
35+
}{
36+
(var bit-pos (- (assoc bms-fault-codes fault-code) 1))
37+
(if (= set-bit 1) (setq bms-fault (bitwise-or bms-fault (shl 1 bit-pos))) (setq bms-fault (bitwise-and bms-fault (bitwise-not (shl 1 bit-pos)))))
38+
})
39+
})
40+
41+
(defun bms-update-config () {
42+
(if (!= (conf-get 'bms-limit-mode) 0) (conf-set 'bms-limit-mode 0)) ;Disable bms limit mode (soc temp volt) so it doesn't dump us.
43+
(setq bms-vmin-limit-start (conf-get 'bms-vmin-limit-start))
44+
(setq bms-vmin-limit-end (conf-get 'bms-vmin-limit-end))
45+
46+
(setq bms-vmax-limit-start (conf-get 'bms-vmax-limit-start))
47+
(setq bms-vmax-limit-end (conf-get 'bms-vmax-limit-end))
48+
49+
(setq bms-tmax-limit-start (conf-get 'bms-t-limit-start))
50+
(setq bms-tmax-limit-end (conf-get 'bms-t-limit-end))
51+
(setq bms-discharge-tmax-limit-start (+ bms-tmax-limit-start 10))
52+
(setq bms-discharge-tmax-limit-end (+ bms-tmax-limit-end 10))
53+
54+
(setq bms-config-update-time (systime))
55+
})
56+
57+
(defun bms-check-cell-volts () {
58+
(var num-cells (get-bms-val 'bms-cell-num))
59+
(if (> num-cells 0) {
60+
(var max-volt (get-bms-val 'bms-v-cell 0))
61+
(var min-volt (get-bms-val 'bms-v-cell 0))
62+
(looprange i 0 num-cells {
63+
(var cell-volt (get-bms-val 'bms-v-cell i))
64+
(if (> cell-volt max-volt)
65+
(setq max-volt cell-volt))
66+
(if (< cell-volt min-volt)
67+
(setq min-volt cell-volt))
68+
(cond
69+
((> cell-volt bms-vmax-limit-end) {
70+
(bms-set-fault 'CELL_HARD_OVER_VOLTAGE 1)
71+
(bms-set-fault 'CELL_SOFT_OVER_VOLTAGE 0)
72+
(break)
73+
})
74+
((> cell-volt bms-vmax-limit-start)
75+
(bms-set-fault 'CELL_SOFT_OVER_VOLTAGE 1))
76+
(t nil)
77+
)
78+
(cond
79+
((< cell-volt bms-vmin-limit-end) {
80+
(bms-set-fault 'CELL_HARD_UNDER_VOLTAGE 1)
81+
(bms-set-fault 'CELL_SOFT_UNDER_VOLTAGE 0)
82+
(break)
83+
})
84+
((< cell-volt bms-vmin-limit-start)
85+
(bms-set-fault 'CELL_SOFT_UNDER_VOLTAGE 1))
86+
(t nil)
87+
)
88+
})
89+
(var volt-diff (abs (- max-volt min-volt)))
90+
(cond
91+
((> volt-diff bms-cell-balance-end) {
92+
(bms-set-fault 'CELL_HARD_BALANCE 1)
93+
})
94+
((> volt-diff bms-cell-balance-start)
95+
(bms-set-fault 'CELL_SOFT_BALANCE 1))
96+
(t nil)
97+
)
98+
})
99+
})
100+
101+
(defun bms-check-temps () {
102+
(looprange i 0 (get-bms-val 'bms-temp-adc-num) {
103+
(var adc-temp (get-bms-val 'bms-temps-adc i))
104+
(cond
105+
((> adc-temp bms-tmax-limit-end) {
106+
(bms-set-fault 'CELL_HARD_OVER_TEMP 1)
107+
(bms-set-fault 'CELL_SOFT_OVER_TEMP 0)
108+
(break)
109+
})
110+
((> adc-temp bms-tmax-limit-start)
111+
(bms-set-fault 'CELL_SOFT_OVER_TEMP 1))
112+
(t nil)
113+
)
114+
(cond
115+
((< adc-temp bms-tmin-limit-end) {
116+
(bms-set-fault 'CELL_HARD_UNDER_TEMP 1)
117+
(bms-set-fault 'CELL_SOFT_UNDER_TEMP 0)
118+
(break)
119+
})
120+
((< adc-temp bms-tmin-limit-start)
121+
(bms-set-fault 'CELL_SOFT_UNDER_TEMP 1))
122+
(t nil)
123+
)
124+
})
125+
(cond
126+
((> (get-bms-val 'bms-temp-ic) bms-discharge-tmax-limit-end)
127+
(bms-set-fault 'BMS_HARD_OVER_TEMP 1))
128+
((> (get-bms-val 'bms-temp-ic) bms-discharge-tmax-limit-start)
129+
(bms-set-fault 'BMS_SOFT_OVER_TEMP 1))
130+
(t nil)
131+
)
132+
})
133+
134+
(defun bms-state-loop () {
135+
(bms-update-config)
136+
(bms-set-fault 'NONE 0)
137+
(loopwhile t {
138+
(if (>= (get-bms-val 'bms-can-id) 0) {
139+
(if (> (secs-since bms-config-update-time) 1.0) (bms-update-config))
140+
(if (> (get-bms-val 'bms-msg-age) 5.0) {
141+
(bms-set-fault 'BMS_COMM_TIMEOUT 1)
142+
} {
143+
(bms-set-fault 'NONE 0)
144+
(bms-check-cell-volts)
145+
(bms-check-temps)
146+
})
147+
(apply ext-bms-set-fault bms-fault)
148+
})
149+
(yield 100000)
150+
})
151+
})

Diff for: src/conf/datatypes.h

+17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,23 @@
2121
#include <stdbool.h>
2222
#include <stdint.h>
2323

24+
typedef enum {
25+
NONE = 0,
26+
BMS_COMM_TIMEOUT = 1,
27+
BMS_SOFT_OVER_TEMP = 2,
28+
BMS_HARD_OVER_TEMP = 3,
29+
CELL_SOFT_OVER_VOLTAGE = 4,
30+
CELL_HARD_OVER_VOLTAGE = 5,
31+
CELL_SOFT_UNDER_VOLTAGE = 6,
32+
CELL_HARD_UNDER_VOLTAGE = 7,
33+
CELL_SOFT_OVER_TEMP = 8,
34+
CELL_HARD_OVER_TEMP = 9,
35+
CELL_SOFT_UNDER_TEMP = 10,
36+
CELL_HARD_UNDER_TEMP = 11,
37+
CELL_SOFT_BALANCE = 12,
38+
CELL_HARD_BALANCE = 13
39+
} BMS_FAULT_CODES;
40+
2441
typedef enum {
2542
INPUTTILT_NONE = 0,
2643
INPUTTILT_UART,

Diff for: src/main.c

+69-7
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,14 @@ typedef enum {
5555
BEEP_SENSORS = 7,
5656
BEEP_LOWBATT = 8,
5757
BEEP_IDLE = 9,
58-
BEEP_ERROR = 10
58+
BEEP_ERROR = 10,
59+
BEEP_TEMP_CELL_UNDER = 11,
60+
BEEP_TEMP_CELL_OVER = 12,
61+
BEEP_CELL_LV = 13,
62+
BEEP_CELL_HV = 14,
63+
BEEP_CELL_BALANCE = 15,
64+
BEEP_BMS_CONNECTION = 16,
65+
BEEP_BMS_TEMP = 17
5966
} BeepReason;
6067

6168
static const FootpadSensorState flywheel_konami_sequence[] = {
@@ -194,6 +201,8 @@ typedef struct {
194201
Konami flywheel_konami;
195202
Konami headlights_on_konami;
196203
Konami headlights_off_konami;
204+
205+
uint32_t bms_fault;
197206
} data;
198207

199208
static void brake(data *d);
@@ -362,6 +371,8 @@ static void configure(data *d) {
362371
sizeof(headlights_off_konami_sequence)
363372
);
364373

374+
d->bms_fault = 0;
375+
365376
reconfigure(d);
366377

367378
if (d->state.state == STATE_DISABLED) {
@@ -745,11 +756,20 @@ static void calculate_setpoint_target(data *d) {
745756
if (d->state.mode != MODE_FLYWHEEL) {
746757
d->state.sat = SAT_PB_DUTY;
747758
}
748-
} else if (d->motor.duty_cycle > 0.05 && input_voltage > d->float_conf.tiltback_hv) {
749-
d->beep_reason = BEEP_HV;
759+
} else if (d->motor.duty_cycle > 0.05 &&
760+
(input_voltage > d->float_conf.tiltback_hv ||
761+
bms_is_fault_set(d->bms_fault, CELL_SOFT_OVER_VOLTAGE) ||
762+
bms_is_fault_set(d->bms_fault, CELL_HARD_OVER_VOLTAGE))) {
763+
if (bms_is_fault_set(d->bms_fault, CELL_SOFT_OVER_VOLTAGE) ||
764+
bms_is_fault_set(d->bms_fault, CELL_HARD_OVER_VOLTAGE)) {
765+
d->beep_reason = BEEP_CELL_HV;
766+
} else {
767+
d->beep_reason = BEEP_HV;
768+
}
750769
beep_alert(d, 3, false);
751770
if (((d->current_time - d->tb_highvoltage_timer) > .5) ||
752-
(input_voltage > d->float_conf.tiltback_hv + 1)) {
771+
(input_voltage > d->float_conf.tiltback_hv + 1) ||
772+
bms_is_fault_set(d->bms_fault, CELL_HARD_OVER_VOLTAGE)) {
753773
// 500ms have passed or voltage is another volt higher, time for some tiltback
754774
if (d->motor.erpm > 0) {
755775
d->setpoint_target = d->float_conf.tiltback_hv_angle;
@@ -792,17 +812,50 @@ static void calculate_setpoint_target(data *d) {
792812
// The rider has 1 degree Celsius left before we start tilting back
793813
d->state.sat = SAT_NONE;
794814
}
795-
} else if (d->motor.duty_cycle > 0.05 && input_voltage < d->float_conf.tiltback_lv) {
815+
} else if (bms_is_fault_set(d->bms_fault, CELL_SOFT_OVER_TEMP) ||
816+
bms_is_fault_set(d->bms_fault, CELL_HARD_OVER_TEMP) ||
817+
bms_is_fault_set(d->bms_fault, CELL_SOFT_UNDER_TEMP) ||
818+
bms_is_fault_set(d->bms_fault, CELL_HARD_UNDER_TEMP) ||
819+
bms_is_fault_set(d->bms_fault, BMS_SOFT_OVER_TEMP) ||
820+
bms_is_fault_set(d->bms_fault, BMS_HARD_OVER_TEMP)) {
821+
// Use the angle from Low-Voltage tiltback, but slower speed from High-Voltage tiltback
822+
beep_alert(d, 3, true);
823+
if (bms_is_fault_set(d->bms_fault, CELL_SOFT_OVER_TEMP) ||
824+
bms_is_fault_set(d->bms_fault, CELL_HARD_OVER_TEMP)) {
825+
d->beep_reason = BEEP_TEMP_CELL_OVER;
826+
} else if (bms_is_fault_set(d->bms_fault, CELL_SOFT_UNDER_TEMP) ||
827+
bms_is_fault_set(d->bms_fault, CELL_HARD_UNDER_TEMP)) {
828+
d->beep_reason = BEEP_TEMP_CELL_UNDER;
829+
} else {
830+
d->beep_reason = BEEP_BMS_TEMP;
831+
}
832+
if (d->motor.erpm > 0) {
833+
d->setpoint_target = d->float_conf.tiltback_lv_angle;
834+
} else {
835+
d->setpoint_target = -d->float_conf.tiltback_lv_angle;
836+
}
837+
d->state.sat = SAT_PB_TEMPERATURE;
838+
} else if (d->motor.duty_cycle > 0.05 &&
839+
(input_voltage < d->float_conf.tiltback_lv ||
840+
bms_is_fault_set(d->bms_fault, CELL_SOFT_UNDER_VOLTAGE) ||
841+
bms_is_fault_set(d->bms_fault, CELL_HARD_UNDER_VOLTAGE))) {
796842
beep_alert(d, 3, false);
797-
d->beep_reason = BEEP_LV;
843+
if (bms_is_fault_set(d->bms_fault, CELL_SOFT_UNDER_VOLTAGE) ||
844+
bms_is_fault_set(d->bms_fault, CELL_HARD_UNDER_VOLTAGE)) {
845+
d->beep_reason = BEEP_CELL_LV;
846+
} else {
847+
d->beep_reason = BEEP_LV;
848+
}
798849
float abs_motor_current = fabsf(d->motor.current);
799850
float vdelta = d->float_conf.tiltback_lv - input_voltage;
800851
float ratio = vdelta * 20 / abs_motor_current;
801852
// When to do LV tiltback:
802853
// a) we're 2V below lv threshold
803854
// b) motor current is small (we cannot assume vsag)
804855
// c) we have more than 20A per Volt of difference (we tolerate some amount of vsag)
805-
if ((vdelta > 2) || (abs_motor_current < 5) || (ratio > 1)) {
856+
if ((vdelta > 2) || (abs_motor_current < 5) || (ratio > 1) ||
857+
bms_is_fault_set(d->bms_fault, CELL_SOFT_UNDER_VOLTAGE) ||
858+
bms_is_fault_set(d->bms_fault, CELL_HARD_UNDER_VOLTAGE)) {
806859
if (d->motor.erpm > 0) {
807860
d->setpoint_target = d->float_conf.tiltback_lv_angle;
808861
} else {
@@ -2582,6 +2635,14 @@ static lbm_value ext_set_fw_version(lbm_value *args, lbm_uint argn) {
25822635
return VESC_IF->lbm_enc_sym_true;
25832636
}
25842637

2638+
// Called from Lisp to pass in the fault code of the bms.
2639+
static lbm_value ext_bms_set_fault(lbm_value *args, lbm_uint argn) {
2640+
unused(argn);
2641+
data *d = (data *) ARG;
2642+
d->bms_fault = VESC_IF->lbm_dec_as_u32(args[0]);
2643+
return VESC_IF->lbm_enc_sym_true;
2644+
}
2645+
25852646
// Used to send the current or default configuration to VESC Tool.
25862647
static int get_cfg(uint8_t *buffer, bool is_default) {
25872648
data *d = (data *) ARG;
@@ -2701,6 +2762,7 @@ INIT_FUN(lib_info *info) {
27012762
VESC_IF->set_app_data_handler(on_command_received);
27022763
VESC_IF->lbm_add_extension("ext-dbg", ext_dbg);
27032764
VESC_IF->lbm_add_extension("ext-set-fw-version", ext_set_fw_version);
2765+
VESC_IF->lbm_add_extension("ext-bms-set-fault", ext_bms_set_fault);
27042766

27052767
return true;
27062768
}

Diff for: src/utils.c

+7
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,10 @@ float clampf(float value, float min, float max) {
3737
const float m = value < min ? min : value;
3838
return m > max ? max : m;
3939
}
40+
41+
bool bms_is_fault_set(uint32_t fault_mask, BMS_FAULT_CODES fault_code) {
42+
if (fault_code < 1 || fault_code > 32) {
43+
return false;
44+
}
45+
return (fault_mask & (1U << (fault_code - 1))) != 0;
46+
}

Diff for: src/utils.h

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#pragma once
1919

20+
#include "conf/datatypes.h"
2021
#include "vesc_c_if.h"
2122

2223
#include <stdint.h>
@@ -118,3 +119,5 @@ float clampf(float value, float min, float max);
118119
* @param step A maximum unit of change of @p value.
119120
*/
120121
void rate_limitf(float *value, float target, float step);
122+
123+
bool bms_is_fault_set(uint32_t fault_mask, BMS_FAULT_CODES fault_code);

Diff for: ui.qml.in

+7
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,13 @@ Item {
867867
[8, "Low Battery"],
868868
[9, "Board Idle"],
869869
[10, "Other"],
870+
[11, "Cell Under Temp"],
871+
[12, "Cell Over Temp"],
872+
[13, "Cell Low Voltage"],
873+
[14, "Cell High Voltage"],
874+
[15, "Cell Balance"],
875+
[16, "BMS Connection"],
876+
[17, "BMS Temp"],
870877
])
871878

872879
property int beepReason: 0

0 commit comments

Comments
 (0)