children's electric bike controller.

Mad Professor

Senior Member
Good day all.

I am looking at starting a new picaxe project.

Last summer I brought some electric quad bikes for my children, and the kids loved them.

But the quad bikes just use a simple on/off switch to drive the motor.

So over the winter I have been thinking about making a controller to give them more control over the speed.

I have not yet designed any of the control boards yet, as I 1st wanted to start work on the picaxe software, To see if I could get it to do what I wanted.

It seems that most of the coding so far is all math based, and math is not my strong point at the best of times.

Here is the current code that I have come up with so far.
Code:
#picaxe 18M2									' 

let pinsB = %00000000								' 
let pinsC = %00000000								' 

'Inputs
symbol battery_voltage = C.0							' Battery voltage monitoring input.
symbol throttle = C.2								' Throttle input.
symbol foot_brake = B.0								' Foot brake input.

'Outputs
symbol power_contactor = B.7							' Drive motor power contactor output.
symbol drive_motor = B.6							' Drive motor output.

'Settings
symbol motor_freq = 15600							' Drive motor running Freq in Hz.
symbol tps_min = 0								' ADC Value for TPS Min.
symbol tps_max = 1023								' ADC Value for TPS Max.
symbol tps_safe = 10								' Max percentage of TPS permitted at powerup.

'
symbol pwm_freq = w12								' 
symbol pwm_duty = w13								' 


init:
low power_contactor								' Turn off power to drive motor power contactor.
pwmout drive_motor,off								' Turn off pwm signal to drive motor.

' insert math equel to "w12 = (1000000/motor_freq)-1			'

pause 1000										' Pause for 1000ms (1Sec).
sertxd ("EV Controller - Firmware v0.1 (09/03/2011)",cr,lf)		' 


powerup_throttle_check:
readadc10 throttle,w1								' Read raw ADC value of TPS, and store data into w1.
let w2 = tps_safe * tps_max							' 
let w3 = tps_safe * tps_min							' 
let w4 = w2 - w3									' 
let w5 = w4 / 100									' 
let w6 = tps_min + w5								' 
'debug										' 
if w1 >= w6 then goto powerup_throttle_check:				' 
if w1 < w6 then goto main:							' 
goto powerup_throttle_check:							' 


main:
readadc10 throttle,w1								' Read raw ADC value of TPS, and store data into w1.

'insert math to calc req pwm_duty based on tps value.

high power_contactor								' Turn on power to drive motor power contactor.
pwmout drive_motor,pwm_freq,pwm_duty					' 
debug										' 
goto main:										' 


interrupt:
low power_contactor								' Turn off power to drive motor power contactor.
pwmout drive_motor,off								' Turn off pwm signal to drive motor.
											' 
return										'
I am sure there is better whys of doing the above code, but I have done it in the way that I understand and can follow.

What I need help with at this point in time, is the math needed to calc the value needed for the PWMOUT Freq, taken from motor_freq.

And then the math needed to work out the PWMOUT Duty Cycle value based on the TPS.

Any help you can give on this project would be grate, and I am sure my kids would also thank you for your time, and support.

Best Regards.
 

hippy

Ex-Staff (retired)
the math needed to calc the value needed for the PWMOUT Freq, taken from motor_freq.
As motor_freq is a constant (Hz) the easiest way to determine what pwmfreq value should be is to use the Programming Editor PWMOut wizard.

And then the math needed to work out the PWMOUT Duty Cycle value based on the TPS.
TPS is the Throttle Position Sensor ?

Assuming TPS goes 0 to 255, you know your pwmfreq then pwmduty should be -

pwmduty = pwmfreq * 4 * TPS / 255

That may require greater than 16-bit maths but you can probably divide by 256 to make things easier.
 

inglewoodpete

Senior Member
It's good to see you're putting some thought into your software design. A well structured program will aid debugging and future enhancements.

Remember the safety of your kids will depend on your hardware and software design. Be assured that they will test every loop and "if" statement in your code, so design carefully!!

On the software side, a few points. I'm guessing that you're using an interrupt to detect brake application and remove power. A good feature but I can't see where you enable the interrupts. Also, when you leave the interrupt routine, execution would normally return to the Main loop. Unfortunately, you have a "high power_contactor" command in the main loop, which will undo the safety feature.

It may be better to only read the throttle when the brake is released, zeroing the "throttle" variable when the brake is applied.
 

MartinM57

Moderator
It may be better to leave it as an on/off switch and find another project that doesn't put your kids into a brick wall on full motor power when there's a bug in your software/hardware that doesn't do the maths correctly, recognise the brake switch is being furiously pressed etc.

Just IMHO, but I just wouldn't do this - especially as you're having to ask about fairly basic things and you will get a solution designed by a committee around just the facts that you care to tell us...
 

StigOfTheDump

