-
Notifications
You must be signed in to change notification settings - Fork 7
/
g30_dash.lisp
433 lines (383 loc) · 13 KB
/
g30_dash.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
; G30 dashboard compability lisp script v1.0 by AKA13 and 1zuna
; UART Wiring: red=5V black=GND yellow=COM-TX (UART-HDX) green=COM-RX (button)+3.3V with 1K Resistor
; Guide (German): https://rollerplausch.com/threads/vesc-controller-einbau-1s-pro2-g30.6032/
; Tested on VESC 6.05 on G30D w/ MKS 84100HP and MP2 300A VESC
; -> User parameters (change these to your needs)
(def software-adc 1)
(def min-adc-throttle 0.1)
(def min-adc-brake 0.1)
(def show-batt-in-idle 1)
(def min-speed 1)
(def button-safety-speed (/ 0.1 3.6)) ; disabling button above 0.1 km/h (due to safety reasons)
; Speed modes (km/h, watts, current scale)
(def eco-speed (/ 7 3.6))
(def eco-current 0.6)
(def eco-watts 400)
(def eco-fw 0)
(def drive-speed (/ 17 3.6))
(def drive-current 0.7)
(def drive-watts 500)
(def drive-fw 0)
(def sport-speed (/ 21 3.6))
(def sport-current 1.0)
(def sport-watts 700)
(def sport-fw 0)
; Secret speed modes. To enable, press the button 2 times while holding break and throttle at the same time.
(def secret-enabled 1)
(def secret-eco-speed (/ 27 3.6))
(def secret-eco-current 0.8)
(def secret-eco-watts 1200)
(def secret-eco-fw 0)
(def secret-drive-speed (/ 47 3.6))
(def secret-drive-current 0.9)
(def secret-drive-watts 1500)
(def secret-drive-fw 0)
(def secret-sport-speed (/ 1000 3.6)) ; 1000 km/h easy
(def secret-sport-current 1.0)
(def secret-sport-watts 1500000)
(def secret-sport-fw 10)
; -> Code starts here (DO NOT CHANGE ANYTHING BELOW THIS LINE IF YOU DON'T KNOW WHAT YOU ARE DOING)
; Load VESC CAN code serer
(import "pkg@://vesc_packages/lib_code_server/code_server.vescpkg" 'code-server)
(read-eval-program code-server)
; Packet handling
(uart-start 115200 'half-duplex)
(gpio-configure 'pin-rx 'pin-mode-in-pu)
(define tx-frame (array-create 15))
(bufset-u16 tx-frame 0 0x5AA5) ;Ninebot protocol
(bufset-u8 tx-frame 2 0x06) ;Payload length is 5 bytes
(bufset-u16 tx-frame 3 0x2021) ; Packet is from ESC to BLE
(bufset-u16 tx-frame 5 0x6400) ; Packet is from ESC to BLE
(def uart-buf (array-create 64))
; Button handling
(def presstime (systime))
(def presses 0)
; Mode states
(def off 0)
(def lock 0)
(def speedmode 4)
(def light 0)
(def unlock 0)
; Sound feedback
(def feedback 0)
(if (= software-adc 1)
(app-adc-detach 3 1)
(app-adc-detach 3 0)
)
(defun adc-input(buffer) ; Frame 0x65
{
(let ((current-speed (* (get-speed) 3.6))
(throttle (/(bufget-u8 uart-buf 5) 77.2)) ; 255/3.3 = 77.2
(brake (/(bufget-u8 uart-buf 6) 77.2)))
{
(if (< throttle 0)
(setf throttle 0))
(if (> throttle 3.3)
(setf throttle 3.3))
(if (< brake 0)
(setf brake 0))
(if (> brake 3.3)
(setf brake 3.3))
; Pass through throttle and brake to VESC
(app-adc-override 0 throttle)
(app-adc-override 1 brake)
}
)
}
)
(defun handle-features()
{
(if (or (or (= off 1) (= lock 1) (< (* (get-speed) 3.6) min-speed)))
(if (not (app-is-output-disabled)) ; Disable output when scooter is turned off
{
(app-adc-override 0 0)
(app-adc-override 1 0)
(app-disable-output -1)
(set-current 0)
;(loopforeach i (can-list-devs)
; (canset-current i 0)
;)
}
)
(if (app-is-output-disabled) ; Enable output when scooter is turned on
(app-disable-output 0)
)
)
(if (= lock 1)
{
(set-current-rel 0) ; No current input when locked
(if (> (* (get-speed) 3.6) min-speed)
(set-brake-rel 1) ; Full power brake
(set-brake-rel 0) ; No brake
)
}
)
}
)
(defun update-dash(buffer) ; Frame 0x64
{
(var current-speed (* (l-speed) 3.6))
(var battery (*(get-batt) 100))
; mode field (1=drive, 2=eco, 4=sport, 8=charge, 16=off, 32=lock)
(if (= off 1)
(bufset-u8 tx-frame 7 16)
(if (= lock 1)
(bufset-u8 tx-frame 7 32) ; lock display
(if (or (> (get-temp-fet) 60) (> (get-temp-mot) 60)) ; temp icon will show up above 60 degree
(bufset-u8 tx-frame 7 (+ 128 speedmode))
(bufset-u8 tx-frame 7 speedmode)
)
)
)
; batt field
(bufset-u8 tx-frame 8 battery)
; light field
(if (= off 0)
(bufset-u8 tx-frame 9 light)
(bufset-u8 tx-frame 9 0)
)
; beep field
(if (= lock 1)
(if (> current-speed min-speed)
(bufset-u8 tx-frame 10 1) ; beep lock
(bufset-u8 tx-frame 10 0))
(if (> feedback 0)
{
(bufset-u8 tx-frame 10 1)
(set 'feedback (- feedback 1))
}
(bufset-u8 tx-frame 10 0)
)
)
; speed field
(if (= (+ show-batt-in-idle unlock) 2)
(if (> current-speed 1)
(bufset-u8 tx-frame 11 current-speed)
(bufset-u8 tx-frame 11 battery))
(bufset-u8 tx-frame 11 current-speed)
)
; error field
(bufset-u8 tx-frame 12 (get-fault))
; calc crc
(var crcout 0)
(looprange i 2 13
(set 'crcout (+ crcout (bufget-u8 tx-frame i))))
(set 'crcout (bitwise-xor crcout 0xFFFF))
(bufset-u8 tx-frame 13 crcout)
(bufset-u8 tx-frame 14 (shr crcout 8))
; write
(uart-write tx-frame)
}
)
(defun read-frames()
(loopwhile t
{
(uart-read-bytes uart-buf 3 0)
(if (= (bufget-u16 uart-buf 0) 0x5aa5)
{
(var len (bufget-u8 uart-buf 2))
(var crc len)
(if (and (> len 0) (< len 60)) ; max 64 bytes
{
(uart-read-bytes uart-buf (+ len 6) 0) ;read remaining 6 bytes + payload, overwrite buffer
(let ((code (bufget-u8 uart-buf 2)) (checksum (bufget-u16 uart-buf (+ len 4))))
{
(looprange i 0 (+ len 4) (set 'crc (+ crc (bufget-u8 uart-buf i))))
(if (= checksum (bitwise-and (+ (shr (bitwise-xor crc 0xFFFF) 8) (shl (bitwise-xor crc 0xFFFF) 8)) 65535)) ;If the calculated checksum matches with sent checksum, forward comman
(handle-frame code)
)
}
)
}
)
}
)
}
)
)
(defun handle-frame(code)
{
(if (and (= code 0x65) (= software-adc 1))
(adc-input uart-buf)
)
(if(= code 0x64)
(update-dash uart-buf)
)
}
)
(defun handle-button()
(if (= presses 1) ; single press
(if (= off 1) ; is it off? turn on scooter again
{
(set 'off 0) ; turn on
(set 'feedback 1) ; beep feedback
(set 'unlock 0) ; Disable unlock on turn off
(apply-mode) ; Apply mode on start-up
(stats-reset) ; reset stats when turning on
}
(set 'light (bitwise-xor light 1)) ; toggle light
)
(if (>= presses 2) ; double press
{
(if (> (get-adc-decoded 1) min-adc-brake) ; if brake is pressed
(if (and (= secret-enabled 1) (> (get-adc-decoded 0) min-adc-throttle))
{
(set 'unlock (bitwise-xor unlock 1))
(set 'feedback 2) ; beep 2x
(apply-mode)
}
{
(set 'unlock 0)
(apply-mode)
(set 'lock (bitwise-xor lock 1)) ; lock on or off
(set 'feedback 1) ; beep feedback
}
)
{
(if (= lock 0)
{
(cond
((= speedmode 1) (set 'speedmode 4))
((= speedmode 2) (set 'speedmode 1))
((= speedmode 4) (set 'speedmode 2))
)
(apply-mode)
}
)
}
)
}
)
)
)
(defun handle-holding-button()
{
(if (= (+ lock off) 0) ; it is locked and off?
{
(set 'unlock 0) ; Disable unlock on turn off
(apply-mode)
(set 'off 1) ; turn off
(set 'light 0) ; turn off light
(set 'feedback 1) ; beep feedback
}
)
}
)
(defun reset-button()
{
(set 'presstime (systime)) ; reset press time again
(set 'presses 0)
}
)
; Speed mode implementation
(defun apply-mode()
(if (= unlock 0)
(if (= speedmode 1)
(configure-speed drive-speed drive-watts drive-current drive-fw)
(if (= speedmode 2)
(configure-speed eco-speed eco-watts eco-current eco-fw)
(if (= speedmode 4)
(configure-speed sport-speed sport-watts sport-current sport-fw)
)
)
)
(if (= speedmode 1)
(configure-speed secret-drive-speed secret-drive-watts secret-drive-current secret-drive-fw)
(if (= speedmode 2)
(configure-speed secret-eco-speed secret-eco-watts secret-eco-current secret-eco-fw)
(if (= speedmode 4)
(configure-speed secret-sport-speed secret-sport-watts secret-sport-current secret-sport-fw)
)
)
)
)
)
(defun configure-speed(speed watts current fw)
{
(set-param 'max-speed speed)
(set-param 'l-watt-max watts)
(set-param 'l-current-max-scale current)
(set-param 'foc-fw-current-max fw)
}
)
(defun set-param (param value)
{
(conf-set param value)
(loopforeach id (can-list-devs)
(looprange i 0 5 {
(if (eq (rcode-run id 0.1 `(conf-set (quote ,param) ,value)) t) (break t))
false
})
)
}
)
(defun l-speed()
{
(var l-speed (get-speed))
(loopforeach i (can-list-devs)
{
(var l-can-speed (canget-speed i))
(if (< l-can-speed l-speed)
(set 'l-speed l-can-speed)
)
}
)
l-speed
}
)
(defun button-logic()
{
; Assume button is not pressed by default
(var buttonold 0)
(loopwhile t
{
(var button (gpio-read 'pin-rx))
(sleep 0.05) ; wait 50 ms to debounce
(var buttonconfirm (gpio-read 'pin-rx))
(if (not (= button buttonconfirm))
(set 'button 0)
)
(if (> buttonold button)
{
(set 'presses (+ presses 1))
(set 'presstime (systime))
}
(button-apply button)
)
(set 'buttonold button)
(handle-features)
}
)
}
)
(defun button-apply(button)
{
(var time-passed (- (systime) presstime))
(var is-active (or (= off 1) (<= (get-speed) button-safety-speed)))
(if (> time-passed 2500) ; after 2500 ms
(if (= button 0) ; check button is still pressed
(if (> time-passed 6000) ; long press after 6000 ms
{
(if is-active
(handle-holding-button)
)
(reset-button) ; reset button
}
)
(if (> presses 0) ; if presses > 0
{
(if is-active
(handle-button) ; handle button presses
)
(reset-button) ; reset button
}
)
)
)
}
)
; Apply mode on start-up
(apply-mode)
; Spawn UART reading frames thread
(spawn 150 read-frames)
(button-logic) ; Start button logic in main thread - this will block the main thread