91 Commits
master ... main

Author SHA1 Message Date
efb438bf51 Exit MULTI_MODE_DRIVE if inputs are not calibrated
- Timeout: 3 seconds
2023-01-08 17:16:33 +01:00
e5f7e9457a Update README.md 2022-12-07 07:53:44 +01:00
24b3d2515f Update README.md 2022-10-15 16:03:09 +02:00
a6430e3a3e HOVERCAR: improved MULTI_MODE
- improved MULTI_MODE by adding torque and speed limits
  - BEGINNER MODE: Power ON + Brake [released] + Throttle [released or pressed]
  - INTERMEDIATE MODE: Power ON + Brake [pressed] + Throttle [released]
  - ADVANCED MODE: Power ON + Brake [pressed] + Throttle [pressed]
- made Voltage mode as default for hovercar (better for toddlers)
- made MULTI_MODE_DRIVE active as default
2022-08-15 18:30:29 +02:00
5aa85d9af0 Update README.md 2022-07-04 08:59:26 +02:00
dbc485bbf4 Update README.md 2022-06-16 14:19:37 +02:00
4c0861e9de Merge pull request #309 from Guruth/MultiModeHoverCar
Multiple Drive Modes for Hovercar variant
2022-06-05 14:55:27 +02:00
5505a71260 Minor styling 2022-06-05 14:52:09 +02:00
cb7f3e9183 Removed speed from logging 2022-05-22 20:41:21 +02:00
87f9d4e8a3 Moved rate, max_speed initialization out of the drive loop 2022-05-22 20:37:09 +02:00
6b2cf03ef1 Disabled MULTI_MODE_DRIVE by default 2022-05-22 11:48:03 +02:00
4ef368330d Fixed Trigger released check for MultiModeDrive
(cherry picked from commit 2a2e2a2091494e8257b5e558077ca7a3c2ac575f)
2022-05-22 11:40:22 +02:00
873fc8ea14 Added Multi Mode Drive
(cherry picked from commit 0167a1d81cf0eaaebc7196e2fcf7120a13438f4d)
2022-05-22 11:15:04 +02:00
4b16b64771 Replaced by yml form 2022-05-06 15:47:15 +02:00
f18eec5ac1 Replaced by yml form 2022-05-06 15:46:52 +02:00
7e6a65199c Replaced by yml form 2022-05-06 15:46:19 +02:00
c7aa31b66c Merge pull request #293 from Candas1/master
Fixes and improvements
2022-05-06 15:34:50 +02:00
12cc722cef Fixes 2022-04-30 13:53:49 +02:00
29535a26e6 Update util.c 2022-04-25 21:31:14 +02:00
31326ad158 Update comms.c 2022-04-25 21:21:52 +02:00
ac489d51e6 Update question-about-the-firmware.yaml 2022-04-25 21:17:41 +02:00
2fbeb1fca4 Update idea---feature-request.yaml 2022-04-25 21:16:55 +02:00
5612af0a90 Fix average speed 2022-04-25 21:11:55 +02:00
bb119d7a38 Fixes and improvements 2022-03-29 21:43:07 +02:00
39a59e0870 Merge branch 'EFeru:master' into master 2022-03-29 21:38:34 +02:00
bd4a34dabf Updated links 2022-03-29 17:30:17 +02:00
b5c6fa0a67 Revert "Changed configuration"
This reverts commit bcf3656e95.
2022-03-24 10:12:25 +01:00
0057cff9a1 Update config.yml 2022-03-23 13:18:34 +01:00
3a5cd3331c Update config.yml 2022-03-23 13:12:45 +01:00
be6ac57c76 Update config.yml 2022-03-23 13:06:12 +01:00
baf4a1e691 Create config.yml 2022-03-23 13:02:39 +01:00
faae9f9033 Update bug_report.yaml 2022-03-23 12:59:49 +01:00
6a72b03c41 Update question-about-the-firmware.yaml 2022-03-23 12:45:01 +01:00
7c247cee4c Update bug_report.yaml 2022-03-23 12:43:58 +01:00
22b1c76c97 Update idea---feature-request.yaml 2022-03-23 12:42:21 +01:00
2b0a4ea7de Update idea---feature-request.yaml 2022-03-23 12:41:41 +01:00
8cadd430c5 Update idea---feature-request.yaml 2022-03-23 12:40:16 +01:00
ae492d1e09 Update idea---feature-request.yaml 2022-03-23 12:39:59 +01:00
99f36738ce Update bug_report.yaml 2022-03-23 12:38:52 +01:00
5001ed5563 Update bug_report.yaml 2022-03-23 12:36:16 +01:00
4bd75c59ec Update bug_report.yaml 2022-03-23 12:35:42 +01:00
453b048382 Update question-about-the-firmware.yaml 2022-03-23 12:14:02 +01:00
4cd8421fa4 Update idea---feature-request.yaml 2022-03-23 12:13:45 +01:00
77bf95771b Update bug_report.yaml 2022-03-23 12:12:56 +01:00
9522c4b325 Update question-about-the-firmware.yaml 2022-03-23 11:15:22 +01:00
81c5a0dd44 Create idea---feature-request.yaml 2022-03-23 11:14:35 +01:00
dfb95cd522 Create question-about-the-firmware.yaml 2022-03-23 11:06:22 +01:00
785f64778a Update bug_report.yaml 2022-03-23 10:58:41 +01:00
124f3d046a Update bug_report.yaml 2022-03-23 10:57:53 +01:00
837fd02990 Update bug_report.yaml 2022-03-23 10:55:58 +01:00
ac33240d20 Update bug_report.yaml 2022-03-23 10:54:14 +01:00
e9eb7fa720 Update bug_report.yaml 2022-03-23 10:53:27 +01:00
33eae7e24b Update and rename wiki.md to bug_report.yaml 2022-03-23 10:52:33 +01:00
eb784bcf3b Create wiki.md 2022-03-23 10:36:01 +01:00
34ec8d8e92 Merge branch 'EFeru:master' into master 2022-03-23 10:11:46 +01:00
18d406982e Update bug_report.md 2022-03-23 09:07:43 +01:00
08880f4823 Update idea---feature-request.md 2022-03-23 09:07:03 +01:00
88fd069c60 Update question-about-the-firmware.md 2022-03-23 09:06:14 +01:00
ef990ed5e7 Update idea---feature-request.md 2022-03-23 09:03:40 +01:00
f38e97d135 Update bug_report.md 2022-03-23 09:00:49 +01:00
bcf3656e95 Changed configuration 2022-03-08 19:54:52 +01:00
2f6d1f191f Merge pull request #269 from Candas1/master
Build for all branches
2022-03-08 18:38:16 +01:00
b02cded3b0 Using carlosperate action, it should cache gcc 2022-03-08 10:39:16 +01:00
b3a3d904f2 Fix 2022-03-08 09:38:43 +01:00
9aa2dcf725 Trying compile on commit for all branches 2022-03-08 09:37:18 +01:00
8ee426e335 Merge branch 'EFeru:master' into master 2022-03-06 18:19:48 +01:00
7bb9a4b3f0 Merge pull request #268 from EFeru/test-gihub-actions
Create build_on_commit.yml
2022-03-06 14:22:53 +01:00
ff42d9787e Create build_on_commit.yml
Update build_on_commit.yml

Update build_on_commit.yml

Update build_on_commit.yml

Update build_on_commit.yml

Removed Travis

Upload build artifact

Updated build artifact

Update build_on_commit.yml

Update build_on_commit.yml

Create download_build.png
2022-03-06 14:17:12 +01:00
4441847569 Added wiki links in the Contents 2022-03-06 13:55:21 +01:00
bf60799358 Added webview link 2022-03-06 11:45:39 +01:00
9d9501ad97 Fix: field weakening #164 2022-03-06 11:43:50 +01:00
79bf9ef768 Merge branch 'EFeru:master' into master 2022-03-04 18:08:34 +01:00
d97ec61c03 Merge pull request #260 from sdegeorgio/master
Reworked the Wii nunchuck driver to make it much more robust.
2022-03-04 08:31:47 +01:00
50704b3395 Reworked the Wii nunchuck driver to make it much more robust. New features now include:
* Nunchuck can be hot-plugged
  * Recovery is made from bad or lost communication
  * Nunchuck checked to see if it is initialised (check for all 0x00 or 0xFF) and values
    ignored if not to avoid motor glitches
  * Initialisation of I2C is made more reliable following guidance of other STM32 users on the web, i.e.
    force restart of peripheral after GPIO pin initialisation
2022-02-06 12:05:59 +00:00
39b98cc0c0 Merge branch 'EFeru:master' into master 2022-01-06 12:43:21 +01:00
4770b13b2c Update README.md 2022-01-02 20:46:51 +01:00
5470f0f63c Update README.md 2022-01-02 18:18:45 +01:00
ddadcb9d70 Update README.md 2022-01-01 14:39:14 +01:00
c71c102bc2 Fix #247 2022-01-01 13:47:42 +01:00
669d227898 Merge branch 'master' into pr/250 2022-01-01 12:53:30 +01:00
b840051037 Update README.md
Moved last phrase in the wiki.
2022-01-01 12:47:01 +01:00
91f2d4c4d5 Merge pull request #195 from fluppie/master
Add CH7, CH8, CH9 & CH10 text to RC Transm. image
2022-01-01 12:19:51 +01:00
0504b10de5 Updated source pptx 2022-01-01 12:14:50 +01:00
f1139d1b66 Update README.md 2021-12-31 17:05:24 +01:00
5da9966f8c various new ideas in README.md. Making hoverserial start from zero speed and highlighting that it will trigger backward beeps. 2021-12-29 19:01:30 +02:00
cf7b1d0de1 Update README.md 2021-11-29 20:36:30 +01:00
928a86b86b Update README.md 2021-09-02 16:15:43 +02:00
7d9d822342 Update README.md 2021-08-19 20:32:51 +02:00
ba2af41fa8 Add CH7, CH8, CH9 & CH10 text to RC Transm. image
Make sure people know to configure the AUX channels on their RC transmitter...
2021-07-21 01:03:58 +02:00
eb20cc0aca Added issue templates 2021-05-16 15:27:16 +02:00
48c5474057 Merge pull request #2 from EmanuelFeru/master
Merge pull request #150 from Candas1/master
2021-04-06 22:26:04 +02:00
22 changed files with 753 additions and 463 deletions

54
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View File

@ -0,0 +1,54 @@
name: 🐞 Bug report
description: Create a report to help us improve
labels: "bug"
body:
- type: markdown
attributes:
value: "**Please check the [Wiki](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki), it contains tips for troubleshooting**"
- type: dropdown
attributes:
label: Variant
description: What variant of the firmware are you using?
multiple: false
options:
- ADC
- USART
- NUNCHUK
- PPM
- PWM
- IBUS
- HOVERCAR
- TRANSPOTTER
- SKATEBOARD
- HOVERBOARD
validations:
required: true
- type: dropdown
attributes:
label: Control type
description: What Control type are you using?
multiple: false
options:
- Commutation
- Sinusoidale
- FOC
validations:
required: true
- type: dropdown
attributes:
label: Control mode
description: What Control mode are you using?
multiple: false
options:
- Voltage
- Speed
- Torque
validations:
required: true
- type: textarea
attributes:
label: What is the bug and how to reproduce it ?
placeholder: Describe the bug and how to reproduce it
validations:
required: true