Senior Member
Belt &amp; Braces

Might be an idea to feed the motor power (or return) through the brake switch or brake switch/relay.
Kids are inventive and after they've "tuned" that throttle up for a bit more speed with a bit of wire or an old battery, the controller might fall to bits.
 

hippy

Ex-Staff (retired)
Safety of the system is important but I never jumped on that as I have in other projects on the grounds that what is planned appears no less safe than what already exists - providing there is a physical 'kill switch' which can cut motor power under any circumstances.

I personally would avoid interrupts; polling loops should have fast enough response time to handle everything and be simpler to analyse and test.
 

Mad Professor

Senior Member
As for crashing into the wall ect, they do that all ready.

It's not like they are going at warp factor 9, I think the fastest top speed of the fastest bike is only something like 4-5mph.

I don't think the kids tampering with the controller will be an issue.

Regarding power to the drive motor, I was looking at driving it via PWM, having the power contactor between the controller and the drive motor, and the contactor control wire(s) also connected to the brake pedel, so this way it will kill the power to the driver motor via software and hardware.

But as said at the start I am in the designing state, nothing yet is set in stone, and all ready I have been giving a few extra ideas to make it safer.
 
Last edited:

hippy

Ex-Staff (retired)
pwmduty = pwmfreq * 4 * TPS / 255

That may require greater than 16-bit maths but you can probably divide by 256 to make things easier.
If one has TPS as 0 to 1023, and uses divide by 1024, it's even easier -

pwmduty = pwmfreq * 4 * TPS / 1024

pwmduty = pwmfreq * TPS / 256

As TPS ( 0 to 255 ) is derived from a READADC, using READADC10 ( 0 to 1023 ) is just as simple.
 

Mad Professor

Senior Member
Hippy can you please confirm that again, as the math, and wizzard are not matching.

0% "63 * 4 * 0 / 1024 = 0"
50% "63 * 4 * 512 / 1024 = 126"
100% "63 * 4 * 1024 / 1024 = 252"

I just went to confirm by using the pwmout wizzard but it gives me the values of, 0, 128, 256, strange.
 
Last edited:

hippy

Ex-Staff (retired)
I suspect it's the difference in rounding and approximation. If I recall right, for an 8-bit PWM frequency value 'ABCDEFGH' the 10-bit duty can range from '0000000000' to 'ABCDEFGH11'.

So for a 63 PWM frequency value ( '00111111' ) that's '0000000000' to '0011111111', which will be 255 for 100%, 127 for 50%. That matches with what the PWMout wizard gives me for 15700Hz @ 100% and @ 50% - We'll come back to the 15700Hz soon.

The more correct calculation for pwmduty should have been, left to right PICAXE maths -

pwmduty = pwmfreq * 4 + 3 * TPS / 1023

with TPS from 0 to 1023.

PWMOUT can only generate certain frequencies exactly, and I suspect that where I chose 15700Hz ( having guessed it to give a '63' PWM frequency value ) you actually use 15600Hz. The calculations in the PWMout Wizard have then rounded the result slightly differently to the values for 15700Hz.

Without digging into the PICmicro datasheets or Wizard source code I'm not absolutely sure if the max duty is '*4+3" or whether there's also another '+1' to be added. That would also have a slight efefct on the exact value.

Normally the 10-bit duty value is 'four times' the 8-bit frequency rule of thumb is close enough to not have any significant effect in practice, the missing '+3' and rounding effects of the PWMout Wizard are minor; either it falls slightly short of 100% or 100% arrives ever so slightly early. This will be more significant though for lower PWM frequency values.

I hope that's clarified it at least a little bit !
 

Dippy

Moderator
Other than good transudcers and electronics, it may be good to add a couple of TPS ReadADC samples to filter glitches. i.e. averaging or rejection.

On a couple of electric cars I have driven, you have to apply the brakes before it'll allow you to power up.
Can you do some kind of interlock like that?


I assume it won't go any faster than what they're used to , but it's nice to remove and sudden things happening.
I'd also add in throttle acceleration damping (in code) but that be OTT for this.
Sounds fun :)
 

BeanieBots

Moderator
Before you get too carried away with basing your maths around a specific PWM frequency, it might be prudent to do some basic tests to determine a frequency that the motors are happy with and that whatever your drive system ends up as can also cope with.
Unfortunately, motors and PWM can be a little bit like the chicken/egg scenario.
 

Mad Professor

Senior Member
BeanieBots: I am indeed aware that finding the best pwm freq for a given motor is not that easy of a task.

I just wanted to make sure I got a good working code to start with then I can carry on from there.

Here is the current code:
Code:
#picaxe 18M2									' 

let pinsB = %00000000								' 
let pinsC = %00000000								' 

