
New button pressed by foot when standing on board replaces the original hand held cut-out switch
It reminds me of one of the WW2 "Dambusters" Lancasters
with the chain driven back-spinning bouncing bomb.
INTRODUCTION
The aim of this project is to build a skateboard based on Segway self-balancing principles. Some skateboards of this type already have been built by others and links to most of the relevant webpages are listed.
This is a work in progress............
Many of those who have built segway clones and self balancing robots do appear to be experienced programmers and possibly already in the IT industry. I am approaching this from another angle having maintained classic cars, being familiar with car electrics and hobby electronic projects. The last time I wrote any computer code was in "BASIC" for my Sinclair computer aged 14 years.
This site will not be an overview that assumes a lot of coding knowledge but will be for "newbies" like me. I have had to learn both how to program in "C" and also specifically how to use this to program an AVR microcontroller. These skills will be useful to me in other aspects of my life and work while the challenge of this project gives me the motivation.
My detective work on the net has yielded a large list of links which I have listed below. Some of them are essential reading before embarking on a project like this.
If you get fed up when things are not going well, have a look at the youtube videos of Ben Smithers, Trevor Blackwell and others!
The skateboard has a number of advantages over a segway clone
1) If it goes wrong (i.e. stops suddenly) you can jump off at a run rather than impaling yourself on the handlebars then being propelled headfirst into the ground. There may be a very good reason why all but the most self-confident Segway clone builders put their controls off to one side!
2) If designed with some thought, it could actually be made to look quite cool unlike a segway.
3) There is no differential wheel speed coding required to make it turn, I can concentrate entirely on trying to get the thing to balance.
Basics of the design
From all my reading of the work of others, the general idea is this:
1) A gyroscope (solid state) decides if the board is tipping (falling over) and speeds up the motor to bring the board back into balance beneath you.
2) The more you are tipping the faster it tries to do this PLUS the faster you are tipping the faster it tries to do this.
3) The problem is the gyro can “drift” with time, but on the other hand it has fast response and is quite immune to vibration. To overcome this drift we utilise a small part of the signal from an accelerometer with each “loop” of the control software. The accelerometer is good because it does not drift and knows which way is “up”, however is quite influenced by any vibration. By adding in a small part of the signal each time we are in effect looking at the average reading over time so random vibration errors should tend to cancel out. See my links page for info on theory of self balancing systems.
4) Hardware: Lead-acid batteries. Because they are cheap and can deliver large current in small bursts if needed – and this is needed because although you need very little power to roll along a level surface, you need a big reservoir of “spare” motor power for the board to bring itself back beneath your centre of gravity if you start to tip over.
5) ATMega 32 microcontroller on a small development board from a robot webstore.
6) 4 potentiometers give manual control of 4 of the constants in the computer balance algorithm. These were initially in a hand-held controller and the idea is to “tune” the balance algorithm while standing on the board rather than changing values in the code each time. When optimum settings are found I can then convert the values found this way into the actual computer code. These analogue hardware “tricks” will hopefully allow me to keep my code relatively straightforward as I am on a rapid coding learning curve.
7) Widest Go-Kart rear wheel available (18cm wide), Go-Kart shortened rear axle, Go-Kart bearings, sprocket carrier, sprocket, chain. 420W electric motor with small drive sprocket.
8) Motor controller is the “OSMC” from the USA used by some others and developed for large combat robots.
9) Chassis sides are made from laser cut steel sheet.
Cardboard mockup to get dimensions correct. Start with wheel, then look at motor. Allow some side to side movement of motor (slotted bolt holes) to get tension on chain exactly right. "Kick ups" each end allow board to be shorter as electronics boxes go inside these, also allows you to theoretically go up hills with board tilted forwards to make it go up the hill, without front end hitting the ground. Small wheels from a skateboard mounted at each end semi-recessed limit damage during development process!
I have used aluminium alloy between the two steel side plates to reduce weight a little. One side is riveted to the steel panel while the other side panel will be held on by lots of small bolts. This allows the bolted side panel to be taken off to assemble the axle, wheel and bearings more easily. As you can see I have several sizes of sprocket for the main wheel. For initial tests I have chosen to use a very large sprocket which will give me a slow top speed but much more torque at the wheel for getting up hills.
I have tried to create bulkheads where feasible and box sections to give strength. It would be nice to think I have created something as elegant as the monocoque frame of a 1960's Formula 1 racing car but in truth it is not quite as good as that!
To stop drilling holes through alloy and then having the bit go straight into electronics I made a handy safety device clamped to the drill bit made from the brass insert from a wire connection block.
Above: Programming the microcontroller using serial port of a laptop and "Ponyprog" software. Programming Software written in C using AVR Studio 4. The AVRStudio contains a simulator, debugger etc. Loaded from Laptop to Microcontroller using a serial cable.
Trimming excess alloy from the motor to get it to fit within the 10cm deep chassis rails.Original plan was to have 2 batteries side by side and micro in a box at far end. However with this setup it is much heavier on the motor side. I have therefore moved one battery out to far end where control box would have been. Not quite as neat and tidy but better for weight distribution. Also you can see there is just enough space to fit a third battery if I want to go to 36 Volts later on (which would probably even up the weight as well).
Originally I had the 4 potentiometers built into the hand controller. Later on I moved them down into the chassis of the machine and just had a "dead man's handle" push-to-make switch in a very simple hand controller. This is very light so if dropped (when falling off) it will cut motor but controller will not break when it hits the floor. If it does braek there is only one switch to replace. Other options are footswitches of various types or a plug that is pulled out if you fall off, as found on drag racing motorbikes and jetskis.
Bearings are for 30mm tubular axle from rear of a Go-kart.
Solid steel axle at moment, very heavy, may replace with aluminium at a later date as part of a weight reduction exercise.
Wiring tidied up behind alloy channel sections as they run from one side to the other. I do not want the wheel to rub through the wiring insulation causing a disaster. Ribbon cable was difficult to route along the side of the machine and has been well wrapped in plastic tubing where it enters through holes in the frame to stop any chance of it chafing against metal edges.
After destroying my gyro by accidentally putting 12V through it, I have used an opto-isolator board from Quasar Electronics to use my logic outputs to control a 12V buzzer (>70% duty cycle warning) and some 12V LED warning lamps (low battery warning. These completely isolate the logic outputs of the microprocessor from the switched 12V items. This may seem excessive but blowing up gyros is a very expensive thing to do.
FURTHER DEVELOPMENTS
Things I could do if money no object:
1) Rebuild frame in carbon fibre. Failing that I could do it in fibreglass with a steel stengthening panel embedded in the structure between the motor and the wheel on the chain side.
2) Better batteries, Lithium too expensive so perhaps NiMH.
3) Hub motor inside wheel would free up plenty of space to make frame smaller.
4) Another possible variant would be to have a 3 speed gearbox in the wheel hub. Thinking of the old cable operated "Sturmey-Archer" boxes found in 1970's bicycles like the "Chopper" which are small light and simple. Would need to disable the freewheel mechanism however! It would allow fast speeds on the level but give lower gearing for hills and rougher terrain.
5) Have twin wheels next to each other. This would require 2 motor controllers, 2 motors (? hub motors) but allow much better low speed turning and ability to turn on the spot.
6) Ideal power plant would be a MICE engine. This is being developed in US, has interest from the military. It is a very small, gasoline powered electricity generator. It has a magnetic piston that oscillates up and down in a coil of wire extremely fast. It therefore has only one main moving part, functions as an alternator, power output 200-500W. This would be absolutely perfect for my application, would give plenty of space for a fuel tank and turn it from a novelty into a vehicle of sorts with decent power and endurance.
MICE engine links:
Update August 08: Guess what, I asked them and they said no!
LINKS
Other projects:
Ben Smithers skateboard Click here
Ben Smithers website Click here
Early German unicycle website Click Here
More on this unicycle Click Here
Trevor Blackwell build your own segway site. Click Here
Version 2 of this scooter Click Here
More on how to build one of these Click Here
His self balancing unicycle. Has downloadable code. As unicycle only has one wheel the code is very
relevant for a self balancing one wheeled skateboard. Study it.... Click Here
MUST SEE: Recent electric unicycle project from Slovenia. www.enicycle.com Uses a hub motor. The other really great thing is that it has a steering mechanism that means you can learn to ride it in 10 minutes. Superb YouTube video of him riding it around town, around a shopping centre, down a corridor and into the office! Click Here
MIT segway project:
IMPORTANT download their technical specifications and definitely read the article on the “balance
filter” by Shane Colton. This explains in plain English how simple (relative to a Kalman filter anyway) self balancing can be made to work and how the signals from the gyro and the accelerometer are used.
Without this article I would have really struggled to understand how this can be done although elements of this algorithm do appear in the software of others in this list. Click Here
My machine uses a "Complimentary Filter" which I believe is not quite the same thing as a "Kalman" filter which is more complex but in theory at least is "better" than a complimentary one. Having said that some have tried Kalman and found that the complimentary trial and error based methods worked best for them. If you want to know about the proper Kalman filter then look here if you can handle the maths: Click here
Robot Power (who supply the OSMC motor controller) Click Here
Active Robots microcontroller boards. Click Here
Free book on how to program in “C” language for those of us who needed to learn this. Click Here
A good set of AVR programming tutorials (i.e. how to program the Atmel series of microcontrollers). Click Here
Excellent tutorial for the complete newbie to AVR programming as I was. Click Here
Gyrobot balancing robot, has some downloadable code for you to study. Click Here
Malcolm Faed has build a Segway type vehicle. Click Here
Geoffrey D Bennett has built “Meta” also a Segway type vehicle. Has downloadable code. Study it. Click Here
Another segway built on low budget very quickly. Click Here
AVRbeginners net.................self explanatory really! Click Here
Another University self balancing skateboard, not quite as good as the Ben Smithers one. Click Here
A neat small Segway project as part of an Atmel design competition. Download his abstract and then the full pdf write up of the project as it has a lot of useful information and code. Click Here
Maiden voyage of the “Leviskate” self balancing skateboard. Click Here
University of Michigan M-skate self balancing skateboard: This seems to have disappeared from youtube.
I love this one, the “Leango”, like riding on an upside down trackball. Click Here
Another homebuilt segway clone. Click Here
Segway project from ?Vietnam. Click Here
Ginger 2, a new home made segway project. Click Here
(Ginger was the codename for the Segway before it was launched)
A really excellent Scandinavian segway project. Click Here
Stanford University skateboard with 2 wheels. Click Here
Another good, working, self balancing skateboard. Click Here
Skatanova self balancing 2 wheeled skateboard. Click Here
Rotanova scooter. Click Here
The Segskate. Click Here
The ECOW scooter. Click Here
The two wheel deal from Purdue. Click Here
Segway clone with attached barstool. See their website for description of some of the injuries you can acquire during development! Their test driver does seem especially bold in his approach. Click Here
Another one. Click Here
Another. Click here
The Mway-III. Click Here
Long video on the Mway build. Click Here
Very good segway clone from Australia. Son of EDGAR. Click Here
Theory of PID controller tuning. Click Here
Phenomenal video from 1950's of a one wheeled vehicle powered by petrol engine and balanced by a
mechanical gyro around country roads. Click Here
Toyota "Winglet" mini-Segway clone. Click Here
Another homebuild segway. Click Here
Parts suppliers
Quasar Electronics. Click Here
Silicon Sensing Systems. Click Here
Maplin. Click Here
RadioSpares. Click Here
Azusa engineering. Click Here
Active Robots. Click Here
Robot Power (OSMC). Click Here
More to follow............
CODE
I must reiterate that I had to teach myself "C" before doing this so please don't laugh at my code.
I have used lots of floating point arithmetic which I know is processor hungry and not optimally efficient. However, by keeping the algorithms simple, avoiding trigonometry (sines etc) and using a reasonably fast processor, I have a program that cycles quickly enough to do the job. Many builders of this sort of thing are reluctant to put their code on the web as it is obviously possible to injure yourself with a machine like this and such code comes with no guarantees. The best option therefore is for me to explain the important parts of the algorithm here and then people can email me if they want to know more.
Here are the main important bits (data collection and calculation of the duty cycle to send to the motor pulse width modulator):
/*
IO:
I am using ATMega32 16MHz with external crystal clock. New planned pin arrangement to OSMC motor controller
PC4 Onboard LED
PD5/OC1A ALI -> OSMC pin 6
PD4/OC1B BLI -> OSMC pin 8
PC1 Disable -> OSMC pin 4
PC2 BHI -> OSMC pin 7
PC3 AHI -> OSMC pin 5
PA6/ADC6 Vbatt/10 -> OSMC pin 3
PA1/ADC1 pitch rate gyro
PA0/ADC0 accelerometer
*/
void adc_init(void) {
/* turn off analogue comparator as we don't use it */
ACSR = (1 << ACD);
/* select PA0 */
ADMUX = 0;
ADMUX |=(1<<REFS0); /*This tells it to use VCC (approx 5V) as the reference
voltage NOT the default which is the internal 2.5V reference*/
/* Set ADC prescaler to 128, enable ADC, and start conversion */
ADCSRA = 0 | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
| (1<<ADEN) //enable ADC
| (1<<ADSC); //start first conversion
/* wait until bogus first conversion finished */
while (ADCSRA & (1 << ADSC)) {
}
}
uint16_t adc_read(uint8_t channel) {
/* select channel */
ADMUX = channel;
ADMUX |=(1<<REFS0);
/* start conversion */
ADCSRA |= (1 << ADSC);
/* wait until conversion finished */
while (ADCSRA & (1 << ADSC)) {
}
/* return the result */
return ADCW;
}
/* 80.6 cycles per sec, 12.4ms per cycle MEASURED ON OSCILLOSCOPE*/
/* read all the ADC inputs and do some conversion */
void sample_inputs(void) {
cli();
uint16_t adc0, adc1, adc2, adc3, adc4, adc5, adc6;
accsum=0;
gyrosum=0;
for (i=0; i<20; i++) {
adc0 = adc_read(0); /* accelerometer pin PA0 */
adc1 = adc_read(1); /* gyro pin PA1*/
accsum= (float) accsum+adc0;
gyrosum= (float) gyrosum+adc1;
}
adc2 = adc_read(2); /* constant ti*/
adc3 = adc_read(3); /* constant k1 PA3*/
adc4 = adc_read(4); /* constant k2 PA4*/
adc5 = adc_read(5); /* constant overallgain PA5*/
adc6 = adc_read(6); /*battery status (via the OSMC I think..yes VBatt/10 is OSMC Pin3) pin PA6*/
sei();
PORTB |= (1<<PB1);//Port B1 turned on/off once per loop so I can measure loop time with an oscilloscope
/*Filtering to remove voltage spikes then RESCALING of each parameter*/
ti=(float) ti*0.9 + 0.1*((adc2-30)/512); //0-2 range scaling factor for gyroangledt, supposed to represent fine tuner for time per cycle in milliseconds. A setting of about 1.8 works well for me.
if (ti<0) ti=0;
k1=(float) k1*0.9 + 0.1*((adc3-30)/204); //gives a range of 0-5 (a setting of 4 works well for me)
if (k1<0) k1=0;
k2=(float) k2*0.9 + 0.1*((adc4-30)/512); //gives a range of 0-2 (a setting of 0.5 works well here)
if (k2<0) k2=0;
overallgain=(float) overallgain*0.9 + 0.1*((adc5-30)/341); //gives a range of about 0-3 (I have it on 1)
if (adc5<100) overallgain=0;
batteryvolts=(float) batteryvolts*0.9 + 0.1*((adc6-30)/20.5);
/*ACCELEROMETER signal processing*/
/*Subtract offsets*/
x_acc=(float) (accsum/20) - 500;
if (x_acc<-100) x_acc=-100; //cap accel values to a range of -100 to +100 (30 degree tilt each way)
if (x_acc>100) x_acc=100;
/* Accelerometer angle change is about 3.45 units per degree tilt in range 0-30 degrees(sin theta)
Convert tilt to degrees of tilt from accelerometer sensor. Sin angle roughly = angle for small angles so
no need to do trigonometry. x_acc below is now in DEGREES*/
x_accdeg= -x_acc/3.45; //The minus sign corrects for a back to front accelerometer mounting!
/*GYRO signal processing*/
/*Subtract offsets: Sensor reading is 0-1024 so "balance point" i.e. my required zero point will be that
reading minus 512*/
ganglerate= (float) (gyrosum/20) - 512;
/*Gyro angle change of 20mV per deg per sec from datasheet gives change of 4.096 PWM units per degree
per sec angle change
This limits the rate of change of gyro angle to just less than the maximum rate it is actually capable
of measuring (100deg/sec)*/
if (ganglerate < -380) ganglerate=-380;
if (ganglerate >380) ganglerate=380;
/*ganglerate now is converted to DEGREES per second below*/
ganglerate=ganglerate/4.096;
/*I turn port B1 on and off once per main program cycle so I can attach an oscilloscope to it and
work out the program cycle time. I use the cycle time to work out gyro angle change per cycle where
you have to know the length of this time interval*/
PORTB &= (0<<PB1);
/*ti represents scaling for the "i" or integral factor
gyroangledt is angle change since last CYCLE in degrees from gyro sensor, where ti is scaling
factor (should be about 1) 0.0124 is the time per cycle in milliseconds as measured using oscilloscope. By adjusting ti I can fine tune this according to the "feel" of the board when riding it. Turning up ti makes board feel much taughter and flatter in operation (slightest tilt is corrected instantly), if ti turned down, board tips more before responding with corrective action...it feels more "sloppy" in action (still balances though, quite tolerant in fact to such changes).
ganglerate is now in units of degrees per second aa varies the time constant, i.e smaller aa
value makes accelerometer time constant longer as it slowly corrects for the gyro drift*/
aa=0.01;
gyroangledt = (float)ti*0.0124*gangleratedeg;
gyro angle rate now converted to radians
gangleraterads=(float)gangleratedeg*0.017453;
/*new angle in DEGREES is old angle plus change in angle from gyro since last cycle with little bit
of new accel reading factored in*/
angle = ((1-aa) * (angle+gyroangledt)) + (aa * x_accdeg); //the main angle calculating function*/
/*Convert new angle from degrees to radians
anglerads=angle*0.017453;
level=(float)((k1*anglerads) + (k2*gangleraterads)) * overallgain;//the main duty cycle calculating function
This simpler version also balances OK when you are starting out: level=(float) k1*anglerads * overallgain; However by adding the (k2*gangleraterads) term to this equation, the motor will then accelerate sharply if you tilt over rapidly (eg if you hit a small obstacle for example) as it adds a term that increases in proportion to the gyro rate i.e. the rate of tipping over.
So if you are suddenly tipping over fast, motor will kick back to correct it on the gyro alone (gyro has fast response, slow drift remember).
However, if not tipping and wobbling like this, then machine will balance nicely minding its own business using the gyro and accelerometer together as complimetary pair. This means you have more chance of getting over a small obstacle with a slight forward "wobble" (and resultant motor kick) rather than just having the thing tip over on anything but the flattest surface and yet it still behaves in a more docile way when on a flat surface balancing nicely and rolling smoothly along.
/*Set up buzzer on Port B2 to warn me to slow down if torque to be delivered is more than 50% of max
possible. The reason for this is that you always need some reserve motor power in case you start tipping forward at speed. If motor already running flat-out you would be about to fall over at high speed! I used an opto-isolator kit to allow the outputs to trigger the buzzer without any direct electrical contact (after I accidentally burned out the gyro).
Some also use an auto-tip back routine here to automatically limit top speed. For now I will do it this way as easier*/
if (level<-0.7 || level>0.7) {
PORTB|=(1<<PB2);
}
else {
PORTB &=(0<<PB2);
}
/*Low battery warning. Some people also automatically increase the overallgain as battery voltage drops*/
if (batteryvolts<19) {
PORTB |= (1<<PB3); //turn on port B3 warning LED if combined battery voltage drops below 19V
}
else {
PORTB &= (0<<PB3); //otherwise set it to off
}
}
/* Configure timer and set up the output pins OC1A(Pin PD5 on my micro) and OC1B(Pin PD4 on my micro) as phase-correct PWM channels. Note: Some strongly feel that locked-antiphase is the way to go as get
regenerative braking and good control around mid-balance point. Downside is that you can get a lot more noise and voltage spikes in system but these can be smoothed out with filters. Others are far more expert on this than I am so need to look into this for yourself but this is my understanding. My aim is to start with phase-correct as I just about understand it and others have used it OK, then develop from there*/
void timer_init()
{
TCCR0 = 0 |
(1<<CS02) | (1<<CS01) | (1<<CS00); // External clock to Pin T0 Clock on rising edge/1024
// PWM mode is "PWM, Phase Correct, 10-bit"
TCCR1A = 0 |
(1<<COM1A1) | (1<<COM1A0) | // set on match up, clear on match down
(1<<COM1B1) | (1<<COM1B0) | // set on match up, clear on match down
//NOTE: I originally had the 2 lines above set up like this after reading datasheet:
(1<<COM1A1) | (0<<COM1A0) |
(1<<COM1B1) | (0<<COM1B0) |
I found that it worked OK but occasionally if tilted quickly, the motor would just cut out dead. Something wrong with the PWM pulses almost seemed to overload the OSMC. This bug took me ages to work out. The version that works properly of course is the one Trevor Blackwell used originally. I should not have meddled with it!//
(1<<WGM11) | (1<<WGM10); //OCR1_Max is 1023 so these are set like this
TCCR1B = 0 |
(1<<CS10); // prescaler divide by 1 see P131 datasheet about prescaling values to change here.
/* 16 MHz / 1 / 1024 / 2 gives 8 kHz, probably about right */
}
void set_motor()
/* The leveli terms is the level term rescaled from -1024 to +1024 as an integer ready to send to the
PWM motor control ports that are in turn connected to the OSMC*/
{
if (level<-0.9) level= -0.9;//checks we are within sensible limits
if (level>0.9) level=0.9;
int16_t leveli = (int16_t)(level*1023);
if (leveli<-1000) leveli=-1000;/*double-checks we are within sensible PWM limits as do not want
to suddenly be thrown off the board*/
if (leveli>1000) leveli=1000;
if (leveli<0){ /*stops a PWM value of 0 ever being sent to OSMC. I am not sure about
this but some say on forums that motor might lock up as OSMC charge-pumps run down.*/
if (leveli>-10){
leveli=-10;
}
}
if (leveli>=0){
if (leveli<10){
leveli=10;
}
}
cli();
PORTC |= (0<<PC1); // AHI=1 (PinC3) and BHI=1 (PinC2) set both to ON for OSMC to work and both to OFF to shut motor down
NOTE: Not sure why but to stop motor cutting out on direction changes I decided in the end to hard
wire AHI and BHI to +12V
Un-disabled OSMC by setting PinC1 (above) output to zero, a 1 would disable the OSMC//
if (leveli<0) {
OCR1A = -leveli; /* ALI is PWM going backwards as leveli variable is a negative signed value,
keep the minus sign in here!*/
OCR1B = 0; // BLI = 0
}
else {
OCR1A = 0; // ALI = 0 going forwards as leveli variable is a positive signed value
OCR1B = leveli; // BLI is PWM
}
sei();
}
int main(void)
{
InitPorts();
adc_init();
timer_init();
/* Initial tilt-start code
Turn on micro while board tipped to one side,
rider about to step onto it, if tilt angle greater than 5 degrees then locked in this loop
until it is tipped to level position as rider gets onto board*/
tipstart=0;
while (tipstart<1){
sample_inputs();
if (x_accdeg<-5 || x_accdeg>5) {
tipstart=0;
}
else {
tipstart=1;
}
}
angle=0;
k2=0;
/* end of tilt start code. If go beyond this point then machine has become level and is active*/
sei();
while (1) {
sample_inputs();
set_motor();
}
}




















