Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: WiiNunchuck mbed-dev
main.cpp
- Committer:
- Thomas_H
- Date:
- 2016-10-23
- Revision:
- 1:5acd27cb1857
- Parent:
- 0:fe156910301e
File content as of revision 1:5acd27cb1857:
#include "mbed.h"
#include "HallDecoder.h"
#include "WiiNunchuck.h"
//------------------------------------
// Hyperterminal configuration
// 9600 bauds, 8-bit data, no parity
//------------------------------------
#define NELEMS(x) (sizeof(x) / sizeof(x[0])) // number of elements in array
#define DEBUG_SERIAL_SPEED 115200
#define NUNCHUCK_I2C_CLK PA_15
#define NUNCHUCK_I2C_SDA PA_14
#define NUNCHUCK_X_OFFSET 123
#define NUNCHUCK_Y_OFFSET 127
#define MOTOR_LEFT_TXD PB_10 // SERIAL1
#define MOTOR_LEFT_RXD NC
#define MOTOR_LEFT_HALL1 PB_15
#define MOTOR_LEFT_HALL2 PB_14
#define MOTOR_LEFT_HALL3 PB_6
#define MOTOR_RIGHT_TXD PC_4 // SERIAL3
#define MOTOR_RIGHT_RXD NC
#define MOTOR_RIGHT_HALL1 PC_7
#define MOTOR_RIGHT_HALL2 PA_8
#define MOTOR_RIGHT_HALL3 PA_9
#define HOVER_SPEED_MAX (90*2) // ticks per second
/******************************************************************************/
WiiNunchuck m_oNunchuck(NUNCHUCK_I2C_SDA, NUNCHUCK_I2C_CLK); // I2C1
Serial m_oPc(SERIAL_TX, SERIAL_RX); // PA_2, PA_3 -> SERIAL2
Timer m_oTimer;
Ticker m_oPeriodic;
DigitalOut led1(LED1);
HallDecoder oHallLeft(MOTOR_LEFT_HALL1, MOTOR_LEFT_HALL2, MOTOR_LEFT_HALL3);
HallDecoder oHallRight(MOTOR_RIGHT_HALL1, MOTOR_RIGHT_HALL2, MOTOR_RIGHT_HALL3);
typedef struct t_controller {
int16_t w; //< setpoint
int16_t u; //< input for controler
int16_t y; //< actual value
int16_t yfilt[3];
int16_t e; //< error
int16_t eSum; //< error sum
float kp; //< controller setting
float ki; //< controller setting
float kd; //< controller setting
} t_controller;
#define LEFT 0
#define RIGHT 1
volatile t_controller _Controlloop[2];
#define MAX_ERROR 100
/******************************************************************************/
// periodic timed control stuff
void ticker()
{
// get new inputs
int nTicks[2];
nTicks[LEFT] = oHallLeft.getticks();
nTicks[RIGHT] = oHallRight.getticks();
oHallLeft.resetticks();
oHallRight.resetticks();
// for both sides
for(int i=0; i<NELEMS(_Controlloop); i++) {
_Controlloop[i].yfilt[0] = _Controlloop[i].yfilt[1];
_Controlloop[i].yfilt[1] = _Controlloop[i].yfilt[2];
_Controlloop[i].yfilt[2] = nTicks[i];
_Controlloop[i].y = (_Controlloop[i].yfilt[0]+_Controlloop[i].yfilt[1]+_Controlloop[i].yfilt[2])/3; // low pass filter
// some max value clipping
if(abs(_Controlloop[i].y)>500) {
_Controlloop[i].y = 0;
}
int16_t nError = _Controlloop[i].w - _Controlloop[i].y;
if(nError>MAX_ERROR) {
nError = MAX_ERROR;
} else if(_Controlloop[i].w - _Controlloop[i].y<-MAX_ERROR) {
nError = -MAX_ERROR;
}
// actual controller equation part
_Controlloop[i].eSum += nError;
if(_Controlloop[i].eSum>100 ) {
_Controlloop[i].eSum = 100;
}
else if( _Controlloop[i].eSum<-100) {
_Controlloop[i].eSum = -100;
}
_Controlloop[i].u = nError* _Controlloop[i].kp + _Controlloop[i].eSum * _Controlloop[i].ki;
_Controlloop[i].e = nError;
}
// reverse one wheel direction to get same rotation direction for positive inputs
_Controlloop[LEFT].u = _Controlloop[LEFT].u * -1;
led1 = !led1;
}
/******************************************************************************/
int main()
{
m_oPc.baud(DEBUG_SERIAL_SPEED);
m_oTimer.start();
m_oPeriodic.attach(ticker, 0.5);
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 = 1;
for(int i=0; i<NELEMS(_Controlloop); i++) {
_Controlloop[i].kp = 2.0;
_Controlloop[i].ki = 0.3;
_Controlloop[i].kd = 0;
}
m_oPc.printf("Hello Hoverboard !\n");
wait(1);
m_oPc.printf("SystemCoreClock = %d Hz\n", SystemCoreClock);
char c = ' ';
while(1) {
m_oPc.printf("%d\n", c);
if(c == ' ') {
_Controlloop[LEFT].w =0;
} else if(c == 'q') {
_Controlloop[LEFT].w -= 10;
} else if(c == 'w') {
_Controlloop[LEFT].w += 10;
} else if(c == '2') {
_Controlloop[LEFT].w += 100;
} else if(c == '1') {
_Controlloop[LEFT].w-= 100;
} else if(c=='r') {
m_oPc.printf("Reset ticks\n");
oHallLeft.resetticks();
oHallRight.resetticks();
} else if(c=='n') {
if(nControl==0) {
m_oPc.printf("Change to nunchuck control");
nControl = 1;
} else {
m_oPc.printf("Change to keyboard control");
nControl = 0;
}
} 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", _Controlloop[LEFT].w);
// main control loop
do {
if(m_oTimer.read_ms() > 500) {
m_oTimer.reset();
m_oPc.printf("Speed set %d speed: %d speed out: %d error: %d \n",
_Controlloop[LEFT].w, _Controlloop[LEFT].y, _Controlloop[LEFT].u, _Controlloop[LEFT].e);
m_oPc.printf(" Speed set %d speed: %d speed out: %d error: %d \n",
_Controlloop[RIGHT].w, _Controlloop[RIGHT].y, _Controlloop[RIGHT].u, _Controlloop[RIGHT].e);
}
if(nControl) {
int nJoyY = ((m_oNunchuck.joyy()-NUNCHUCK_Y_OFFSET)*HOVER_SPEED_MAX) / 127; // + -> forward
int nJoyX = ((m_oNunchuck.joyx()-NUNCHUCK_X_OFFSET)*HOVER_SPEED_MAX) / 127; // + -> right
if(m_oNunchuck.buttonz()) {
// same inputs for both wheels
_Controlloop[LEFT].w = nJoyY;
_Controlloop[RIGHT].w = nJoyY;
}
else {
_Controlloop[LEFT].w = nJoyY + nJoyX/2;
_Controlloop[RIGHT].w = nJoyY - nJoyX/2;
}
if(m_oNunchuck.buttonc()) {
m_oPc.printf("switch back to auto mode\n");
nControl = 0; // fallback to manual controll
}
}
oMotorRight.putc(256);
oMotorRight.putc(_Controlloop[RIGHT].u & 0xFF);
oMotorRight.putc((_Controlloop[RIGHT].u >> 8) & 0xFF);
oMotorRight.putc(_Controlloop[RIGHT].u & 0xFF);
oMotorRight.putc((_Controlloop[RIGHT].u >> 8) & 0xFF);
oMotorRight.putc(85);
oMotorRight.putc(82);
oMotorRight.putc(82);
wait_ms(1);
oMotorLeft.putc(256);
oMotorLeft.putc(_Controlloop[LEFT].u & 0xFF);
oMotorLeft.putc((_Controlloop[LEFT].u >> 8) & 0xFF);
oMotorLeft.putc(_Controlloop[LEFT].u & 0xFF);
oMotorLeft.putc((_Controlloop[LEFT].u >> 8) & 0xFF);
oMotorLeft.putc(85);
oMotorLeft.putc(82);
oMotorLeft.putc(82);
} while(!m_oPc.readable());
c=m_oPc.getc();
}
}