Merge pull request #20 from larsmm/master

Lars: added lots of documentation, adc improved, motor reverse added
This commit is contained in:
NiklasFauth 2018-05-29 12:19:17 +02:00 committed by GitHub
commit 9332f59f82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 41 deletions

View File

@ -6,45 +6,64 @@
#define PWM_FREQ 16000 // PWM frequency in Hz
#define DEAD_TIME 32 // PWM deadtime
#define DC_CUR_LIMIT 15 // Motor DC current limit in amps
#define DC_CUR_LIMIT 15 // Motor DC current limit in amps. it does not disable motors, it is a soft current limit.
#define BAT_LOW_LVL1 36.0 // gently beeps at this voltage level
#define BAT_LOW_LVL2 33.0 // your battery is almost empty. Charge now!
#define BAT_LOW_DEAD 31.0 // undervoltage lockout
#define BAT_LOW_LVL1 36.0 // gently beeps at this voltage level. ~3.6V/cell
#define BAT_LOW_LVL2 33.0 // your battery is almost empty. Charge now! ~3.3V/cell
#define BAT_LOW_DEAD 31.0 // undervoltage lockout. ~3.1V/cell
// ################################################################################
#define DEBUG_SERIAL_USART2
//#define DEBUG_SERIAL_USART3
#define DEBUG_SERIAL_USART2 // left sensor board cable, disable if ADC or PPM is used!
//#define DEBUG_SERIAL_USART3 // right sensor board cable, disable if I2C (nunchuck) is used!
#define DEBUG_BAUD 115200 // UART baud rate
//#define DEBUG_SERIAL_SERVOTERM
#define DEBUG_SERIAL_ASCII
//#define DEBUG_I2C_LCD
#define DEBUG_SERIAL_ASCII // human readable output. i.e. "345;1337;0;0\n\r"
#define TIMEOUT 5 //number of wrong / missing commands before emergency off
//#define DEBUG_I2C_LCD // standard 16x2 or larger text-lcd via i2c-converter on right sensor board cable
#define TIMEOUT 5 // number of wrong / missing commands before emergency off
// ################################################################################
// ###### CONTROL VIA RC REMOTE ######
//#define CONTROL_PPM // use PPM CONTROL_PPM
//#define PPM_NUM_CHANNELS 6 // number of PPM channels to receive
// left sensor board cable. Channel 1: steering, Channel 2: speed.
//#define CONTROL_PPM // use PPM-Sum as input. disable DEBUG_SERIAL_USART2!
//#define PPM_NUM_CHANNELS 6 // total number of PPM channels to receive, even if they are not used.
// ###### CONTROL VIA TWO POTENTIOMETERS ######
// #define CONTROL_ADC
// ADC-calibration to cover the full poti-range: connect potis to left sensor board cable (0 to 3.3V), watch UART on the right sensor board cable. the first 2 values are ADC1 and ADC2. write minimum and maximum poti position-values to ADC?_MIN and ADC?_MAX.
//#define CONTROL_ADC // use ADC as input. disable DEBUG_SERIAL_USART2!
//#define ADC1_MIN 0 // min ADC1-value while poti at minimum-position (0 - 4095)
//#define ADC1_MAX 4095 // max ADC1-value while poti at maximum-position (0 - 4095)
//#define ADC2_MIN 0 // min ADC2-value while poti at minimum-position (0 - 4095)
//#define ADC2_MAX 4095 // max ADC2-value while poti at maximum-position (0 - 4095)
// ###### CONTROL VIA NINTENDO NUNCHUCK ######
#define CONTROL_NUNCHUCK
// left sensor board cable. keep cable short, use shielded cable, use ferrits, stabalize voltage in nunchuck, use the right one of the 2 types of nunchucks, add i2c pullups.
#define CONTROL_NUNCHUCK // use nunchuck as input. disable DEBUG_SERIAL_USART3!
// ################################################################################
// ###### DRIVING BEHAVIOR ######
#define FILTER 0.1
#define SPEED_COEFFICIENT 0.5
#define STEER_COEFFICIENT 0.5
//Turno boost at high speeds while button1 is pressed:
// inputs:
// - cmd1 and cmd2: analog normalized input values. -1000 to 1000
// - button1 and button2: digital input values. 0 or 1
// - adc_buffer.l_tx2 and adc_buffer.l_rx2: unfiltered ADC values (you do not need them). 0 to 4095
// outputs:
// - speedR and speedL: normal driving -1000 to 1000
// - weakr and weakl: field weakening for extra boost at high speed (speedR > 700 and speedL > 700). 0 to ~400
#define FILTER 0.1 // lower value == softer filter. do not use values <0.01, you will get float precision issues.
#define SPEED_COEFFICIENT 0.5 // higher value == stronger. 0.0 to 1.0
#define STEER_COEFFICIENT 0.5 // higher value == stronger. if you do not want any steering, set it to 0.0; 0.0 to 1.0
//#define INVERT_R_DIRECTION
//#define INVERT_L_DIRECTION
//Turbo boost at high speeds while button1 is pressed:
//#define ADDITIONAL_CODE \
if (button1 && speed > 700) { /* field weakening at high speeds */ \
if (button1 && speedR > 700) { /* field weakening at high speeds */ \
weakl = cmd1 - 700; /* weak should never exceed 400 or 450 MAX!! */ \
weakr = cmd1 - 700; } \
else { \
@ -57,7 +76,7 @@ else { \
// #define STEER_COEFFICIENT 0
// #define ADDITIONAL_CODE \
if (button1 && speedR < 300) { \
if (button1 && speedR < 300) { /* drive backwards */ \
speedR = speedR * -0.2f; \
speedL = speedL * -0.2f; } \
else { \
@ -82,3 +101,23 @@ else {\
weakr = 0;
// #define BEEPS_BACKWARD
// ################################################################################
// validate settings (do not touch this):
#if defined DEBUG_SERIAL_USART2 && defined CONTROL_ADC
#error CONTROL_ADC and DEBUG_SERIAL_USART2 not allowed. use DEBUG_SERIAL_USART3 instead.
#endif
#if defined DEBUG_SERIAL_USART2 && defined CONTROL_PPM
#error CONTROL_PPM and DEBUG_SERIAL_USART2 not allowed. use DEBUG_SERIAL_USART3 instead.
#endif
#if defined DEBUG_SERIAL_USART3 && defined CONTROL_NUNCHUCK
#error CONTROL_NUNCHUCK and DEBUG_SERIAL_USART3 not allowed. use DEBUG_SERIAL_USART2 instead.
#endif
#if defined CONTROL_PPM && defined CONTROL_ADC && defined CONTROL_NUNCHUCK || defined CONTROL_PPM && defined CONTROL_ADC || defined CONTROL_ADC && defined CONTROL_NUNCHUCK || defined CONTROL_PPM && defined CONTROL_NUNCHUCK
#error only 1 input method allowed. use CONTROL_PPM or CONTROL_ADC or CONTROL_NUNCHUCK.
#endif

View File

@ -22,9 +22,9 @@ http://vocke.tv/lib/exe/fetch.php?media=20150722_hoverboard_sch.pdf
---
#### Flashing
To build the firmware, just type "make". Make sure you have specified your gcc-arm-none-eabi binary location in the Makefile. Right to the STM32, there is a debugging header with GND, 3V3, SWDIO and SWCLK. Connect these to your SWD programmer, like the ST-Link found on many STM devboards.
To build the firmware, just type "make". Make sure you have specified your gcc-arm-none-eabi binary location in the Makefile ("PREFIX = ..."). 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.
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.
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 flash the STM32, use the ST-Flash utility (https://github.com/texane/stlink).
@ -40,16 +40,22 @@ st-flash --reset write build/hover.bin 0x8000000
---
#### Troubleshooting
First, check that power is connected and voltage is > 36V.
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.
Nunchuck not working: Use the right one of the 2 types of nunchucks. Use i2c pullups.
Nunchuck 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, stabalize voltage in nunchuck 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.
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.
---
#### Examples
Have a look at the config.h in the Inc directory. That's where you configure to firmware to match your project.
Currently supported: Wii Nunchuck, analog potentiometer and PPM signal from a RC remote.
Currently supported: Wii Nunchuck, analog potentiometer and PPM-Sum signal from a RC remote.
If you need additional features like a boost button, have a look at the while(1) loop in the main.c

View File

@ -32,11 +32,10 @@ extern TIM_HandleTypeDef htim_right;
extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;
extern volatile adc_buf_t adc_buffer;
extern volatile adc_buf_t adc_buffer;
//LCD_PCF8574_HandleTypeDef lcd;
extern I2C_HandleTypeDef hi2c2;
int cmd1;
int cmd1; // normalized input values. -1000 to 1000
int cmd2;
int cmd3;
@ -127,30 +126,29 @@ int main(void) {
I2C_Init();
HAL_Delay(50);
lcd.pcf8574.PCF_I2C_ADDRESS = 0x27;
lcd.pcf8574.PCF_I2C_TIMEOUT = 5;
lcd.pcf8574.i2c = hi2c2;
lcd.NUMBER_OF_LINES = NUMBER_OF_LINES_2;
lcd.type = TYPE0;
lcd.pcf8574.PCF_I2C_TIMEOUT = 5;
lcd.pcf8574.i2c = hi2c2;
lcd.NUMBER_OF_LINES = NUMBER_OF_LINES_2;
lcd.type = TYPE0;
if(LCD_Init(&lcd)!=LCD_OK){
// error occured
//TODO while(1);
}
if(LCD_Init(&lcd)!=LCD_OK){
// error occured
//TODO while(1);
}
LCD_ClearDisplay(&lcd);
LCD_ClearDisplay(&lcd);
HAL_Delay(5);
LCD_SetLocation(&lcd, 0, 0);
LCD_WriteString(&lcd, "Hover V2.0");
LCD_WriteString(&lcd, "Hover V2.0");
LCD_SetLocation(&lcd, 0, 1);
LCD_WriteString(&lcd, "Initializing...");
#endif
enable = 1;
enable = 1; // enable motors
while(1) {
HAL_Delay(5);
#ifdef CONTROL_NUNCHUCK
Nunchuck_Read();
cmd1 = CLAMP((nunchuck_data[0] - 127) * 8, -1000, 1000); // x - axis. Nunchuck joystick readings range 30 - 230
@ -168,8 +166,13 @@ int main(void) {
#endif
#ifdef CONTROL_ADC
cmd1 = CLAMP(adc_buffer.l_rx2 - 700, 0, 2350) / 2.35; // ADC values range 0-4095, however full range of our poti only covers 650 - 3050
uint8_t button1 = (uint8_t)(adc_buffer.l_tx2 > 2000);
// ADC values range: 0-4095, see ADC-calibration in config.h
cmd1 = CLAMP(adc_buffer.l_tx2 - ADC1_MIN, 0, ADC1_MAX) / (ADC1_MAX / 1000.0f); // ADC1
cmd2 = CLAMP(adc_buffer.l_rx2 - ADC2_MIN, 0, ADC2_MAX) / (ADC2_MAX / 1000.0f); // ADC2
// use ADCs as button inputs:
button1 = (uint8_t)(adc_buffer.l_tx2 > 2000); // ADC1
button2 = (uint8_t)(adc_buffer.l_rx2 > 2000); // ADC2
timeout = 0;
#endif
@ -184,17 +187,31 @@ int main(void) {
speedR = CLAMP(speed * SPEED_COEFFICIENT - steer * STEER_COEFFICIENT, -1000, 1000);
speedL = CLAMP(speed * SPEED_COEFFICIENT + steer * STEER_COEFFICIENT, -1000, 1000);
// ####### DEBUG SERIAL OUT #######
#ifdef CONTROL_ADC
setScopeChannel(0, (int)adc_buffer.l_tx2); // ADC1
setScopeChannel(1, (int)adc_buffer.l_rx2); // ADC2
#endif
setScopeChannel(2, (int)speedR);
setScopeChannel(3, (int)speedL);
#ifdef ADDITIONAL_CODE
ADDITIONAL_CODE;
ADDITIONAL_CODE;
#endif
// ####### SET OUTPUTS #######
if ((speedL < lastSpeedL + 50 && speedL > lastSpeedL - 50) && (speedR < lastSpeedR + 50 && speedR > lastSpeedR - 50) && timeout < TIMEOUT) {
#ifdef INVERT_R_DIRECTION
pwmr = speedR;
#else
pwmr = -speedR;
#endif
#ifdef INVERT_L_DIRECTION
pwml = -speedL;
#else
pwml = speedL;
#endif
}
lastSpeedL = speedL;