9
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,9 @@
blank_issues_enabled: false
contact_links:
- name: Wiki Pages
url: https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki
about: Please check the Wiki first
- name: 💬 Telegram Community
url: https://t.me/joinchat/BHWO_RKu2LT5ZxEkvUB8uw
about: Connect with the Telegram Community

View File

@ -0,0 +1,60 @@
name: 🚀 Idea / Feature request
description: Suggest an idea for this project
labels: "enhancement"
body:
- type: markdown
attributes:
value: "**Please check the [Wiki](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki) for existing features**"
- type: dropdown
attributes:
label: Variant
description: What variant of the firmware are you using?
multiple: false
options:
- ADC
- USART
- NUNCHUK
- PPM
- PWM
- IBUS
- HOVERCAR
- TRANSPOTTER
- SKATEBOARD
- HOVERBOARD
validations:
required: false
- type: dropdown
attributes:
label: Control type
description: What Control type are you using?
multiple: false
options:
- Commutation
- Sinusoidale
- FOC
validations:
required: false
- type: dropdown
attributes:
label: Control mode
description: What Control mode are you using?
multiple: false
options:
- Voltage
- Speed
- Torque
validations:
required: false
- type: textarea
attributes:
label: What can we do to make the firmware better?
placeholder: Consider if code examples or images would help communicate your request
validations:
required: true
- type: textarea
attributes:
label: Describe suggestions or alternatives you have considered
placeholder: A clear and concise description of any alternative solutions or features you've considered
validations:
required: true

View File

@ -0,0 +1,54 @@
name: ❓ Question about the firmware
description: How to use the firmware to...
labels: "question"
body:
- type: markdown
attributes:
value: "**Please check the [Wiki](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki), it might already contain an answer to your question**"
- type: dropdown
attributes:
label: Variant
description: What variant of the firmware are you using?
multiple: false
options:
- ADC
- USART
- NUNCHUK
- PPM
- PWM
- IBUS
- HOVERCAR
- TRANSPOTTER
- SKATEBOARD
- HOVERBOARD
validations:
required: false
- type: dropdown
attributes:
label: Control type
description: What Control type are you using?
multiple: false
options:
- Commutation
- Sinusoidale
- FOC
validations:
required: false
- type: dropdown
attributes:
label: Control mode
description: What Control mode are you using?
multiple: false
options:
- Voltage
- Speed
- Torque
validations:
required: false
- type: textarea
attributes:
label: Description
placeholder: If applicable, indicate what you tried that doesn't work
validations:
required: true

