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

Revision:
0:fe156910301e
Child:
1:5acd27cb1857
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Oct 13 08:57:49 2016 +0000
@@ -0,0 +1,135 @@
+#include "mbed.h"
+#include "HallDecoder.h"
+#include "WiiNunchuck.h"
+
+//------------------------------------
+// Hyperterminal configuration
+// 9600 bauds, 8-bit data, no parity
+//------------------------------------
+
+#define HOVER_SPEED_MAX 1000
+
+//Serial m_oPc(SERIAL_TX, SERIAL_RX);
+Serial m_oPc(SERIAL_TX, SERIAL_RX);     // PA_2, PA_3 -> SERIAL2
+
+WiiNunchuck m_oNunchuck(PA_14, PA_15);    // I2C1
+#define NUNCHUCK_X_OFFSET   123
+#define NUNCHUCK_Y_OFFSET   127
+
+#define MOTOR_RIGHT_TXD     PC_4        // SERIAL1
+#define MOTOR_RIGHT_RXD     NC
+#define MOTOR_RIGHT_HALL1   PB_13
+#define MOTOR_RIGHT_HALL2   PB_14
+#define MOTOR_RIGHT_HALL3   PB_15
+
+#define MOTOR_LEFT_TXD      PB_10       // SERIAL3
+#define MOTOR_LEFT_RXD      NC
+#define MOTOR_LEFT_HALL1    PB_6
+#define MOTOR_LEFT_HALL2    PB_7
+#define MOTOR_LEFT_HALL3    PB_9
+
+DigitalOut myled(LED1);
+
+int main()
+{
+    RawSerial oMotorRight(MOTOR_RIGHT_TXD, NC); 
+    oMotorRight.baud(26315);
+    oMotorRight.format(9, SerialBase::None, 1);
+    
+    RawSerial oMotorLeft(MOTOR_LEFT_TXD, NC); 
+    oMotorLeft.baud(26315);
+    oMotorLeft.format(9, SerialBase::None, 1);
+
+    int nControl = 0;
+
+    //HallDecoder oHallRight(MOTOR_RIGHT_HALL1, MOTOR_LEFT_HALL2, MOTOR_LEFT_HALL3);
+    //int32_t nTicks = oHallRight.getticks();
+
+    m_oPc.printf("Hello World !\n");
+
+    wait(1);
+    m_oPc.printf("SystemCoreClock = %d Hz\n", SystemCoreClock);
+
+    myled = !myled;
+
+    char c = ' ';
+    int16_t sp=0;
+    int16_t spl = 0;
+    int32_t nSpeedOld = 0;
+
+    while(1) {
+        m_oPc.printf("%d\n", c);
+        if(c == ' ') {
+            sp=0;
+        } else if(c == 'q') {
+            sp -= 10;
+        } else if(c == 'w') {
+            sp += 10;
+        } else if(c == '2') {
+            sp += 100;
+        }  else if(c == '1') {
+            sp -= 100;
+        } else if(c=='r') {
+            //m_oPc.printf("Reset ticks");
+            //oHallRight.resetticks();
+        } else if(c=='n') {
+            if(nControl==0) {
+                m_oPc.printf("Change to nunchuck control");
+                nControl = 1;
+            } else {
+                m_oPc.printf("Change to nunchuck control");
+                nControl = 1;
+            }
+        } else if(c=='m') {
+            m_oPc.printf("nunchuck x: %d\n", m_oNunchuck.joyx());
+            m_oPc.printf("nunchuck x: %d\n", m_oNunchuck.joyy());
+            m_oPc.printf("nunchuck c: %d\n", m_oNunchuck.buttonc());
+            m_oPc.printf("nunchuck z: %d\n", m_oNunchuck.buttonz());
+        }
+
+
+        m_oPc.printf("speed %d\n", sp);
+        
+        nSpeedOld = sp;
+        do {
+            //if(nTicks != oHallRight.getticks()) {
+            //    nTicks = oHallRight.getticks();
+            //    m_oPc.printf("Ticks 1: %d\n", nTicks);
+            //}
+
+            if(nControl) {
+                sp = ((m_oNunchuck.joyy()-NUNCHUCK_Y_OFFSET)*HOVER_SPEED_MAX) / 127;
+                if(nSpeedOld != sp) {
+                    nSpeedOld = sp;
+                    m_oPc.printf("speed %d\n", sp);
+                }
+                if(m_oNunchuck.buttonc()) {
+                    m_oPc.printf("switch back to auto mode\n");
+                    nControl = 0;   // fallback to manual controll
+                }
+            }
+
+            oMotorRight.putc(256);
+            oMotorRight.putc(sp & 0xFF);
+            oMotorRight.putc((sp >> 8) & 0xFF);
+            oMotorRight.putc(sp & 0xFF);
+            oMotorRight.putc((sp >> 8) & 0xFF);
+            oMotorRight.putc(85);
+            oMotorRight.putc(82);
+            oMotorRight.putc(82);
+            
+            spl = sp * -1;
+            oMotorLeft.putc(256);
+            oMotorLeft.putc(spl & 0xFF);
+            oMotorLeft.putc((spl >> 8) & 0xFF);
+            oMotorLeft.putc(spl & 0xFF);
+            oMotorLeft.putc((spl >> 8) & 0xFF);
+            oMotorLeft.putc(85);
+            oMotorLeft.putc(82);
+            oMotorLeft.putc(82);
+            wait_us(300);
+        } while(!m_oPc.readable());
+        c=m_oPc.getc();
+    }
+}
+