Simple piece of code for simulation sensor inputs of a hoverboard to do basic control of wheels.

Dependencies:   WiiNunchuck mbed-dev

This program is inspired by this site:

http://drewspewsmuse.blogspot.co.at/2016/06/how-i-hacked-self-balancing-scooter.html

Here you can get more information of the protocol revervse engineering.

This program uses a Wii nunchuk connected over I2C to controll the speed. Speed is controlled by a closed loop P controller. Feedback is done by counting HALL events from the brushless motor. Some more pictures are available here:

https://github.com/tyler123durden/hoverboard-hardware

Basically you need a serial TX and 3 HALL IRQs per motor side.

Wiring of the board. Gyro boards are not used, input is generated from nucleo board. Motor board has still the HALL connections. Nucleo board just also reads HALL inputs to get speed information for closed loop controll.

/media/uploads/Thomas_H/wiring.jpg

Committer:
Thomas_H
Date:
Thu Oct 13 08:57:49 2016 +0000
Revision:
0:fe156910301e
Child:
1:5acd27cb1857
nunchuck support

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Thomas_H 0:fe156910301e 1 #include "mbed.h"
Thomas_H 0:fe156910301e 2 #include "HallDecoder.h"
Thomas_H 0:fe156910301e 3 #include "WiiNunchuck.h"
Thomas_H 0:fe156910301e 4
Thomas_H 0:fe156910301e 5 //------------------------------------
Thomas_H 0:fe156910301e 6 // Hyperterminal configuration
Thomas_H 0:fe156910301e 7 // 9600 bauds, 8-bit data, no parity
Thomas_H 0:fe156910301e 8 //------------------------------------
Thomas_H 0:fe156910301e 9
Thomas_H 0:fe156910301e 10 #define HOVER_SPEED_MAX 1000
Thomas_H 0:fe156910301e 11
Thomas_H 0:fe156910301e 12 //Serial m_oPc(SERIAL_TX, SERIAL_RX);
Thomas_H 0:fe156910301e 13 Serial m_oPc(SERIAL_TX, SERIAL_RX); // PA_2, PA_3 -> SERIAL2
Thomas_H 0:fe156910301e 14
Thomas_H 0:fe156910301e 15 WiiNunchuck m_oNunchuck(PA_14, PA_15); // I2C1
Thomas_H 0:fe156910301e 16 #define NUNCHUCK_X_OFFSET 123
Thomas_H 0:fe156910301e 17 #define NUNCHUCK_Y_OFFSET 127
Thomas_H 0:fe156910301e 18
Thomas_H 0:fe156910301e 19 #define MOTOR_RIGHT_TXD PC_4 // SERIAL1
Thomas_H 0:fe156910301e 20 #define MOTOR_RIGHT_RXD NC
Thomas_H 0:fe156910301e 21 #define MOTOR_RIGHT_HALL1 PB_13
Thomas_H 0:fe156910301e 22 #define MOTOR_RIGHT_HALL2 PB_14
Thomas_H 0:fe156910301e 23 #define MOTOR_RIGHT_HALL3 PB_15
Thomas_H 0:fe156910301e 24
Thomas_H 0:fe156910301e 25 #define MOTOR_LEFT_TXD PB_10 // SERIAL3
Thomas_H 0:fe156910301e 26 #define MOTOR_LEFT_RXD NC
Thomas_H 0:fe156910301e 27 #define MOTOR_LEFT_HALL1 PB_6
Thomas_H 0:fe156910301e 28 #define MOTOR_LEFT_HALL2 PB_7
Thomas_H 0:fe156910301e 29 #define MOTOR_LEFT_HALL3 PB_9
Thomas_H 0:fe156910301e 30
Thomas_H 0:fe156910301e 31 DigitalOut myled(LED1);
Thomas_H 0:fe156910301e 32
Thomas_H 0:fe156910301e 33 int main()
Thomas_H 0:fe156910301e 34 {
Thomas_H 0:fe156910301e 35 RawSerial oMotorRight(MOTOR_RIGHT_TXD, NC);
Thomas_H 0:fe156910301e 36 oMotorRight.baud(26315);
Thomas_H 0:fe156910301e 37 oMotorRight.format(9, SerialBase::None, 1);
Thomas_H 0:fe156910301e 38
Thomas_H 0:fe156910301e 39 RawSerial oMotorLeft(MOTOR_LEFT_TXD, NC);
Thomas_H 0:fe156910301e 40 oMotorLeft.baud(26315);
Thomas_H 0:fe156910301e 41 oMotorLeft.format(9, SerialBase::None, 1);
Thomas_H 0:fe156910301e 42
Thomas_H 0:fe156910301e 43 int nControl = 0;
Thomas_H 0:fe156910301e 44
Thomas_H 0:fe156910301e 45 //HallDecoder oHallRight(MOTOR_RIGHT_HALL1, MOTOR_LEFT_HALL2, MOTOR_LEFT_HALL3);
Thomas_H 0:fe156910301e 46 //int32_t nTicks = oHallRight.getticks();
Thomas_H 0:fe156910301e 47
Thomas_H 0:fe156910301e 48 m_oPc.printf("Hello World !\n");
Thomas_H 0:fe156910301e 49
Thomas_H 0:fe156910301e 50 wait(1);
Thomas_H 0:fe156910301e 51 m_oPc.printf("SystemCoreClock = %d Hz\n", SystemCoreClock);
Thomas_H 0:fe156910301e 52
Thomas_H 0:fe156910301e 53 myled = !myled;
Thomas_H 0:fe156910301e 54
Thomas_H 0:fe156910301e 55 char c = ' ';
Thomas_H 0:fe156910301e 56 int16_t sp=0;
Thomas_H 0:fe156910301e 57 int16_t spl = 0;
Thomas_H 0:fe156910301e 58 int32_t nSpeedOld = 0;
Thomas_H 0:fe156910301e 59
Thomas_H 0:fe156910301e 60 while(1) {
Thomas_H 0:fe156910301e 61 m_oPc.printf("%d\n", c);
Thomas_H 0:fe156910301e 62 if(c == ' ') {
Thomas_H 0:fe156910301e 63 sp=0;
Thomas_H 0:fe156910301e 64 } else if(c == 'q') {
Thomas_H 0:fe156910301e 65 sp -= 10;
Thomas_H 0:fe156910301e 66 } else if(c == 'w') {
Thomas_H 0:fe156910301e 67 sp += 10;
Thomas_H 0:fe156910301e 68 } else if(c == '2') {
Thomas_H 0:fe156910301e 69 sp += 100;
Thomas_H 0:fe156910301e 70 } else if(c == '1') {
Thomas_H 0:fe156910301e 71 sp -= 100;
Thomas_H 0:fe156910301e 72 } else if(c=='r') {
Thomas_H 0:fe156910301e 73 //m_oPc.printf("Reset ticks");
Thomas_H 0:fe156910301e 74 //oHallRight.resetticks();
Thomas_H 0:fe156910301e 75 } else if(c=='n') {
Thomas_H 0:fe156910301e 76 if(nControl==0) {
Thomas_H 0:fe156910301e 77 m_oPc.printf("Change to nunchuck control");
Thomas_H 0:fe156910301e 78 nControl = 1;
Thomas_H 0:fe156910301e 79 } else {
Thomas_H 0:fe156910301e 80 m_oPc.printf("Change to nunchuck control");
Thomas_H 0:fe156910301e 81 nControl = 1;
Thomas_H 0:fe156910301e 82 }
Thomas_H 0:fe156910301e 83 } else if(c=='m') {
Thomas_H 0:fe156910301e 84 m_oPc.printf("nunchuck x: %d\n", m_oNunchuck.joyx());
Thomas_H 0:fe156910301e 85 m_oPc.printf("nunchuck x: %d\n", m_oNunchuck.joyy());
Thomas_H 0:fe156910301e 86 m_oPc.printf("nunchuck c: %d\n", m_oNunchuck.buttonc());
Thomas_H 0:fe156910301e 87 m_oPc.printf("nunchuck z: %d\n", m_oNunchuck.buttonz());
Thomas_H 0:fe156910301e 88 }
Thomas_H 0:fe156910301e 89
Thomas_H 0:fe156910301e 90
Thomas_H 0:fe156910301e 91 m_oPc.printf("speed %d\n", sp);
Thomas_H 0:fe156910301e 92
Thomas_H 0:fe156910301e 93 nSpeedOld = sp;
Thomas_H 0:fe156910301e 94 do {
Thomas_H 0:fe156910301e 95 //if(nTicks != oHallRight.getticks()) {
Thomas_H 0:fe156910301e 96 // nTicks = oHallRight.getticks();
Thomas_H 0:fe156910301e 97 // m_oPc.printf("Ticks 1: %d\n", nTicks);
Thomas_H 0:fe156910301e 98 //}
Thomas_H 0:fe156910301e 99
Thomas_H 0:fe156910301e 100 if(nControl) {
Thomas_H 0:fe156910301e 101 sp = ((m_oNunchuck.joyy()-NUNCHUCK_Y_OFFSET)*HOVER_SPEED_MAX) / 127;
Thomas_H 0:fe156910301e 102 if(nSpeedOld != sp) {
Thomas_H 0:fe156910301e 103 nSpeedOld = sp;
Thomas_H 0:fe156910301e 104 m_oPc.printf("speed %d\n", sp);
Thomas_H 0:fe156910301e 105 }
Thomas_H 0:fe156910301e 106 if(m_oNunchuck.buttonc()) {
Thomas_H 0:fe156910301e 107 m_oPc.printf("switch back to auto mode\n");
Thomas_H 0:fe156910301e 108 nControl = 0; // fallback to manual controll
Thomas_H 0:fe156910301e 109 }
Thomas_H 0:fe156910301e 110 }
Thomas_H 0:fe156910301e 111
Thomas_H 0:fe156910301e 112 oMotorRight.putc(256);
Thomas_H 0:fe156910301e 113 oMotorRight.putc(sp & 0xFF);
Thomas_H 0:fe156910301e 114 oMotorRight.putc((sp >> 8) & 0xFF);
Thomas_H 0:fe156910301e 115 oMotorRight.putc(sp & 0xFF);
Thomas_H 0:fe156910301e 116 oMotorRight.putc((sp >> 8) & 0xFF);
Thomas_H 0:fe156910301e 117 oMotorRight.putc(85);
Thomas_H 0:fe156910301e 118 oMotorRight.putc(82);
Thomas_H 0:fe156910301e 119 oMotorRight.putc(82);
Thomas_H 0:fe156910301e 120
Thomas_H 0:fe156910301e 121 spl = sp * -1;
Thomas_H 0:fe156910301e 122 oMotorLeft.putc(256);
Thomas_H 0:fe156910301e 123 oMotorLeft.putc(spl & 0xFF);
Thomas_H 0:fe156910301e 124 oMotorLeft.putc((spl >> 8) & 0xFF);
Thomas_H 0:fe156910301e 125 oMotorLeft.putc(spl & 0xFF);
Thomas_H 0:fe156910301e 126 oMotorLeft.putc((spl >> 8) & 0xFF);
Thomas_H 0:fe156910301e 127 oMotorLeft.putc(85);
Thomas_H 0:fe156910301e 128 oMotorLeft.putc(82);
Thomas_H 0:fe156910301e 129 oMotorLeft.putc(82);
Thomas_H 0:fe156910301e 130 wait_us(300);
Thomas_H 0:fe156910301e 131 } while(!m_oPc.readable());
Thomas_H 0:fe156910301e 132 c=m_oPc.getc();
Thomas_H 0:fe156910301e 133 }
Thomas_H 0:fe156910301e 134 }
Thomas_H 0:fe156910301e 135