41
.github/workflows/build_on_commit.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: Build
on:
push:
branches: [ '*' ]
pull_request:
branches: [ '*' ]
jobs:
build:
runs-on: ubuntu-latest
steps:
# Get required packages
- uses: actions/checkout@v2
- uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
release: '9-2019-q4'
# Build with make
- name: make
env:
VARIANT: VARIANT_ADC
run: make
# Build with Platformio
- name: PlatformIO Install
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: PlatformIO Run
run: pio run
- name: 'Upload Build Artifact'
uses: actions/upload-artifact@v3
with:
path: ${{github.workspace}}/.pio/build/**
name: ${{github.event.repository.name}}_build_${{github.run_number}}
retention-days: 5

View File

@ -1,55 +0,0 @@
notifications:
email: true
os: linux
jobs:
fast_finish: true
include:
- name: make (gcc-arm-none-eabi-7)
script: make
env: VARIANT=VARIANT_ADC
language: c
addons:
apt:
packages:
- libc6-i386
install:
- pushd .
- cd ~
- mkdir arm-gcc-toolchain
- wget -O $HOME/arm-gcc-toolchain/gcc.tar.bz2 https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2018q2/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2?revision=bc2c96c0-14b5-4bb4-9f18-bceb4050fee7?product=GNU%20Arm%20Embedded%20Toolchain,64-bit,,Linux,7-2018-q2-update
- cd arm-gcc-toolchain
- tar -jxf gcc.tar.bz2 --strip=1
- popd
- export PATH=$HOME/arm-gcc-toolchain/bin:$PATH
before_script: arm-none-eabi-gcc --version
- name: make (gcc-arm-none-eabi-5)
script: make
env: VARIANT=VARIANT_ADC
language: c
addons:
apt:
packages:
- libc6-i386
install:
- pushd .
- cd ~
- mkdir arm-gcc-toolchain
- wget -O $HOME/arm-gcc-toolchain/gcc.tar.bz2 https://developer.arm.com/-/media/Files/downloads/gnu-rm/5_4-2016q3/gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2?revision=111dee36-f88b-4672-8ac6-48cf41b4d375?product=GNU%20Arm%20Embedded%20Toolchain,32-bit,,Linux,5-2016-q3-update
- cd arm-gcc-toolchain
- tar -jxf gcc.tar.bz2 --strip=1
- popd
- export PATH=$HOME/arm-gcc-toolchain/bin:$PATH
before_script: arm-none-eabi-gcc --version
- name: platformio
script: platformio run
language: python
install:
- pip install -U platformio
- platformio update
cache:
- directories: "~/.platformio"

View File

@ -11,6 +11,8 @@
// it is recommended to use the built-in Serial interface for full speed perfomace.
// • The data packaging includes a Start Frame, checksum, and re-syncronization capability for reliable communication
//
// The code starts with zero speed and moves towards +
//
// CONFIGURATION on the hoverboard side in config.h:
// • Option 1: Serial on Right Sensor cable (short wired cable) - recommended, since the USART3 pins are 5V tolerant.
// #define CONTROL_SERIAL_USART3
@ -28,6 +30,7 @@
#define START_FRAME 0xABCD // [-] Start frme definition for reliable serial communication
#define TIME_SEND 100 // [ms] Sending time interval
#define SPEED_MAX_TEST 300 // [-] Maximum speed for testing
#define SPEED_STEP 20 // [-] Speed step
// #define DEBUG_RX // [-] Debug received data. Prints all bytes to serial (comment-out to disable)
#include <SoftwareSerial.h>
@ -146,8 +149,8 @@ void Receive()
// ########################## LOOP ##########################
unsigned long iTimeSend = 0;
int iTestMax = SPEED_MAX_TEST;
int iTest = 0;
int iStep = SPEED_STEP;
void loop(void)
{
@ -159,11 +162,14 @@ void loop(void)
// Send commands
if (iTimeSend > timeNow) return;
iTimeSend = timeNow + TIME_SEND;
Send(0, SPEED_MAX_TEST - 2*abs(iTest));
Send(0, iTest);
// Calculate test command signal
iTest += 10;
if (iTest > iTestMax) iTest = -iTestMax;
iTest += iStep;
// invert step if reaching limit
if (iTest >= SPEED_MAX_TEST || iTest <= -SPEED_MAX_TEST)
iStep = -iStep;
// Blink the LED
digitalWrite(LED_BUILTIN, (timeNow%2000)<1000);

View File

@ -3,9 +3,9 @@
*
* Code generated for Simulink model 'BLDC_controller'.
*
* Model version : 1.1296
* Model version : 1.1297
* Simulink Coder version : 8.13 (R2017b) 24-Jul-2017
* C/C++ source code generated on : Tue Oct 20 17:29:57 2020
* C/C++ source code generated on : Sun Mar 6 11:02:11 2022
*
* Target selection: ert.tlc
* Embedded hardware selection: ARM Compatible->ARM Cortex

View File

@ -78,6 +78,7 @@
#define BAT_CELLS 10 // battery number of cells. Normal Hoverboard battery: 10s
#define BAT_LVL2_ENABLE 0 // to beep or not to beep, 1 or 0
#define BAT_LVL1_ENABLE 1 // to beep or not to beep, 1 or 0
#define BAT_DEAD_ENABLE 1 // to poweroff or not to poweroff, 1 or 0
#define BAT_BLINK_INTERVAL 80 // battery led blink interval (80 loops * 5ms ~= 400ms)
#define BAT_LVL5 (390 * BAT_CELLS * BAT_CALIB_ADC) / BAT_CALIB_REAL_VOLTAGE // Green blink: no beep
#define BAT_LVL4 (380 * BAT_CELLS * BAT_CALIB_ADC) / BAT_CALIB_REAL_VOLTAGE // Yellow: no beep
@ -299,6 +300,7 @@
#define DEBUG_SERIAL_USART3 // right sensor board cable, disable if I2C (nunchuk or lcd) is used!
#endif
// #define TANK_STEERING // use for tank steering, each input controls each wheel
// #define ADC_ALTERNATE_CONNECT // use to swap ADC inputs
// #define SUPPORT_BUTTONS_LEFT // use left sensor board cable for button inputs. Disable DEBUG_SERIAL_USART2!
// #define SUPPORT_BUTTONS_RIGHT // use right sensor board cable for button inputs. Disable DEBUG_SERIAL_USART3!
@ -316,7 +318,7 @@
// #define SIDEBOARD_SERIAL_USART3 0
// #define CONTROL_SERIAL_USART3 0 // right sensor board cable. Number indicates priority for dual-input. Disable if I2C (nunchuk or lcd) is used! For Arduino control check the hoverSerial.ino
// #define FEEDBACK_SERIAL_USART3 // right sensor board cable, disable if I2C (nunchuk or lcd) is used!
// #define DUAL_INPUTS // UART*(Primary) + SIDEBOARD(Auxiliary). Uncomment this to use Dual-inputs
#define PRI_INPUT1 3, -1000, 0, 1000, 0 // TYPE, MIN, MID, MAX, DEADBAND. See INPUT FORMAT section
#define PRI_INPUT2 3, -1000, 0, 1000, 0 // TYPE, MIN, MID, MAX, DEADBAND. See INPUT FORMAT section
@ -330,6 +332,7 @@
#define FLASH_WRITE_KEY 0x1002 // Flash memory writing key. Change this key to ignore the input calibrations from the flash memory and use the ones in config.h
#endif
// #define TANK_STEERING // use for tank steering, each input controls each wheel
// #define SUPPORT_BUTTONS_LEFT // use left sensor board cable for button inputs. Disable DEBUG_SERIAL_USART2!
// #define SUPPORT_BUTTONS_RIGHT // use right sensor board cable for button inputs. Disable DEBUG_SERIAL_USART3!
#endif
@ -396,6 +399,7 @@
#endif
#define PPM_NUM_CHANNELS 6 // total number of PPM channels to receive, even if they are not used.
// #define TANK_STEERING // use for tank steering, each input controls each wheel
// #define SUPPORT_BUTTONS // Define for PPM buttons support
// #define SUPPORT_BUTTONS_LEFT // use left sensor board cable for button inputs. Disable DEBUG_SERIAL_USART2!
// #define SUPPORT_BUTTONS_RIGHT // use right sensor board cable for button inputs. Disable DEBUG_SERIAL_USART3!
@ -435,6 +439,7 @@
#define FILTER 6553 // 0.1f [-] fixdt(0,16,16) lower value == softer filter [0, 65535] = [0.0 - 1.0].
#define SPEED_COEFFICIENT 16384 // 1.0f [-] fixdt(1,16,14) higher value == stronger. [0, 65535] = [-2.0 - 2.0]. In this case 16384 = 1.0 * 2^14
#define STEER_COEFFICIENT 16384 // 1.0f [-] fixdt(1,16,14) higher value == stronger. [0, 65535] = [-2.0 - 2.0]. In this case 16384 = 1.0 * 2^14. If you do not want any steering, set it to 0.
// #define TANK_STEERING // use for tank steering, each input controls each wheel
// #define INVERT_R_DIRECTION
// #define INVERT_L_DIRECTION
// #define SUPPORT_BUTTONS_LEFT // use left sensor board cable for button inputs. Disable DEBUG_SERIAL_USART2!
@ -479,6 +484,8 @@
#define PRI_INPUT2 3, -1000, 0, 1000, 0 // TYPE, MIN, MID, MAX, DEADBAND. See INPUT FORMAT section
#endif
// #define TANK_STEERING // use for tank steering, each input controls each wheel
#if defined(CONTROL_SERIAL_USART3) && !defined(DUAL_INPUTS)
#define DEBUG_SERIAL_USART2 // left sensor cable debug
#elif defined(DEBUG_SERIAL_USART2) && !defined(DUAL_INPUTS)
@ -493,7 +500,7 @@
#ifdef VARIANT_HOVERCAR
#define FLASH_WRITE_KEY 0x1107 // Flash memory writing key. Change this key to ignore the input calibrations from the flash memory and use the ones in config.h
#undef CTRL_MOD_REQ
#define CTRL_MOD_REQ TRQ_MODE // HOVERCAR works best in TORQUE Mode
#define CTRL_MOD_REQ VLT_MODE // HOVERCAR works best in TORQUE Mode. VOLTAGE mode is preffered when freewheeling is not desired when throttle is released.
#define CONTROL_ADC 0 // use ADC as input. Number indicates priority for dual-input. Disable CONTROL_SERIAL_USART2, FEEDBACK_SERIAL_USART2, DEBUG_SERIAL_USART2!
#define SIDEBOARD_SERIAL_USART3 1 // Rx from right sensor board: to use photosensors as buttons. Number indicates priority for dual-input. Comment-out if sideboard is not used!
#define FEEDBACK_SERIAL_USART3 // Tx to right sensor board: for LED battery indication. Comment-out if sideboard is not used!
@ -517,6 +524,28 @@
// #define ELECTRIC_BRAKE_ENABLE // [-] Flag to enable electric brake and replace the motor "freewheel" with a constant braking when the input torque request is 0. Only available and makes sense for TORQUE mode.
// #define ELECTRIC_BRAKE_MAX 100 // (0, 500) Maximum electric brake to be applied when input torque request is 0 (pedal fully released).
// #define ELECTRIC_BRAKE_THRES 120 // (0, 500) Threshold below at which the electric brake starts engaging.
#define MULTI_MODE_DRIVE // This option enables the selection of 3 driving modes at start-up using combinations of Brake and Throttle pedals (see below)
#ifdef MULTI_MODE_DRIVE
// BEGINNER MODE: Power ON + Brake [released] + Throttle [released or pressed]
#define MULTI_MODE_DRIVE_M1_MAX 175
#define MULTI_MODE_DRIVE_M1_RATE 250
#define MULTI_MODE_M1_I_MOT_MAX 4
#define MULTI_MODE_M1_N_MOT_MAX 30
// INTERMEDIATE MODE: Power ON + Brake [pressed] + Throttle [released]
#define MULTI_MODE_DRIVE_M2_MAX 500
#define MULTI_MODE_DRIVE_M2_RATE 300
#define MULTI_MODE_M2_I_MOT_MAX 8
#define MULTI_MODE_M2_N_MOT_MAX 80
// ADVANCED MODE: Power ON + Brake [pressed] + Throttle [pressed]
#define MULTI_MODE_DRIVE_M3_MAX 1000
#define MULTI_MODE_DRIVE_M3_RATE 450
#define MULTI_MODE_M3_I_MOT_MAX I_MOT_MAX
#define MULTI_MODE_M3_N_MOT_MAX N_MOT_MAX
#endif
#endif
// Multiple tap detection: default DOUBLE Tap on Brake pedal (4 pulses)

View File

@ -229,11 +229,16 @@ typedef struct {
uint16_t l_rx2;
} adc_buf_t;
typedef enum {
NUNCHUK_CONNECTING,
NUNCHUK_DISCONNECTED,
NUNCHUK_RECONNECTING,
NUNCHUK_CONNECTED
} nunchuk_state;
// Define I2C, Nunchuk, PPM, PWM functions
void I2C_Init(void);
void Nunchuk_Init(void);
void Nunchuk_Read(void);
uint8_t Nunchuk_Ping(void);
nunchuk_state Nunchuk_Read(void);
void PPM_Init(void);
void PPM_ISR_Callback(void);
void PWM_Init(void);
@ -256,6 +261,5 @@ void PWM_ISR_CH2_Callback(void);
#define SWC_SET (0x1800) // 0001 1000 0000 0000
#define SWD_SET (0x2000) // 0010 0000 0000 0000
#endif // DEFINES_H

View File

@ -3,9 +3,9 @@
*
* Code generated for Simulink model 'BLDC_controller'.
*
* Model version : 1.1296
* Model version : 1.1297
* Simulink Coder version : 8.13 (R2017b) 24-Jul-2017
* C/C++ source code generated on : Tue Oct 20 17:29:57 2020
* C/C++ source code generated on : Sun Mar 6 11:02:11 2022
*
* Target selection: ert.tlc
* Embedded hardware selection: ARM Compatible->ARM Cortex

200
README.md
View File

@ -1,5 +1,5 @@
# hoverboard-firmware-hack-FOC
[![Build Status](https://travis-ci.com/EmanuelFeru/hoverboard-firmware-hack-FOC.svg?branch=master)](https://travis-ci.com/EmanuelFeru/hoverboard-firmware-hack-FOC)
[![Build status](https://github.com/EFeru/hoverboard-firmware-hack-FOC/actions/workflows/build_on_commit.yml/badge.svg)](https://github.com/EFeru/hoverboard-firmware-hack-FOC/actions/workflows/build_on_commit.yml)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=CU2SWN2XV9SCY&currency_code=EUR&source=url)
@ -8,26 +8,20 @@ This repository implements Field Oriented Control (FOC) for stock hoverboards. C
- smooth torque output and improved motor efficiency. Thus, lower energy consumption
- field weakening to increase maximum speed range
Table of Contents
=======================
* **Wiki:** please check the wiki pages for [Getting Started](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki#getting-started) and for [Troubleshooting](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki#troubleshooting)
* [Hardware](#hardware)
* [FOC Firmware](#foc-firmware)
* [Example Variants](#example-variants)
* [Dual Inputs](#dual-inputs)
* [Flashing](#flashing)
* [Troubleshooting](#troubleshooting)
* [Diagnostics](#diagnostics)
* [Projects and Links](#projects-and-links)
* [Contributions](#contributions)
#### For the hoverboard sideboard firmware, see the following repositories:
- [hoverboard-sideboard-hack-GD](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-GD)
- [hoverboard-sideboard-hack-STM](https://github.com/EmanuelFeru/hoverboard-sideboard-hack-STM)
#### The hoverboards with mainboards also come with 2 sideboards(not [splitboards](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki/Firmware-Compatibility#split-boards)), check the following [wiki](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki/Sideboards) about this firmware
#### For the FOC controller design, see the following repository:
- [bldc-motor-control-FOC](https://github.com/EmanuelFeru/bldc-motor-control-FOC)
- [bldc-motor-control-FOC](https://github.com/EFeru/bldc-motor-control-FOC)
#### Videos:
<table>
@ -59,14 +53,14 @@ For the reverse-engineered schematics of the mainboard, see [20150722_hoverboard
---
## FOC Firmware
In this firmware 3 control types are available:
- Commutation
- SIN (Sinusoidal)
- FOC (Field Oriented Control) with the following 3 control modes:
- **VOLTAGE MODE**: in this mode the controller applies a constant Voltage to the motors. Recommended for robotics applications or applications where a fast motor response is required.
- **SPEED MODE**: in this mode a closed-loop controller realizes the input speed target by rejecting any of the disturbance (resistive load) applied to the motor. Recommended for robotics applications or constant speed applications.
- **TORQUE MODE**: in this mode the input torque target is realized. This mode enables motor "freewheeling" when the torque target is `0`. Recommended for most applications with a sitting human driver.
In this firmware 3 control types are available, it can be set in config.h file via CTRL_TYP_SEL parameter:
- Commutation (COM_CTRL)
- Sinusoidal (SIN_CTRL)
- Field Oriented Control (FOC_CTRL) with the following 3 control modes that can be set in config.h file with parameter CTRL_MOD_REQ:
- **VOLTAGE MODE(VLT_MODE)**: in this mode the controller applies a constant Voltage to the motors. Recommended for robotics applications or applications where a fast motor response is required.
- **SPEED MODE(SPD_MODE)**: in this mode a closed-loop controller realizes the input speed RPM target by rejecting any of the disturbance (resistive load) applied to the motor. Recommended for robotics applications or constant speed applications.
- **TORQUE MODE(TRQ_MODE)**: in this mode the input torque target is realized. This mode enables motor "freewheeling" when the torque target is `0`. Recommended for most applications with a sitting human driver.
#### Comparison between different control methods
|Control method| Complexity | Efficiency | Smoothness | Field Weakening | Freewheeling | Standstill hold |
@ -89,28 +83,35 @@ In all FOC control modes, the controller features maximum motor speed and maximu
- The Field Weakening is a linear interpolation from 0 to FIELD_WEAK_MAX or PHASE_ADV_MAX (depeding if FOC or SIN is selected, respectively)
- The Field Weakening starts engaging at FIELD_WEAK_LO and reaches the maximum value at FIELD_WEAK_HI
- The figure below shows different possible calibrations for Field Weakening / Phase Advance
![Field Weakening](/docs/pictures/FieldWeakening.png)
- If you re-calibrate the Field Weakening please take all the safety measures! The motors can spin very fast!
![Field Weakening](/docs/pictures/FieldWeakening.png)
⚠️ If you re-calibrate the Field Weakening please take all the safety measures! The motors can spin very fast!
Power consumption will be highly increase and you can trigger the overvoltage protection of your BMS ⚠️
### Parameters
- All the calibratable motor parameters can be found in the 'BLDC_controller_data.c'. I provided you with an already calibrated controller, but if you feel like fine tuning it feel free to do so
- The parameters are represented in Fixed-point data type for a more efficient code execution
- For calibrating the fixed-point parameters use the [Fixed-Point Viewer](https://github.com/EmanuelFeru/FixedPointViewer) tool
- The controller parameters are given in [this table](https://github.com/EmanuelFeru/bldc-motor-control-FOC/blob/master/02_Figures/paramTable.png)
- For calibrating the fixed-point parameters use the [Fixed-Point Viewer](https://github.com/EFeru/FixedPointViewer) tool
- The controller parameters are given in [this table](https://github.com/EFeru/bldc-motor-control-FOC/blob/master/02_Figures/paramTable.png)
### FOC Webview
To explore the controller without a Matlab/Simulink installation click on the link below:
[https://eferu.github.io/bldc-motor-control-FOC/](https://eferu.github.io/bldc-motor-control-FOC/)
---
## Example Variants
This firmware offers currently these variants (selectable in [platformio.ini](/platformio.ini) or [config.h](/Inc/config.h)):
- **VARIANT_ADC**: The motors are controlled by two potentiometers connected to the Left sensor cable (long wired)
- **VARIANT_USART**: The motors are controlled via serial protocol (e.g. on USART3 right sensor cable, the short wired cable). The commands can be sent from an Arduino. Check out the [hoverserial.ino](/Arduino/hoverserial) as an example sketch.
- **VARIANT_NUNCHUK**: Wii Nunchuk offers one hand control for throttle, braking and steering. This was one of the first input device used for electric armchairs or bottle crates.
- **VARIANT_PPM**: RC remote control with PPM Sum signal.
- **VARIANT_PWM**: RC remote control with PWM signal.
- **VARIANT_IBUS**: RC remote control with Flysky iBUS protocol connected to the Left sensor cable.
- **VARIANT_HOVERCAR**: The motors are controlled by two pedals brake and throttle. Reverse is engaged by double tapping on the brake pedal at standstill. See [HOVERCAR wiki](https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC/wiki/Variant-HOVERCAR).
- **VARIANT_HOVERCAR**: The motors are controlled by two pedals brake and throttle. Reverse is engaged by double tapping on the brake pedal at standstill. See [HOVERCAR wiki](https://github.com/EFeru/hoverboard-firmware-hack-FOC/wiki/Variant-HOVERCAR).
- **VARIANT_HOVERBOARD**: The mainboard reads the two sideboards data. The sideboards need to be flashed with the hacked version. The balancing controller is **not** yet implemented.
- **VARIANT_TRANSPOTTER**: This is for transpotter build, which is a hoverboard based transportation system. For more details on how to build it check [here](https://github.com/NiklasFauth/hoverboard-firmware-hack/wiki/Build-Instruction:-TranspOtter) and [here](https://hackaday.io/project/161891-transpotter-ng).
- **VARIANT_SKATEBOARD**: This is for skateboard build, controlled using an RC remote with PWM signal connected to the right sensor cable.
@ -118,163 +119,34 @@ This firmware offers currently these variants (selectable in [platformio.ini](/p
Of course the firmware can be further customized for other needs or projects.
---
## Dual Inputs
The firmware supports the input to be provided from two different sources connected to the Left and Right cable, respectively. To enable dual-inputs functionality uncomment `#define DUAL_INPUTS` in config.h for the respective variant. Various dual-inputs combinations can be realized as illustrated in the following table:
| Left | Right | Availability |
| --- | --- | --- |
| ADC<sup>(0)</sup> | UART<sup>(1)</sup> | VARIANT_ADC |
| ADC<sup>(0)</sup> | {PPM,PWM,iBUS}<sup>(1)</sup> | VARIANT_{PPM,PWM,IBUS} |
| ADC<sup>(0)</sup> | Sideboard<sup></sup><sup>(1*)</sup> | VARIANT_HOVERCAR |
| UART<sup>(0)</sup> | Sideboard<sup>(1*)</sup> | VARIANT_UART |
| UART<sup>(1)</sup> | Nunchuk<sup>(0)</sup> | VARIANT_NUNCHUK |
<sup>(0)</sup> Primary input: this input is used when the Auxilliary input is not available or not connected.<br/>
<sup>(1)</sup> Auxilliary input: this inputs is used when connected or enabled by a switch<sup>(*)</sup>. If the Auxilliary input is disconnected, the firmware will automatically switch to the Primary input. Timeout is reported **only** on the Primary input.
With slight modifications in config.h, other dual-inputs combinations can be realized as:
| Left | Right | Possibility |
| --- | --- | --- |
| Sideboard<sup>(1*)</sup> | UART<sup>(0)</sup> | VARIANT_UART |
| UART<sup>(0)</sup> | {PPM,PWM,iBUS}<sup>(1)</sup> | VARIANT_{PPM,PWM,IBUS} |
| {PPM,PWM,iBUS}<sup>(1)</sup> | Nunchuk<sup>(0)</sup> | VARIANT_{PPM,PWM,IBUS} |
---
## Flashing
Right to the STM32, there is a debugging header with GND, 3V3, SWDIO and SWCLK. Connect GND, SWDIO and SWCLK to your SWD programmer, like the ST-Link found on many STM devboards.
If you have never flashed your sideboard before, the MCU is probably locked. To unlock the flash, check-out the wiki page [How to Unlock MCU flash](https://github.com/EmanuelFeru/hoverboard-firmware-hack-FOC/wiki/How-to-Unlock-MCU-flash).
Do not power the mainboard from the 3.3V of your programmer! This has already killed multiple mainboards.
Make sure you hold the powerbutton or connect a jumper to the power button pins while flashing the firmware, as the STM might release the power latch and switches itself off during flashing. Battery > 36V have to be connected while flashing.
To build and flash choose one of the following methods:
### Method 1: Using Platformio IDE
- open the folder in the IDE of choice (vscode or Atom)
- press the 'PlatformIO:Build' or the 'PlatformIO:Upload' button (bottom left in vscode).
### Method 2: Using Keil uVision
- in [Keil uVision](https://www.keil.com/download/product/), open the [mainboard-hack.uvproj](/MDK-ARM/)
- if you are asked to install missing packages, click Yes
- click Build Target (or press F7) to build the firmware
- click Load Code (or press F8) to flash the firmware.
### Method 3: Using Linux CLI
- prerequisites: install [ST-Flash utility](https://github.com/texane/stlink).
- open a terminal in the repo check-out folder and if you have definded the variant in [config.h](/Inc/config.h) type:
```
make
```
or you can set the variant like this
```
make -e VARIANT=VARIANT_####
```
- flash the firmware by typing:
```
make flash
```
- or
```
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c flash "write_image erase build/hover.bin 0x8000000"
```
### Method 4: MacOS CLI
- prerequisites: first get brew https://brew.sh
- then install stlink ST-Flash utility
#### Using Make
```
brew install stlink
```
- open a terminal in the repo check-out folder and if you have definded the variant in [config.h](/Inc/config.h) type:
```
make
```
or you can set the variant like this
```
make -e VARIANT=VARIANT_####
```
If compiling fails because something is missing just install it with brew AND leave a comment to improve this howto or pull request ;-)
- flash the firmware by typing:
```
make flash
```
- if unlock is needed
```
make unlock
```
#### Using platformio CLI
```
brew install platformio
platformio run -e VARIANT_####
platformio run target upload -e VARIANT_####
```
If you have set default_envs in [platformio.ini](/platformio.ini) you can ommit -e parameter
---
## Troubleshooting
First, check that power is connected and voltage is >36V while flashing.
If the board draws more than 100mA in idle, it's probably broken.
If the motors do something, but don't rotate smooth and quietly, try to use an alternative phase mapping. Usually, color-correct mapping (blue to blue, green to green, yellow to yellow) works fine. However, some hoverboards have a different layout then others, and this might be the reason your motor isn't spinning.
Nunchuk not working: Use the right one of the 2 types of nunchuks. Use i2c pullups.
Nunchuk or PPM working bad: The i2c bus and PPM signal are very sensitive to emv distortions of the motor controller. They get stronger the faster you are. Keep cables short, use shielded cable, use ferrits, stabilize voltage in nunchuk or reviever, add i2c pullups. To many errors leads to very high accelerations which triggers the protection board within the battery to shut everything down.
Recommendation: Nunchuk Breakout Board https://github.com/Jan--Henrik/hoverboard-breakout
Most robust way for input is to use the ADC and potis. It works well even on 1m unshielded cable. Solder ~100k Ohm resistors between ADC-inputs and gnd directly on the mainboard. Use potis as pullups to 3.3V.
---
## Diagnostics
The errors reported by the board are in the form of audible beeps:
- **1 beep (low pitch)**: Motor error (see [possible causes](https://github.com/EmanuelFeru/bldc-motor-control-FOC#diagnostics))
- **2 beeps (low pitch)**: ADC timeout
- **3 beeps (low pitch)**: Serial communication timeout
- **4 beeps (low pitch)**: General timeout (PPM, PWM, Nunchuk)
- **5 beeps (low pitch)**: Mainboard temperature warning
- **1 beep slow (medium pitch)**: Low battery voltage < 36V
- **1 beep fast (medium pitch)**: Low battery voltage < 35V
- **1 beep fast (high pitch)**: Backward spinning motors
For a more detailed troubleshooting connect an [FTDI Serial adapter](https://s.click.aliexpress.com/e/_AqPOBr) or a [Bluetooth module](https://s.click.aliexpress.com/e/_A4gkMD) to the DEBUG_SERIAL cable (Left or Right) and monitor the output data using the [Hoverboard Web Serial Control](https://candas1.github.io/Hoverboard-Web-Serial-Control/) tool developed by [Candas](https://github.com/Candas1/).
---
## Projects and Links
- **Original firmware:** [https://github.com/NiklasFauth/hoverboard-firmware-hack](https://github.com/NiklasFauth/hoverboard-firmware-hack)
- **Original firmware:** [https://github.com/lucysrausch/hoverboard-firmware-hack](https://github.com/lucysrausch/hoverboard-firmware-hack)
- **[Candas](https://github.com/Candas1/) Hoverboard Web Serial Control:** [https://github.com/Candas1/Hoverboard-Web-Serial-Control](https://github.com/Candas1/Hoverboard-Web-Serial-Control)
- **[RoboDurden's](https://github.com/RoboDurden) online compiler:** [https://pionierland.de/hoverhack/](https://pionierland.de/hoverhack/)
- **Hoverboard hack for AT32F403RCT6 mainboards:** [https://github.com/cloidnerux/hoverboard-firmware-hack](https://github.com/cloidnerux/hoverboard-firmware-hack)
- **Hoverboard hack for split mainboards:** [https://github.com/flo199213/Hoverboard-Firmware-Hack-Gen2](https://github.com/flo199213/Hoverboard-Firmware-Hack-Gen2)
- **Hoverboard hack from BiPropellant:** [https://github.com/bipropellant](https://github.com/bipropellant)
- **Hoverboard breakout boards:** [https://github.com/Jan--Henrik/hoverboard-breakout](https://github.com/Jan--Henrik/hoverboard-breakout)
- **Hoverboard breakout boards:** [https://github.com/Jana-Marie/hoverboard-breakout](https://github.com/Jana-Marie/hoverboard-breakout)
<a/>
- **Bobbycar** [https://github.com/larsmm/hoverboard-firmware-hack-bbcar](https://github.com/larsmm/hoverboard-firmware-hack-bbcar)
- **Bobbycar** [https://github.com/larsmm/hoverboard-firmware-hack-FOC-bbcar](https://github.com/larsmm/hoverboard-firmware-hack-FOC-bbcar)
- **Wheel chair:** [https://github.com/Lahorde/steer_speed_ctrl](https://github.com/Lahorde/steer_speed_ctrl)
- **TranspOtterNG:** [https://github.com/Jan--Henrik/transpOtterNG](https://github.com/Jan--Henrik/transpOtterNG)
- **Hoverboard driver for ROS:** [https://github.com/alex-makarov/hoverboard-driver](https://github.com/alex-makarov/hoverboard-driver)
- **Ongoing OneWheel project:** [https://forum.esk8.news/t/yet-another-hoverboard-to-onewheel-project/60979/14](https://forum.esk8.news/t/yet-another-hoverboard-to-onewheel-project/60979/14)
- **ST Community:** [Custom FOC motor control](https://community.st.com/s/question/0D50X0000B28qTDSQY/custom-foc-control-current-measurement-dma-timer-interrupt-needs-review)
<a/>
- **Telegram Community:** If you are an enthusiast join our [Hooover Telegram Group](https://t.me/joinchat/BHWO_RKu2LT5ZxEkvUB8uw)
---
## Stargazers
[![Stargazers over time](https://starchart.cc/EFeru/hoverboard-firmware-hack-FOC.svg)](https://starchart.cc/EFeru/hoverboard-firmware-hack-FOC)
---
## Contributions
@ -285,6 +157,4 @@ If you want to donate to keep this firmware updated, please use the link below:
[![paypal](https://www.paypalobjects.com/en_US/NL/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=CU2SWN2XV9SCY&currency_code=EUR&source=url)
---

View File

@ -3,9 +3,9 @@
*
* Code generated for Simulink model 'BLDC_controller'.
*
* Model version : 1.1296
* Model version : 1.1297
* Simulink Coder version : 8.13 (R2017b) 24-Jul-2017
* C/C++ source code generated on : Tue Oct 20 17:29:57 2020
* C/C++ source code generated on : Sun Mar 6 11:02:11 2022
*
* Target selection: ert.tlc
* Embedded hardware selection: ARM Compatible->ARM Cortex
@ -1019,6 +1019,8 @@ void BLDC_controller_step(RT_MODEL *const rtM)
int32_T rtb_Sum1_jt;
int16_T rtb_Merge_m;
int16_T rtb_Merge1;
uint16_T rtb_Divide14_e;
uint16_T rtb_Divide1_f;
int16_T rtb_TmpSignalConversionAtLow_Pa[2];
int32_T rtb_Switch1;
int32_T rtb_Sum1;
@ -2116,20 +2118,15 @@ void BLDC_controller_step(RT_MODEL *const rtM)
/* End of Switch: '<S44>/Switch2' */
/* Switch: '<S42>/Switch2' incorporates:
* Constant: '<S1>/z_ctrlTypSel'
* Constant: '<S42>/CTRL_COMM2'
* Constant: '<S42>/a_phaAdvMax'
* Constant: '<S42>/id_fieldWeakMax'
* RelationalOperator: '<S42>/Relational Operator1'
/* Product: '<S42>/Divide14' incorporates:
* Constant: '<S42>/r_fieldWeakHi'
* Constant: '<S42>/r_fieldWeakLo'
* Sum: '<S42>/Sum1'
* Sum: '<S42>/Sum3'
*/
if (rtP->z_ctrlTypSel == 2) {
rtb_Saturation1 = rtP->id_fieldWeakMax;
} else {
rtb_Saturation1 = rtP->a_phaAdvMax;
}
/* End of Switch: '<S42>/Switch2' */
rtb_Divide14_e = (uint16_T)(((int16_T)(DataTypeConversion2 -
rtP->r_fieldWeakLo) << 15) / (int16_T)(rtP->r_fieldWeakHi -
rtP->r_fieldWeakLo));
/* Switch: '<S43>/Switch2' incorporates:
* Constant: '<S42>/n_fieldWeakAuthHi'
@ -2151,25 +2148,53 @@ void BLDC_controller_step(RT_MODEL *const rtM)
/* End of Switch: '<S43>/Switch2' */
/* Product: '<S42>/Divide3' incorporates:
/* Product: '<S42>/Divide1' incorporates:
* Constant: '<S42>/n_fieldWeakAuthHi'
* Constant: '<S42>/n_fieldWeakAuthLo'
* Constant: '<S42>/r_fieldWeakHi'
* Constant: '<S42>/r_fieldWeakLo'
* Product: '<S42>/Divide1'
* Product: '<S42>/Divide14'
* Product: '<S42>/Divide2'
* Sum: '<S42>/Sum1'
* Sum: '<S42>/Sum2'
* Sum: '<S42>/Sum3'
* Sum: '<S42>/Sum4'
*/
rtDW->Divide3 = (int16_T)(((uint16_T)(((uint32_T)(uint16_T)(((int16_T)
(DataTypeConversion2 - rtP->r_fieldWeakLo) << 15) / (int16_T)
(rtP->r_fieldWeakHi - rtP->r_fieldWeakLo)) * (uint16_T)(((int16_T)
(rtb_Saturation - rtP->n_fieldWeakAuthLo) << 15) / (int16_T)
(rtP->n_fieldWeakAuthHi - rtP->n_fieldWeakAuthLo))) >> 15) *
rtb_Saturation1) >> 15);
rtb_Divide1_f = (uint16_T)(((int16_T)(rtb_Saturation -
rtP->n_fieldWeakAuthLo) << 15) / (int16_T)(rtP->n_fieldWeakAuthHi -
rtP->n_fieldWeakAuthLo));
/* Switch: '<S42>/Switch1' incorporates:
* MinMax: '<S42>/MinMax1'
* RelationalOperator: '<S42>/Relational Operator6'
*/
if (rtb_Divide14_e < rtb_Divide1_f) {
/* MinMax: '<S42>/MinMax' */
if (!(rtb_Divide14_e > rtb_Divide1_f)) {
rtb_Divide14_e = rtb_Divide1_f;
}
/* End of MinMax: '<S42>/MinMax' */
} else {
if (rtb_Divide1_f < rtb_Divide14_e) {
/* MinMax: '<S42>/MinMax1' */
rtb_Divide14_e = rtb_Divide1_f;
}
}
/* End of Switch: '<S42>/Switch1' */
/* Switch: '<S42>/Switch2' incorporates:
* Constant: '<S1>/z_ctrlTypSel'
* Constant: '<S42>/CTRL_COMM2'
* Constant: '<S42>/a_phaAdvMax'
* Constant: '<S42>/id_fieldWeakMax'
* RelationalOperator: '<S42>/Relational Operator1'
*/
if (rtP->z_ctrlTypSel == 2) {
rtb_Saturation1 = rtP->id_fieldWeakMax;
} else {
rtb_Saturation1 = rtP->a_phaAdvMax;
}
/* End of Switch: '<S42>/Switch2' */
/* Product: '<S42>/Divide3' */
rtDW->Divide3 = (int16_T)((rtb_Saturation1 * rtb_Divide14_e) >> 15);
/* End of Outputs for SubSystem: '<S6>/Field_Weakening_Enabled' */
}