'Inputs
symbol tps_adc = C.2								' Throttle raw ADC input.
symbol foot_brake = B.3								' Foot brake input.

'Outputs
symbol power_contactor = B.7							' Drive motor power contactor output.
symbol drive_motor = B.6							' Drive motor output.

'Settings
symbol tps_min = 0								' ADC Value for TPS Min.
symbol tps_max = 1023								' ADC Value for TPS Max.
symbol tps_safe = 5								' Max percentage of TPS permitted at powerup.

'
symbol pwm_freq = w12								' 
symbol pwm_duty = w13								' 


init:
low power_contactor								' Turn off power to drive motor power contactor.
pwmout drive_motor,off								' Turn off pwm signal to drive motor.
let w2 = tps_safe * tps_max							' 
let w3 = tps_safe * tps_min							' 
let w4 = w2 - w3									' 
let w5 = w4 / 100									' 
let w6 = tps_min + w5								' 
let w11 = w4 /10									' 
let w12 = 63									' "= (1000000/15600)-1" Req motor freq 15600Hz.
pause 1000										' Pause for 1000ms (1Sec).
sertxd ("EV Controller - Firmware v0.1 (10/03/2011)",cr,lf)		' 


powerup_tps_adc_check:
readadc10 tps_adc,w1								' Read raw ADC value of TPS, and store data into w1.
if w1 >= w6 then goto powerup_tps_adc_check:				' 
if w1 < w6 then goto main:							' 
goto powerup_tps_adc_check:							' 


main:
'low power_contactor								' Turn off power to drive motor power contactor.
'pwmout drive_motor,off								' Turn off pwm signal to drive motor.
'											' 
readadc10 tps_adc,w1								' Read raw ADC value of TPS, and store data into w1.
let w7 = pwm_freq * w1 / w11							' 
let pwm_duty = 4 * w7								' 
high power_contactor								' Turn on power to drive motor power contactor.
pwmout drive_motor,pwm_freq,pwm_duty					' 
debug											' 
goto main:										' 									'
Still needs more adding, and cleaning up.

Now just looking to add the code to turn the contactor off when the brake is pressed and or when the tps is <1%.

Now back to reading the manuals.
 
Last edited:

hippy

Ex-Staff (retired)
I'm not at all convinced that "w7 = pwm_freq * w1 / w11" will do what you want as 'w1' will be 0 to 1023 regardless of 'w11', though I'm not quite sure exactly what you are trying to achieve.

You have run-time calculations of constants which would be far better determined by multiple SYMBOL statements and you are using variables referenced by default name 'w12' and by SYMBOL names 'pwm_freq' for example. That makes everything very confusing and error prone.

While I said this project was likely no less dangerous than what exists, turning it into a 'bucking bronco' or having behaviour other than expected is more dangerous so it has to be done properly.

I would suggest writing the code simply to control the motor from throttle, cut out all the extraneous interlocks, braking and other enhancements, for now. Define as a written specification what your motor response will be and then get that to a solid and reliable implementation first.
 

papaof2

Senior Member
I take it that Hippy has not watched kids with their battery powered vehicles. The "bucking bronco" effect with heads bobbing back and forth is something they do and think is funny.

The key to safety is two-fold: acceleration and top speed. Maximum acceleration is defined by the motor used in the vehicle and the size of the battery (controlling factors with an on/off power control). Top speed is controlled by the motor size, battery voltage, and gearing ratio from motor to axle.

Disney did a study on top speed (for the gas engine powered cars at some of their parks) and the cars were governed at 9mph as a safe speed for front or rear collisions. They also had spring bumpers to absorb some shock when hitting a non-movable object.

The Powerwheels series of vehicles (Jeep/Gator style) have two speeds, with the lower speed for younger kids and when the vehicle is backing up. The lower speed is achieved by putting the two 12 volt motors in series so each of them effectively has 6 volts across it.

Design your controller to handle the maximum current draw: at least what the OEM circuit breaker is rated for, although I would consider using pass components with double that rating (the magic smoke is much too easily released). The 12 volt 8AH battery used in the Powerwheels Jeep (and similar) can deliver high peak currents - the OEM circuit breaker is 30 amps. I did some testing on the vehicles the grandkids love (no, I didn't spend $600 for two of these - they were zero cost on freecycle.org and I installed a new $30 battery in each of them). A 12 amp breaker will hold for 2 kids on level pavement (~100 lb total), but trips going uphill with that load.

John
 

hippy

Ex-Staff (retired)
I take it that Hippy has not watched kids with their battery powered vehicles. The "bucking bronco" effect with heads bobbing back and forth is something they do and think is funny.
I definitely agree. It's that category of things when it's okay to do it to yourself, but probably not when someone does it to you or happens unexpectedly. Technically it's a question of control; in the first case it's performing as expected, second case it's not, is 'out of control'.
 
Top