View File

@ -3,9 +3,9 @@
*
* Code generated for Simulink model 'BLDC_controller'.
*
* Model version : 1.1296
* Model version : 1.1297
* Simulink Coder version : 8.13 (R2017b) 24-Jul-2017
* C/C++ source code generated on : Tue Oct 20 17:29:57 2020
* C/C++ source code generated on : Sun Mar 6 11:02:11 2022
*
* Target selection: ert.tlc
* Embedded hardware selection: ARM Compatible->ARM Cortex

View File

@ -487,7 +487,8 @@ void handle_input(uint8_t *userCommand, uint32_t len)
// If there is already an unprocessed command, exit
if (command.semaphore == 1) return;
if (*userCommand != '$') return; // reject if first character is not $
// Check end of line
userCommand+=len-1; // Go to last char
if (*userCommand != '\n' && *userCommand != '\r'){
@ -495,6 +496,7 @@ void handle_input(uint8_t *userCommand, uint32_t len)
return;
}
userCommand-=len-1; // Come back
userCommand++; // Skip $
int8_t cindex = -1;
int8_t pindex = -1;

View File

@ -6,6 +6,8 @@
#include "setup.h"
#include "config.h"
#define NUNCHUK_I2C_ADDRESS 0xA4
TIM_HandleTypeDef TimHandle;
TIM_HandleTypeDef TimHandle2;
uint8_t ppm_count = 0;
@ -15,6 +17,7 @@ uint8_t timeoutFlgGen = 0;
uint8_t nunchuk_data[6] = {0};
uint8_t i2cBuffer[2];
nunchuk_state nunchukState = NUNCHUK_CONNECTING;
extern I2C_HandleTypeDef hi2c2;
extern DMA_HandleTypeDef hdma_i2c2_rx;
@ -214,44 +217,127 @@ void PWM_Init(void) {
}
#endif
uint8_t Nunchuk_Ping(void) {
if (HAL_I2C_Master_Receive(&hi2c2,0xA4,(uint8_t*)nunchuk_data, 1, 10) == HAL_OK) {
return 1;
uint8_t Nunchuk_tx(uint8_t i2cBuffer[], uint8_t i2cBufferLength) {
if(HAL_I2C_Master_Transmit(&hi2c2,NUNCHUK_I2C_ADDRESS,(uint8_t*)i2cBuffer, i2cBufferLength, 100) == HAL_OK) {
return true;
}
return 0;
return false;
}
void Nunchuk_Init(void) {
//-- START -- init WiiNunchuk
uint8_t Nunchuk_rx(uint8_t i2cBuffer[], uint8_t i2cBufferLength) {
if(HAL_I2C_Master_Receive(&hi2c2,NUNCHUK_I2C_ADDRESS,(uint8_t*)i2cBuffer, i2cBufferLength, 100) == HAL_OK) {
return true;
}
return false;
}
uint8_t Nunchuk_Init(void) {
//-- START -- init WiiNunchuk
i2cBuffer[0] = 0xF0;
i2cBuffer[1] = 0x55;
HAL_I2C_Master_Transmit(&hi2c2,0xA4,(uint8_t*)i2cBuffer, 2, 100);
if(Nunchuk_tx(i2cBuffer, 2) == false) {
return false;
}
HAL_Delay(10);
i2cBuffer[0] = 0xFB;
i2cBuffer[1] = 0x00;
HAL_I2C_Master_Transmit(&hi2c2,0xA4,(uint8_t*)i2cBuffer, 2, 100);
if(Nunchuk_tx(i2cBuffer, 2) == false) {
return false;
}
HAL_Delay(10);
return true;
}
void Nunchuk_Read(void) {
i2cBuffer[0] = 0x00;
HAL_I2C_Master_Transmit(&hi2c2,0xA4,(uint8_t*)i2cBuffer, 1, 10);
HAL_Delay(3);
if (HAL_I2C_Master_Receive(&hi2c2,0xA4,(uint8_t*)nunchuk_data, 6, 10) == HAL_OK) {
uint8_t Nunchuk_Connect() {
/* Initialise / re-initialise I2C peripheral */
I2C_Init();
/* Initialise / re-initialise nunchuk */
if(Nunchuk_Init() == true) {
nunchukState = NUNCHUK_CONNECTED;
return true;
} else {
return false;
}
}
nunchuk_state Nunchuk_Read(void) {
static uint8_t delay_counter = 0;
uint16_t checksum = 0;
uint8_t success = true;
uint8_t i = 0;
switch(nunchukState) {
case NUNCHUK_DISCONNECTED:
success = false;
/* Delay a bit before reconnecting */
if(delay_counter++ > 100) {
success = Nunchuk_Connect();
delay_counter = 0;
}
break;
case NUNCHUK_CONNECTING:
case NUNCHUK_RECONNECTING:
/* Try to reconnect once, if fails again fall back to disconnected state */
success = Nunchuk_Connect();
if(!success) {
nunchukState = NUNCHUK_DISCONNECTED;
}
break;
case NUNCHUK_CONNECTED:
/* Send read address of 0x00 to the Nunchuk */
i2cBuffer[0] = 0x00;
if(!Nunchuk_tx(i2cBuffer, 1)) {
success = false;
}
HAL_Delay(3);
/* Clear the receive data buffer */
for(i = 0; i<6; i++) {
nunchuk_data[i] = 0;
}
/* Read back 6 bytes from the Nunchuk */
if(!Nunchuk_rx(nunchuk_data, 6)) {
success = false;
}
HAL_Delay(3);
/* Checksum the receive buffer to ensure it is not in an error condition, i.e. all 0x00 or 0xFF */
for(i = 0; i<6; i++) {
checksum += nunchuk_data[i];
}
if(checksum == 0 || checksum == 0x5FA) {
success = false;
}
/* Comms failure or timeout counter reached timeout limit */
if(success == false || timeoutCntGen > 3) {
/* Clear the receive data buffer */
for(i = 0; i<6; i++) {
nunchuk_data[i] = 0;
}
/* Brings motors to safe stop */
/* Expected values from nunchuk for stopped (mid) position */
nunchuk_data[0] = 127;
nunchuk_data[1] = 128;
timeoutFlgGen = 1;
nunchukState = NUNCHUK_RECONNECTING;
}
break;
}
/* Reset the timeout flag and counter if successful communication */
if(success == true) {
timeoutCntGen = 0;
timeoutFlgGen = 0;
}
#ifndef TRANSPOTTER
if (timeoutCntGen > 3) {
HAL_Delay(50);
Nunchuk_Init();
}
#endif
return nunchukState;
//setScopeChannel(0, (int)nunchuk_data[0]);
//setScopeChannel(1, (int)nunchuk_data[1]);
//setScopeChannel(2, (int)nunchuk_data[5] & 1);

View File

@ -138,7 +138,7 @@ static uint8_t sideboard_leds_R;
#endif
#ifdef VARIANT_TRANSPOTTER
extern uint8_t nunchuk_connected;
uint8_t nunchuk_connected;
extern float setDistance;
static uint8_t checkRemote = 0;
@ -162,6 +162,14 @@ static uint32_t buzzerTimer_prev = 0;
static uint32_t inactivity_timeout_counter;
static MultipleTap MultipleTapBrake; // define multiple tap functionality for the Brake pedal
static uint16_t rate = RATE; // Adjustable rate to support multiple drive modes on startup
#ifdef MULTI_MODE_DRIVE
static uint8_t drive_mode;
static uint16_t max_speed;
#endif
int main(void) {
HAL_Init();
@ -205,9 +213,41 @@ int main(void) {
int32_t board_temp_adcFixdt = adc_buffer.temp << 16; // Fixed-point filter output initialized with current ADC converted to fixed-point
int16_t board_temp_adcFilt = adc_buffer.temp;
#ifdef MULTI_MODE_DRIVE
if (adc_buffer.l_tx2 > input1[0].min + 50 && adc_buffer.l_rx2 > input2[0].min + 50) {
drive_mode = 2;
max_speed = MULTI_MODE_DRIVE_M3_MAX;
rate = MULTI_MODE_DRIVE_M3_RATE;
rtP_Left.n_max = rtP_Right.n_max = MULTI_MODE_M3_N_MOT_MAX << 4;
rtP_Left.i_max = rtP_Right.i_max = (MULTI_MODE_M3_I_MOT_MAX * A2BIT_CONV) << 4;
} else if (adc_buffer.l_tx2 > input1[0].min + 50) {
drive_mode = 1;
max_speed = MULTI_MODE_DRIVE_M2_MAX;
rate = MULTI_MODE_DRIVE_M2_RATE;
rtP_Left.n_max = rtP_Right.n_max = MULTI_MODE_M2_N_MOT_MAX << 4;
rtP_Left.i_max = rtP_Right.i_max = (MULTI_MODE_M2_I_MOT_MAX * A2BIT_CONV) << 4;
} else {
drive_mode = 0;
max_speed = MULTI_MODE_DRIVE_M1_MAX;
rate = MULTI_MODE_DRIVE_M1_RATE;
rtP_Left.n_max = rtP_Right.n_max = MULTI_MODE_M1_N_MOT_MAX << 4;
rtP_Left.i_max = rtP_Right.i_max = (MULTI_MODE_M1_I_MOT_MAX * A2BIT_CONV) << 4;
}
printf("Drive mode %i selected: max_speed:%i acc_rate:%i \r\n", drive_mode, max_speed, rate);
#endif
// Loop until button is released
while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); }
#ifdef MULTI_MODE_DRIVE
// Wait until triggers are released. Exit if timeout elapses (to unblock if the inputs are not calibrated)
int iTimeout = 0;
while((adc_buffer.l_rx2 + adc_buffer.l_tx2) >= (input1[0].min + input2[0].min) && iTimeout++ < 300) {
HAL_Delay(10);
}
#endif
while(1) {
if (buzzerTimer - buzzerTimer_prev > 16*DELAY_IN_MAIN_LOOP) { // 1 ms = 16 ticks buzzerTimer
@ -216,7 +256,8 @@ int main(void) {
#ifndef VARIANT_TRANSPOTTER
// ####### MOTOR ENABLING: Only if the initial input is very small (for SAFETY) #######
if (enable == 0 && (!rtY_Left.z_errCode && !rtY_Right.z_errCode) && (input1[inIdx].cmd > -50 && input1[inIdx].cmd < 50) && (input2[inIdx].cmd > -50 && input2[inIdx].cmd < 50)){
if (enable == 0 && !rtY_Left.z_errCode && !rtY_Right.z_errCode &&
ABS(input1[inIdx].cmd) < 50 && ABS(input2[inIdx].cmd) < 50){
beepShort(6); // make 2 beeps indicating the motor enable
beepShort(4); HAL_Delay(100);
steerFixdt = speedFixdt = 0; // reset filters
@ -274,8 +315,8 @@ int main(void) {
#endif
// ####### LOW-PASS FILTER #######
rateLimiter16(input1[inIdx].cmd , RATE, &steerRateFixdt);
rateLimiter16(input2[inIdx].cmd , RATE, &speedRateFixdt);
rateLimiter16(input1[inIdx].cmd, rate, &steerRateFixdt);
rateLimiter16(input2[inIdx].cmd, rate, &speedRateFixdt);
filtLowPass32(steerRateFixdt >> 4, FILTER, &steerFixdt);
filtLowPass32(speedRateFixdt >> 4, FILTER, &speedFixdt);
steer = (int16_t)(steerFixdt >> 16); // convert fixed-point to integer
@ -284,6 +325,13 @@ int main(void) {
// ####### VARIANT_HOVERCAR #######
#ifdef VARIANT_HOVERCAR
if (inIdx == CONTROL_ADC) { // Only use use implementation below if pedals are in use (ADC input)
#ifdef MULTI_MODE_DRIVE
if (speed >= max_speed) {
speed = max_speed;
}
#endif
if (!MultipleTapBrake.b_multipleTap) { // Check driving direction
speed = steer + speed; // Forward driving: in this case steer = Brake, speed = Throttle
} else {
@ -293,10 +341,15 @@ int main(void) {
}
#endif
// ####### MIXER #######
// cmdR = CLAMP((int)(speed * SPEED_COEFFICIENT - steer * STEER_COEFFICIENT), INPUT_MIN, INPUT_MAX);
// cmdL = CLAMP((int)(speed * SPEED_COEFFICIENT + steer * STEER_COEFFICIENT), INPUT_MIN, INPUT_MAX);
mixerFcn(speed << 4, steer << 4, &cmdR, &cmdL); // This function implements the equations above
#if defined(TANK_STEERING) && !defined(VARIANT_HOVERCAR) && !defined(VARIANT_SKATEBOARD)
// Tank steering (no mixing)
cmdL = steer;
cmdR = speed;
#else
// ####### MIXER #######
mixerFcn(speed << 4, steer << 4, &cmdR, &cmdL); // This function implements the equations above
#endif
// ####### SET OUTPUTS (if the target change is less than +/- 100) #######
#ifdef INVERT_R_DIRECTION
@ -376,17 +429,15 @@ int main(void) {
#ifdef SUPPORT_NUNCHUK
if (transpotter_counter % 500 == 0) {
if (nunchuk_connected == 0 && enable == 0) {
if (Nunchuk_Ping()) {
HAL_Delay(500);
Nunchuk_Init();
#ifdef SUPPORT_LCD
LCD_SetLocation(&lcd, 0, 0); LCD_WriteString(&lcd, "Nunchuk Control");
#endif
timeoutCntGen = 0;
timeoutFlgGen = 0;
HAL_Delay(1000);
nunchuk_connected = 1;
}
if(Nunchuk_Read() == NUNCHUK_CONNECTED) {
#ifdef SUPPORT_LCD
LCD_SetLocation(&lcd, 0, 0); LCD_WriteString(&lcd, "Nunchuk Control");
#endif
nunchuk_connected = 1;
}
} else {
nunchuk_connected = 0;
}
}
}
#endif
@ -409,14 +460,19 @@ int main(void) {
#endif
// ####### SIDEBOARDS HANDLING #######
#if defined(SIDEBOARD_SERIAL_USART2) && defined(FEEDBACK_SERIAL_USART2)
sideboardLeds(&sideboard_leds_L);
#if defined(SIDEBOARD_SERIAL_USART2)
sideboardSensors((uint8_t)Sideboard_L.sensors);
#endif
#if defined(SIDEBOARD_SERIAL_USART3) && defined(FEEDBACK_SERIAL_USART3)
sideboardLeds(&sideboard_leds_R);
#if defined(FEEDBACK_SERIAL_USART2)
sideboardLeds(&sideboard_leds_L);
#endif
#if defined(SIDEBOARD_SERIAL_USART3)
sideboardSensors((uint8_t)Sideboard_R.sensors);
#endif
#if defined(FEEDBACK_SERIAL_USART3)
sideboardLeds(&sideboard_leds_R);
#endif
// ####### CALC BOARD TEMPERATURE #######
filtLowPass32(adc_buffer.temp, TEMP_FILT_COEF, &board_temp_adcFixdt);
@ -437,7 +493,7 @@ int main(void) {
#if defined(DEBUG_SERIAL_PROTOCOL)
process_debug();
#else
printf("in1:%i in2:%i cmdL:%i cmdR:%i BatADC:%i BatV:%i TempADC:%i Temp:%i\r\n",
printf("in1:%i in2:%i cmdL:%i cmdR:%i BatADC:%i BatV:%i TempADC:%i Temp:%i \r\n",
input1[inIdx].raw, // 1: INPUT1
input2[inIdx].raw, // 2: INPUT2
cmdL, // 3: output command: [-1000, 1000]
@ -486,7 +542,15 @@ int main(void) {
poweroffPressCheck();
// ####### BEEP AND EMERGENCY POWEROFF #######
if ((TEMP_POWEROFF_ENABLE && board_temp_deg_c >= TEMP_POWEROFF && speedAvgAbs < 20) || (batVoltage < BAT_DEAD && speedAvgAbs < 20)) { // poweroff before mainboard burns OR low bat 3
if (TEMP_POWEROFF_ENABLE && board_temp_deg_c >= TEMP_POWEROFF && speedAvgAbs < 20){ // poweroff before mainboard burns OR low bat 3
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Powering off, temperature is too high\r\n");
#endif
poweroff();
} else if ( BAT_DEAD_ENABLE && batVoltage < BAT_DEAD && speedAvgAbs < 20){
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Powering off, battery voltage is too low\r\n");
#endif
poweroff();
} else if (rtY_Left.z_errCode || rtY_Right.z_errCode) { // 1 beep (low pitch): Motor error, disable motors
enable = 0;
@ -503,7 +567,7 @@ int main(void) {
beepCount(0, 10, 6);
} else if (BAT_LVL2_ENABLE && batVoltage < BAT_LVL2) { // 1 beep slow (medium pitch): Low bat 2
beepCount(0, 10, 30);
} else if (BEEPS_BACKWARD && ((speed < -50 && speedAvg < 0) || MultipleTapBrake.b_multipleTap)) { // 1 beep fast (high pitch): Backward spinning motors
} else if (BEEPS_BACKWARD && (((cmdR < -50 || cmdL < -50) && speedAvg < 0) || MultipleTapBrake.b_multipleTap)) { // 1 beep fast (high pitch): Backward spinning motors
beepCount(0, 5, 1);
backwardDrive = 1;
} else { // do not beep
@ -512,13 +576,24 @@ int main(void) {
}
inactivity_timeout_counter++;
// ####### INACTIVITY TIMEOUT #######
if (abs(cmdL) > 50 || abs(cmdR) > 50) {
inactivity_timeout_counter = 0;
} else {
inactivity_timeout_counter++;
}
#if defined(CRUISE_CONTROL_SUPPORT) || defined(STANDSTILL_HOLD_ENABLE)
if ((abs(rtP_Left.n_cruiseMotTgt) > 50 && rtP_Left.b_cruiseCtrlEna) ||
(abs(rtP_Right.n_cruiseMotTgt) > 50 && rtP_Right.b_cruiseCtrlEna)) {
inactivity_timeout_counter = 0;
}
#endif
if (inactivity_timeout_counter > (INACTIVITY_TIMEOUT * 60 * 1000) / (DELAY_IN_MAIN_LOOP + 1)) { // rest of main loop needs maybe 1ms
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Powering off, wheels were inactive for too long\r\n");
#endif
poweroff();
}

View File

@ -283,17 +283,21 @@ DMA_HandleTypeDef hdma_i2c2_tx;
void I2C_Init(void)
{
/* Initialise I2C2 GPIO pins
* I2C2 GPIO Configuration
* PB10 ------> I2C2_SCL
* PB11 ------> I2C2_SDA
*/
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Initialise I2C peripheral */
__HAL_RCC_I2C2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA1_Channel4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 1, 4);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
/* DMA1_Channel5_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 3);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 200000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
@ -303,65 +307,53 @@ void I2C_Init(void)
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
__HAL_RCC_I2C2_FORCE_RESET();
__HAL_RCC_I2C2_RELEASE_RESET();
HAL_I2C_Init(&hi2c2);
GPIO_InitTypeDef GPIO_InitStruct;
/* Peripheral DMA init*/
/* __HAL_RCC_DMA1_CLK_ENABLE();
*/
/* DMA1_Channel4_IRQn interrupt configuration */
/* HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 1, 4);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
*/
/* DMA1_Channel5_IRQn interrupt configuration */
/* HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 3);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
*/
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* USER CODE BEGIN I2C2_MspInit 0 */
/* hdma_i2c2_rx.Instance = DMA1_Channel5;
hdma_i2c2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c2_rx.Init.Mode = DMA_NORMAL;
hdma_i2c2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_i2c2_rx);
/* USER CODE END I2C2_MspInit 0 */
/**I2C2 GPIO Configuration
PB10 ------> I2C2_SCL
PB11 ------> I2C2_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C2_CLK_ENABLE();
/* Peripheral DMA init*/
hdma_i2c2_rx.Instance = DMA1_Channel5;
hdma_i2c2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c2_rx.Init.Mode = DMA_NORMAL;
hdma_i2c2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_i2c2_rx);
__HAL_LINKDMA(&hi2c2,hdmarx,hdma_i2c2_rx);
hdma_i2c2_tx.Instance = DMA1_Channel4;
hdma_i2c2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c2_tx.Init.Mode = DMA_NORMAL;
hdma_i2c2_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_i2c2_tx);
__HAL_LINKDMA(&hi2c2,hdmatx,hdma_i2c2_tx);
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
/* USER CODE BEGIN I2C2_MspInit 1 */
/* USER CODE END I2C2_MspInit 1 */
__HAL_LINKDMA(&hi2c2,hdmarx,hdma_i2c2_rx);
*/
/* hdma_i2c2_tx.Instance = DMA1_Channel4;
hdma_i2c2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_i2c2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2c2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2c2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_i2c2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_i2c2_tx.Init.Mode = DMA_NORMAL;
hdma_i2c2_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hdma_i2c2_tx);
__HAL_LINKDMA(&hi2c2,hdmatx,hdma_i2c2_tx);
*/
/* Peripheral interrupt init */
/* HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C2_ER_IRQn);
*/
}
void MX_GPIO_Init(void) {

View File

@ -111,12 +111,6 @@ uint8_t ctrlModReq = CTRL_MOD_REQ; // Final control mode request
LCD_PCF8574_HandleTypeDef lcd;
#endif
#if defined(CONTROL_NUNCHUK) || defined(SUPPORT_NUNCHUK)
uint8_t nunchuk_connected = 1;
#else
uint8_t nunchuk_connected = 0;
#endif
#ifdef VARIANT_TRANSPOTTER
float setDistance;
uint16_t VirtAddVarTab[NB_OF_VAR] = {1337}; // Virtual address defined by the user: 0xFFFF value is prohibited
@ -288,11 +282,6 @@ void Input_Init(void) {
PWM_Init();
#endif
#ifdef CONTROL_NUNCHUK
I2C_Init();
Nunchuk_Init();
#endif
#if defined(DEBUG_SERIAL_USART2) || defined(CONTROL_SERIAL_USART2) || defined(FEEDBACK_SERIAL_USART2) || defined(SIDEBOARD_SERIAL_USART2)
UART2_Init();
#endif
@ -314,6 +303,10 @@ void Input_Init(void) {
EE_Init(); /* EEPROM Init */
EE_ReadVariable(VirtAddVarTab[0], &writeCheck);
if (writeCheck == FLASH_WRITE_KEY) {
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Using the configuration from EEprom\r\n");
#endif
EE_ReadVariable(VirtAddVarTab[1] , &readVal); rtP_Left.i_max = rtP_Right.i_max = (int16_t)readVal;
EE_ReadVariable(VirtAddVarTab[2] , &readVal); rtP_Left.n_max = rtP_Right.n_max = (int16_t)readVal;
for (uint8_t i=0; i<INPUTS_NR; i++) {
@ -325,8 +318,16 @@ void Input_Init(void) {
EE_ReadVariable(VirtAddVarTab[ 8+8*i] , &readVal); input2[i].min = (int16_t)readVal;
EE_ReadVariable(VirtAddVarTab[ 9+8*i] , &readVal); input2[i].mid = (int16_t)readVal;
EE_ReadVariable(VirtAddVarTab[10+8*i] , &readVal); input2[i].max = (int16_t)readVal;
printf("Limits Input1: TYP:%i MIN:%i MID:%i MAX:%i\r\nLimits Input2: TYP:%i MIN:%i MID:%i MAX:%i\r\n",
input1[i].typ, input1[i].min, input1[i].mid, input1[i].max,
input2[i].typ, input2[i].min, input2[i].mid, input2[i].max);
}
} else {
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Using the configuration from config.h\r\n");
#endif
for (uint8_t i=0; i<INPUTS_NR; i++) {
if (input1[i].typDef == 3) { // If Input type defined is 3 (auto), identify the input type based on the values from config.h
input1[i].typ = checkInputType(input1[i].min, input1[i].mid, input1[i].max);
@ -338,6 +339,9 @@ void Input_Init(void) {
} else {
input2[i].typ = input2[i].typDef;
}
printf("Limits Input1: TYP:%i MIN:%i MID:%i MAX:%i\r\nLimits Input2: TYP:%i MIN:%i MID:%i MAX:%i\r\n",
input1[i].typ, input1[i].min, input1[i].mid, input1[i].max,
input2[i].typ, input2[i].min, input2[i].mid, input2[i].max);
}
}
HAL_FLASH_Lock();
@ -455,14 +459,25 @@ void beepShortMany(uint8_t cnt, int8_t dir) {
void calcAvgSpeed(void) {
// Calculate measured average speed. The minus sign (-) is because motors spin in opposite directions
#if !defined(INVERT_L_DIRECTION) && !defined(INVERT_R_DIRECTION)
speedAvg = ( rtY_Left.n_mot - rtY_Right.n_mot) / 2;
#elif !defined(INVERT_L_DIRECTION) && defined(INVERT_R_DIRECTION)
speedAvg = ( rtY_Left.n_mot + rtY_Right.n_mot) / 2;
#elif defined(INVERT_L_DIRECTION) && !defined(INVERT_R_DIRECTION)
speedAvg = (-rtY_Left.n_mot - rtY_Right.n_mot) / 2;
#elif defined(INVERT_L_DIRECTION) && defined(INVERT_R_DIRECTION)
speedAvg = (-rtY_Left.n_mot + rtY_Right.n_mot) / 2;
speedAvg = 0;
#if defined(MOTOR_LEFT_ENA)
#if defined(INVERT_L_DIRECTION)
speedAvg -= rtY_Left.n_mot;
#else
speedAvg += rtY_Left.n_mot;
#endif
#endif
#if defined(MOTOR_RIGHT_ENA)
#if defined(INVERT_R_DIRECTION)
speedAvg += rtY_Right.n_mot;
#else
speedAvg -= rtY_Right.n_mot;
#endif
// Average only if both motors are enabled
#if defined(MOTOR_LEFT_ENA)
speedAvg /= 2;
#endif
#endif
// Handle the case when SPEED_COEFFICIENT sign is negative (which is when most significant bit is 1)
@ -532,16 +547,13 @@ void adcCalibLim(void) {
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Input1 is ");
#endif
input1[inIdx].typ = checkInputType(INPUT1_MIN_temp, INPUT1_MID_temp, INPUT1_MAX_temp);
if (input1[inIdx].typ == input1[inIdx].typDef || input1[inIdx].typDef == 3) { // Accept calibration only if the type is correct OR type was set to 3 (auto)
input1[inIdx].min = INPUT1_MIN_temp + input_margin;
input1[inIdx].mid = INPUT1_MID_temp;
input1[inIdx].max = INPUT1_MAX_temp - input_margin;
uint8_t input1TypTemp = checkInputType(INPUT1_MIN_temp, INPUT1_MID_temp, INPUT1_MAX_temp);
if (input1TypTemp == input1[inIdx].typDef || input1[inIdx].typDef == 3) { // Accept calibration only if the type is correct OR type was set to 3 (auto)
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("..OK\r\n");
#endif
} else {
input1[inIdx].typ = 0; // Disable input
input1TypTemp = 0; // Disable input
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("..NOK\r\n");
#endif
@ -550,26 +562,42 @@ void adcCalibLim(void) {
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Input2 is ");
#endif
input2[inIdx].typ = checkInputType(INPUT2_MIN_temp, INPUT2_MID_temp, INPUT2_MAX_temp);
if (input2[inIdx].typ == input2[inIdx].typDef || input2[inIdx].typDef == 3) { // Accept calibration only if the type is correct OR type was set to 3 (auto)
input2[inIdx].min = INPUT2_MIN_temp + input_margin;
input2[inIdx].mid = INPUT2_MID_temp;
input2[inIdx].max = INPUT2_MAX_temp - input_margin;
uint8_t input2TypTemp = checkInputType(INPUT2_MIN_temp, INPUT2_MID_temp, INPUT2_MAX_temp);
if (input2TypTemp == input2[inIdx].typDef || input2[inIdx].typDef == 3) { // Accept calibration only if the type is correct OR type was set to 3 (auto)
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("..OK\r\n");
#endif
} else {
input2[inIdx].typ = 0; // Disable input
input2TypTemp = 0; // Disable input
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("..NOK\r\n");
#endif
}
inp_cal_valid = 1; // Mark calibration to be saved in Flash at shutdown
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Limits Input1: TYP:%i MIN:%i MID:%i MAX:%i\r\nLimits Input2: TYP:%i MIN:%i MID:%i MAX:%i\r\n",
input1[inIdx].typ, input1[inIdx].min, input1[inIdx].mid, input1[inIdx].max,
input2[inIdx].typ, input2[inIdx].min, input2[inIdx].mid, input2[inIdx].max);
#endif
// At least one of the inputs is not ignored
if (input1TypTemp != 0 || input2TypTemp != 0){
input1[inIdx].typ = input1TypTemp;
input1[inIdx].min = INPUT1_MIN_temp + input_margin;
input1[inIdx].mid = INPUT1_MID_temp;
input1[inIdx].max = INPUT1_MAX_temp - input_margin;
input2[inIdx].typ = input2TypTemp;
input2[inIdx].min = INPUT2_MIN_temp + input_margin;
input2[inIdx].mid = INPUT2_MID_temp;
input2[inIdx].max = INPUT2_MAX_temp - input_margin;
inp_cal_valid = 1; // Mark calibration to be saved in Flash at shutdown
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Limits Input1: TYP:%i MIN:%i MID:%i MAX:%i\r\nLimits Input2: TYP:%i MIN:%i MID:%i MAX:%i\r\n",
input1[inIdx].typ, input1[inIdx].min, input1[inIdx].mid, input1[inIdx].max,
input2[inIdx].typ, input2[inIdx].min, input2[inIdx].mid, input2[inIdx].max);
#endif
}else{
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Both inputs cannot be ignored, calibration rejected.\r\n");
#endif
}
#endif
#endif // AUTO_CALIBRATION_ENA
@ -813,8 +841,7 @@ void readInputRaw(void) {
#endif
#if defined(CONTROL_NUNCHUK) || defined(SUPPORT_NUNCHUK)
if (nunchuk_connected) {
Nunchuk_Read();
if (Nunchuk_Read() == NUNCHUK_CONNECTED) {
if (inIdx == CONTROL_NUNCHUK) {
input1[inIdx].raw = (nunchuk_data[0] - 127) * 8; // X axis 0-255
input2[inIdx].raw = (nunchuk_data[1] - 128) * 8; // Y axis 0-255
@ -1052,7 +1079,7 @@ void readCommand(void) {
#endif
#if defined(CRUISE_CONTROL_SUPPORT) && (defined(SUPPORT_BUTTONS) || defined(SUPPORT_BUTTONS_LEFT) || defined(SUPPORT_BUTTONS_RIGHT))
cruiseControl(button1); // Cruise control activation/deactivation
cruiseControl(button1); // Cruise control activation/deactivation
#endif
}
@ -1070,16 +1097,16 @@ void usart2_rx_check(void)
#endif
#if defined(DEBUG_SERIAL_USART2)
uint8_t ptr[SERIAL_BUFFER_SIZE];
uint8_t ptr_debug[SERIAL_BUFFER_SIZE];
if (pos != old_pos) { // Check change in received data
if (pos > old_pos) { // "Linear" buffer mode: check if current position is over previous one
usart_process_debug(&rx_buffer_L[old_pos], pos - old_pos); // Process data
} else { // "Overflow" buffer mode
memcpy(&ptr[0], &rx_buffer_L[old_pos], rx_buffer_L_len - old_pos); // First copy data from the end of buffer
memcpy(&ptr_debug[0], &rx_buffer_L[old_pos], rx_buffer_L_len - old_pos); // First copy data from the end of buffer
if (pos > 0) { // Check and continue with beginning of buffer
memcpy(&ptr[rx_buffer_L_len - old_pos], &rx_buffer_L[0], pos); // Copy remaining data
memcpy(&ptr_debug[rx_buffer_L_len - old_pos], &rx_buffer_L[0], pos); // Copy remaining data
}
usart_process_debug(ptr, rx_buffer_L_len - old_pos + pos); // Process data
usart_process_debug(ptr_debug, rx_buffer_L_len - old_pos + pos); // Process data
}
}
#endif // DEBUG_SERIAL_USART2
@ -1142,17 +1169,17 @@ void usart3_rx_check(void)
#endif
#if defined(DEBUG_SERIAL_USART3)
uint8_t ptr[SERIAL_BUFFER_SIZE];
uint8_t ptr_debug[SERIAL_BUFFER_SIZE];
if (pos != old_pos) { // Check change in received data
if (pos > old_pos) { // "Linear" buffer mode: check if current position is over previous one
usart_process_debug(&rx_buffer_R[old_pos], pos - old_pos); // Process data
} else { // "Overflow" buffer mode
memcpy(&ptr[0], &rx_buffer_R[old_pos], rx_buffer_R_len - old_pos); // First copy data from the end of buffer
memcpy(&ptr_debug[0], &rx_buffer_R[old_pos], rx_buffer_R_len - old_pos); // First copy data from the end of buffer
if (pos > 0) { // Check and continue with beginning of buffer
memcpy(&ptr[rx_buffer_R_len - old_pos], &rx_buffer_R[0], pos); // Copy remaining data
memcpy(&ptr_debug[rx_buffer_R_len - old_pos], &rx_buffer_R[0], pos); // Copy remaining data
}
usart_process_debug(ptr, rx_buffer_R_len - old_pos + pos); // Process data
usart_process_debug(ptr_debug, rx_buffer_R_len - old_pos + pos); // Process data
}
}
#endif // DEBUG_SERIAL_USART3
@ -1399,9 +1426,7 @@ void sideboardSensors(uint8_t sensors) {
sensor1_prev = sensor1_index;
} else { // Use Optical switches
sensor1_trig = (sensors & SENSOR1_SET) && !sensor1_prev; // rising edge detection
sensor2_trig = (sensors & SENSOR2_SET) && !sensor2_prev; // rising edge detection
sensor1_prev = sensors & SENSOR1_SET;
sensor2_prev = sensors & SENSOR2_SET;
}
// Control MODE and Control Type Handling
@ -1430,11 +1455,7 @@ void sideboardSensors(uint8_t sensors) {
if (++sensor1_index > 4) { sensor1_index = 0; }
}
#ifdef CRUISE_CONTROL_SUPPORT // Cruise Control Activation/Deactivation
if (sensor2_trig) {
cruiseControl(sensor2_trig);
}
#else // Field Weakening Activation/Deactivation
// Field Weakening Activation/Deactivation
static uint8_t sensor2_index = 1; // holds the press index number for sensor2, when used as a button
// Override in case the Sideboard control is Active
@ -1445,25 +1466,33 @@ void sideboardSensors(uint8_t sensors) {
sensor2_trig = 1;
}
sensor2_prev = sensor2_index;
}else{
sensor2_trig = (sensors & SENSOR2_SET) && !sensor2_prev; // rising edge detection
sensor2_prev = sensors & SENSOR2_SET;
}
if (sensor2_trig) {
switch (sensor2_index) {
case 0: // FW Disabled
rtP_Left.b_fieldWeakEna = 0;
rtP_Right.b_fieldWeakEna = 0;
Input_Lim_Init();
break;
case 1: // FW Enabled
rtP_Left.b_fieldWeakEna = 1;
rtP_Right.b_fieldWeakEna = 1;
Input_Lim_Init();
break;
#ifdef CRUISE_CONTROL_SUPPORT // Cruise Control Activation/Deactivation
if (sensor2_trig) {
cruiseControl(sensor2_trig);
}
if (inIdx == inIdx_prev) { beepShortMany(sensor2_index + 1, 1); }
if (++sensor2_index > 1) { sensor2_index = 0; }
}
#endif // CRUISE_CONTROL_SUPPORT
#else
if (sensor2_trig) {
switch (sensor2_index) {
case 0: // FW Disabled
rtP_Left.b_fieldWeakEna = 0;
rtP_Right.b_fieldWeakEna = 0;
Input_Lim_Init();
break;
case 1: // FW Enabled
rtP_Left.b_fieldWeakEna = 1;
rtP_Right.b_fieldWeakEna = 1;
Input_Lim_Init();
break;
}
if (inIdx == inIdx_prev) { beepShortMany(sensor2_index + 1, 1); }
if (++sensor2_index > 1) { sensor2_index = 0; }
}
#endif // CRUISE_CONTROL_SUPPORT
#endif
}
@ -1485,6 +1514,10 @@ void saveConfig() {
#endif
#if !defined(VARIANT_HOVERBOARD) && !defined(VARIANT_TRANSPOTTER)
if (inp_cal_valid || cur_spd_valid) {
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Saving configuration to EEprom\r\n");
#endif
HAL_FLASH_Unlock();
EE_WriteVariable(VirtAddVarTab[0] , (uint16_t)FLASH_WRITE_KEY);
EE_WriteVariable(VirtAddVarTab[1] , (uint16_t)rtP_Left.i_max);
@ -1525,12 +1558,14 @@ void poweroff(void) {
void poweroffPressCheck(void) {
#if !defined(VARIANT_HOVERBOARD) && !defined(VARIANT_TRANSPOTTER)
if(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
enable = 0;
uint16_t cnt_press = 0;
while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
HAL_Delay(10);
if (cnt_press++ == 5 * 100) { beepShort(5); }
}
if (cnt_press > 8) enable = 0;
if (cnt_press >= 5 * 100) { // Check if press is more than 5 sec
HAL_Delay(1000);
if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { // Double press: Adjust Max Current, Max Speed
@ -1546,7 +1581,10 @@ void poweroffPressCheck(void) {
#endif
}
} else if (cnt_press > 8) { // Short press: power off (80 ms debounce)
poweroff();
#if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
printf("Powering off, button has been pressed\r\n");
#endif
poweroff();
}
}
#elif defined(VARIANT_TRANSPOTTER)
@ -1646,22 +1684,22 @@ void rateLimiter16(int16_t u, int16_t rate, int16_t *y) {
* Parameters: SPEED_COEFFICIENT, STEER_COEFFICIENT = fixdt(0,16,14)
*/
void mixerFcn(int16_t rtu_speed, int16_t rtu_steer, int16_t *rty_speedR, int16_t *rty_speedL) {
int16_t prodSpeed;
int16_t prodSteer;
int32_t tmp;
int16_t prodSpeed;
int16_t prodSteer;
int32_t tmp;
prodSpeed = (int16_t)((rtu_speed * (int16_t)SPEED_COEFFICIENT) >> 14);
prodSteer = (int16_t)((rtu_steer * (int16_t)STEER_COEFFICIENT) >> 14);
prodSpeed = (int16_t)((rtu_speed * (int16_t)SPEED_COEFFICIENT) >> 14);
prodSteer = (int16_t)((rtu_steer * (int16_t)STEER_COEFFICIENT) >> 14);
tmp = prodSpeed - prodSteer;
tmp = CLAMP(tmp, -32768, 32767); // Overflow protection
*rty_speedR = (int16_t)(tmp >> 4); // Convert from fixed-point to int
*rty_speedR = CLAMP(*rty_speedR, INPUT_MIN, INPUT_MAX);
tmp = prodSpeed - prodSteer;
tmp = CLAMP(tmp, -32768, 32767); // Overflow protection
*rty_speedR = (int16_t)(tmp >> 4); // Convert from fixed-point to int
*rty_speedR = CLAMP(*rty_speedR, INPUT_MIN, INPUT_MAX);
tmp = prodSpeed + prodSteer;
tmp = CLAMP(tmp, -32768, 32767); // Overflow protection
*rty_speedL = (int16_t)(tmp >> 4); // Convert from fixed-point to int
*rty_speedL = CLAMP(*rty_speedL, INPUT_MIN, INPUT_MAX);
tmp = prodSpeed + prodSteer;
tmp = CLAMP(tmp, -32768, 32767); // Overflow protection
*rty_speedL = (int16_t)(tmp >> 4); // Convert from fixed-point to int
*rty_speedL = CLAMP(*rty_speedL, INPUT_MIN, INPUT_MAX);
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB