Gruber
HobbyMasters
M.L. Toys
KidsWheels
Gruber
HobbyMasters
M.L. Toys
KidsWheels
HobbyMasters M.L. Toys
Gruber
KidsWheels
Electronic Scooter Controllers have become a popular addition to our vehicles. Ask specific questions about ESCs here!

***WARNING*** this section is for ADVANCED MODDERS. if you try anything in this section you NEED to expect minor issues with the build up to and including complete FAILURE of EVERYTHING in your freshly built BPRO.

Have fun ;-) :-)
#128943
Recently a relative gifted a Fisher-Price 2-seater Jeep to my kids. They are 5 and 3 yrs old.

One of the things my kids (and their two cousins) loved to do do was to take the gear selector and row it back and forth while moving so that it would rapidly switch directions. That can't be good for the gearbox.

So I decided to implement a micro-controller based soft-start/stop with a lockout so that if somebody switched directions rapidly, the vehicle would gradually slow, wait a short delay, and then switch direction. Also I could remove the hi-speed limiter screw on the gear selector and limit the speeds electronically.

The microcontroller I decided to use was basically an arduino (for quick prototyping), but I plan to make a more permanent design with just a bare chip, once I worked out the details.

The arduino needed 5V, so I also need a voltage regulator to bring the 12V down to 5V.

Finally, I needed some kind of motor controller. I found a dual H-Bridge based on a BTS7960B chip which was is rated for 43A (which should be good enough for this application since the stock fuse is 40 amps)
#128969
Some more details

- no variable speed control, only on or off, albeit with gradual transitions between forward, reverse, stopping (and it includes braking!)
- minimal cost (about $25) and wire cutting (only need to cut 2 wires!)

How does it work? I guess a diagram is in order

power-wheels MC2.jpg


On the left is the stock wiring. On the right, my modifications. Basically it turns the pedal (aka throttle switch) into a drive-by-wire type.

In my actually inplementation, I used an arduino nano, which doesn't have it's own built-in 5V regulator, so I actually have an external one, but I've omitted it for clarity here.

Also, I included a master off switch, on the +Positive wire, just coming off the battery. Otherwise the microprocessor will always be on, unless you disconnect the battery. I put the switch on the dashboard and included a small light to show when the car was powered on. The kids seem to enjoy playing with the switch as much as playing with the gear lever.
Last edited by momsmechanic on Thu Dec 04, 2014 1:15 pm, edited 1 time in total.
#128970
For those of you who don't know what an Arduino is? It's basically an Atmel Microprocessor, set up to be easy to learn and use:

http://arduino.cc

Now you can buy a genuine one, but the design is open-source, which means you can pick up clones on ebay from china for a fraction of the price. Typically, less than $10, I've seen some as low as only $5
http://www.ebay.com/sch/i.html?_nkw=arduino+uno+r3

The "Dual H-bridge" controller is basically what's inside most reversible ESC's. The one I used is based on the BTS7960B (half-bridge driver for motors). I stumbled upon them on Ebay. Apparently this an obsolete part, but there seems to be no shortage of them on ebay. I picked mine up for around $15, but I've seen lower prices recently (down to about $10).
http://www.ebay.com/sch/i.html?_nkw=bts7960B
Last edited by momsmechanic on Thu Dec 04, 2014 1:13 pm, edited 1 time in total.
#128971
*** UPDATE *** see the post below below for a bug discovered in my original code, courtesy of maxpower.

Finally, the code, the usually disclaimers apply, use at your own risk:

*** Added a necessary delay in the commandMotor funtion that I accidentally removed when I cleaned up this code to make it look a pretty.

Code: Select all/*****************************************************************************************************************************************
Power wheels drive-by-wire controller code
By Mom's Mechanic
*****************************************************************************************************************************************/
// Variables, Defines
/*****************************************************************************************************************************************/
// Direction
#define forward 1
#define stopped 0
#define reverse -1

// Commands
#define cmd_none   0
#define cmd_fwdlo  1
#define cmd_fwdhi  3
#define cmd_rev    4

// Input definitions
#define ON  LOW

// Input pin definitions
#define fwdpin1 5  // Low speed
#define fwdpin2 4  // High speed
#define revpin  2  // Reverse

// Output pin definitions
#define fwdpwm 9   // PWM for forward
#define revpwm 11  // PWM for reverse

// Variables
byte currentmode=stopped;  // To store current direction of motion
int pwmspeed=0;            // To store current commanded speed: value may be from -255 (reverse) to 255 (forward). Zero means stopped
byte command;              // to store Commands


// Values for accel/decel/braking
#define accel_ratelo  2
#define accel_ratehi  4
#define decel_rate    3
#define brake_rate    6

// Value for delay when changing direction without stopping first
#define directionchangedelay 1000

// values for maximum commanded motor speed (maximum is 255 for forward directions, and -255 for reverse)
#define maxfwd1  128
#define maxfwd2  180
#define maxrev  -128

/*****************************************************************************************************************************************/
 
void setup()
{
  // Set up input & output pin modes
  pinMode(fwdpin1,INPUT_PULLUP);
  pinMode(fwdpin2,INPUT_PULLUP);
  pinMode(revpin,INPUT_PULLUP);
  pinMode(fwdpwm,OUTPUT);
  pinMode(revpwm,OUTPUT);
}
 
void loop()
{
  //read the pin statuses
  command=readCommand();
  switch(command)
  {
    case cmd_none:
    {
      if(currentmode != stopped){
        slowdown();
      }
      break;
    }
    case cmd_fwdlo:
    {
      forwardlo();
      break;
    }
    case cmd_fwdhi:
    {
      forwardhi();
      break;
    }
    case cmd_rev:
    {
      reverselo();
      break;
    }
    default:
    {
      //Error! ALL STOP!
      allstop();
      break;
    }
  }
}
 
/*****************************************************************************************************************************************/
int readCommand(){
  // Read the input pins and return a value for the current input state
  int count=0;
  if(digitalRead(fwdpin1)==ON){
    count+=1;
  }
  if(digitalRead(fwdpin2)==ON){
    count+=2;
  }
  if(digitalRead(revpin)==ON){
    count+=4;
  }
  return count;
}
/*****************************************************************************************************************************************/
/*****************************************************************************************************************************************/
void slowdown(){
  // slows vehicle down when pedal is released
  if(pwmspeed>0){ // motor is currently set to forward
    pwmspeed-=decel_rate;
    if(pwmspeed<0){
      pwmspeed=0;
    }
  } else
  if(pwmspeed<0){ // motor is current set to reverse
    pwmspeed+=decel_rate;
    if(pwmspeed>0){
      pwmspeed=0;
    }
  }
  commandMotor();
}
/*****************************************************************************************************************************************/
void forwardlo(){
  // moves vehicle foward up to low speed maximum
  if(currentmode==stopped){ // go from stopped to fwd1
    currentmode=forward;
    acceleratehi();
  } else
  if(currentmode==reverse){ // go from reverse to fwd 1
    brake();
  } else
  if(pwmspeed>maxfwd1){ // slow from fwd2 down to fwd1
    slowdown();
  } else
  if(pwmspeed<maxfwd1){ // continue to accelerate to fwd1
    acceleratehi();
  }
}
/*****************************************************************************************************************************************/
void forwardhi(){
  if(currentmode==stopped){ // go from stopped to fwd2
    currentmode=forward;
    acceleratelo();
  } else
  if(currentmode==reverse){ // go from reverse to fwd2
    brake();
  } else
  if(pwmspeed<maxfwd2){  // continue to accelerate to fwd2
    acceleratelo();
  }
}
/*****************************************************************************************************************************************/
void reverselo(){
  if(currentmode==stopped){   // go from stopped to reverse
    currentmode=reverse;
    acceleratelo();           // change to acceratehi() if you want to reverse at a quicker rate!
  } else
  if(currentmode==forward){   // go from fwd1/2 to reverse
    brake();
  } else
  if(pwmspeed>maxrev){        // continue to accelerate to reverse
    acceleratelo();           // change to acceratehi() if you want to reverse at a quicker rate!
  }
}
/*****************************************************************************************************************************************/
void allstop(){
  // Emergency brake! Used when Error condition detected
  pwmspeed=0;
  commandMotor();
  delay(3000); // delay before starting up again
}
/*****************************************************************************************************************************************/
/*****************************************************************************************************************************************/
void acceleratehi(){
  // First gear! (also may be used for reverse if you want to reverse faster)
  if(currentmode==forward){
    pwmspeed+=accel_ratehi;
  } else {
    pwmspeed-=accel_ratehi;
  }
  commandMotor();
}
/*****************************************************************************************************************************************/
void acceleratelo(){
  // Second gear! (hence lower acceleration); note, also used for reverse
  if(currentmode==forward){
    pwmspeed+=accel_ratelo;
  } else {
    pwmspeed-=accel_ratelo;
  }
  commandMotor();
}
/*****************************************************************************************************************************************/
void brake(){
  // Stop at high rate, used when lever is changed direction and pedal is pressed before vehicle has come to a stop.
  if(pwmspeed>0){  // slow from forward direction
    pwmspeed-=brake_rate;
    if(pwmspeed<0){
      pwmspeed=0;
    }
  } else
  if(pwmspeed<0){  // slow from reverse direction
    pwmspeed+=brake_rate;
    if(pwmspeed>0){
      pwmspeed=0;
    }
  }
  commandMotor();
  if(pwmspeed==0){    // add a delay (that'll teach 'em not to mess around with the lever!)
    delay(directionchangedelay);
  }
}
/*****************************************************************************************************************************************/
/*****************************************************************************************************************************************/
void commandMotor(){
  // send the command to the motor
  if(pwmspeed==0){ // All stopped
    analogWrite(fwdpwm,0);
    analogWrite(revpwm,0);
    currentmode=stopped;
  } else
  if(pwmspeed>0){ // forward motion
    analogWrite(revpwm,0);
    analogWrite(fwdpwm,pwmspeed);
  } else {  // reverse motion
    analogWrite(fwdpwm,0);
    analogWrite(revpwm,-1*pwmspeed);
  }
  delay(50); // forgot to include this line originally, added June 30, 2015
}
/*****************************************************************************************************************************************/

Last edited by momsmechanic on Mon Jul 31, 2017 9:28 am, edited 4 times in total.
#128972
So, a quick explanation how it works.

The arduino reads the inputs from what were originally the leads to the motor. Depending on the hi/lo and fwd/rev switches, the lines (fwd1, fwd2 and rev) will be switch on or off)
No inputs switched on means the pedal has been released.

Combined with what the last speed was commanded and the current direction of travel, the arduino will command an increase, decrease or leave the motor speed as it was.

If an invalid combination of switches are read, i.e. fwd and rev at the same time, then the arduino will go into failsafe and stop everything, delay 3 seconds, and then try reading the inputs again.


One other thing to note is that the motor controller is wired to switch between power on and leads shorted (i.e. motor braking). If you are familiar with PWM (there is an FAQ about it in the FAQ section if you don't know what this is), this means when the motors are stopped, they are effectively braked. When slowing down, it applies brakes as well. When accelerating, it controls the rate of acceleration as well, even if going downhill.

I had originally thought about allowing the motor to freewheel and then apply brakes separately, but ultimately I decided, for safety's sake, to do it this way instead. Also it keeps things simple with only one pedal (no separate pedal for brake) My kids are still very young, and too many controls would just confuse them.

The values for maximum speeds are defined near the beginning (maxfwd1, maxfwd2 and maxrev). These are the values I ended up using. It keeps the speeds manageable, but still allows enough power to climb small inclines.

As stated earlier, anybody is welcome to use this code, but use at your own risk.
Last edited by momsmechanic on Thu Dec 04, 2014 1:56 pm, edited 2 times in total.
#128973
I just realized my diagram has a small mistake, it's a single H-bridge, not a dual h-bridge.

For those of you who don't understand how an H-bridge works, here is a tutorial:

http://www.mcmanis.com/chuck/robotics/t ... /h-bridge/

The two orange wires in my diagram in post #2 control the left and right sides of the "H" respectively. It's set up such that at any given time, on each side of the "H" one switch is on and the other is off.

I'll try to see if I can get some picture and a video, but since it is winter, and the jeeps have been put away at the grandparent's house, I might not be able to do that anytime soon.
Last edited by momsmechanic on Thu Dec 04, 2014 2:48 pm, edited 2 times in total.
#128976
Nice work! You're implementing some of the same things I implemented for the car I built for my kids. You're reminding me how much fun it would be to do it with what's available off the self today. I've since done lots of projects with PIC and Atmel processors and keep thinking maybe it's time to start working on a new generation car for the eventual grand kids. You should post a picture of your electronics and then we can go compare that to the picture of my car project from the 90s that's covered in the thread in my signature line. Visual proof of the rapid evolution of technology.

Sounds like you've done some form of this, but one of the most useful features I implemented was having an encoder on the motors and then controlling based on speed instead of motor power. Essentially, the computer in my car takes the position of the gas pedal as "desired speed", and then controls the motor power to achieve that speed. Then the car goes the same speed whether it's going uphill, downhill, is in grass, or pavement. There is a special key sequence on my dashboard to enter "parent" mode to change certain parameters such as max allowed speed. I realized you don't have a proportional input gas pedal, well at least yet :), but I think you'll still find this very useful.

speaking of "yet" .... my progression went something like this....
- on/off gas pedal, manual steering
- proportional gas pedal
- added speed sensor and shifted to controlling by speed instead of motor power
- added radio control so parent could stop the car remotely
- added drive by wire steering so RC could take over full control of car on demand and return control to kid on demand

I'm slowly working on 2 additions to my car now in-between other projects
- Collision avoidance using ultrasonic range sensors (partially implemented)
- GPS based geo-fencing
#128978
Thanks for sharing!

A few questions from the diagram,

Are the inputs supplied with 5v + and the module looks for connection to ground, as opposed to looking for v+ input?

I relate your H-Bridge to a normal ESC. Is the H-bridge acting like a relay, being turned off and on by the pwm output of the Arduino?

How is the soft braking being accomplished, by variably shorting the motors?

Overall, I think that's pretty cool, there could definitely be a market for this 8-)
#128980
MtbMacgyver wrote:Nice work! You're implementing some of the same things I implemented for the car I built for my kids. You're reminding me how much fun it would be to do it with what's available off the self today. I've since done lots of projects with PIC and Atmel processors and keep thinking maybe it's time to start working on a new generation car for the eventual grand kids. You should post a picture of your electronics and then we can go compare that to the picture of my car project from the 90s that's covered in the thread in my signature line. Visual proof of the rapid evolution of technology.

[...]


Some of the things you mentioned I considered, but my design parameters were:

1. had to be cheap!
2. simple! My kids are very young. The younger one can barely reach, let alone control the gas pedal, so I decided against proportional gas pedal, or even a separate brake pedal
3. Must be SAFE! I actually had my wife test-drive it before I let the kids use it. She's still within the weight limit.
4. had to be easily reversible. The car I did this on was in pristine condition, and I didn't want to screw it up if the H-Bridge wasn't able to handle the current. This design only requires you to cut 2 wires (at the pedal) and disconnect the 4 wires from the motors

I thought about ways to implement some kind of speed detection, but I couldn't find anything simple and cheap (and easily reversible). One thing I considered, which you don't mention, is using some kind of 3-axis accelerometer to determine speed (and even detect angle of the vehicle i.e. about to tip over), but this was neither cheap, not simple. I wanted to get up and running quickly.

Out of curiosity, how did you implement your speed sensor?

I also thought about implementing some kind of current detection, so I could still limit top speed, but add extra power when needed (i.e. when going uphill, or starting from stop)

As it is, it's so simple, I could've used an attiny instead of a full-blown arduino, but the arduino let me get up and running very quickly.
Last edited by momsmechanic on Thu Dec 04, 2014 5:21 pm, edited 4 times in total.
#128981
toycrusher wrote:Thanks for sharing!

A few questions from the diagram,

Are the inputs supplied with 5v + and the module looks for connection to ground, as opposed to looking for v+ input?

I relate your H-Bridge to a normal ESC. Is the H-bridge acting like a relay, being turned off and on by the pwm output of the Arduino?

How is the soft braking being accomplished, by variably shorting the motors?

Overall, I think that's pretty cool, there could definitely be a market for this 8-)


The inputs on the arduino actually have internal 5v pullups, so yes, when they're pulled low to ground (i.e. pedal pressed), that is considered "ON" state. You can do it just as easily by looking for +5v as "ON", but that would mean having to running an extra wire to the pedal to feed the +5v. This way, I can splice directly into the negative wire since it goes right past the pedal anyways.


The H-Bridge actually is more like 4 separate switches (or relays). In my case, they're actually MOSFETS.

Image

What happens is that when the vehicle is stopped, the lower switch on the both sides are closed, and the upper switches are open. In this case, both terminals of the motor are grounded

When it's moving, the upper and lower switch alternate opening and closing on one side (via PWM signal). Which side is determined by which direction the motor is supposed to turn.

So for instance, to move forward, the upper left side closes, and at the same time the lower left switch opens. And then they switch places, the upper switch opens, and the lower closes. On the right hand side, only the lower switch stays closed. So the motor terminal "+" is seeing +positive, -ground, +positive, -ground, etc, at variable rates. Terminal "-" on the motor only sees ground.

To change the direction of the motor, you close the lower switch on the left side and then alternate switching on the right side.

So in effect the motor is actually never freewheeling, it alternating between turning and stopping, albeit at a very fast rate. It's the same effect as if you press and release the gas pedal very very quickly.

In theory, relays could be used, if you could find ones that can switch fast enough. In practice, these relays are very expensive!
Last edited by momsmechanic on Thu Dec 04, 2014 5:28 pm, edited 6 times in total.
#129018
Are you sure you need the voltage regulator? The following is from the Arduiino website for the uno:

Operating Voltage 5V
Input Voltage (recommended) 7-12V
Input Voltage (limits) 6-20V

5V.This pin outputs a regulated 5V from the regulator on the board. The board can be supplied with power either from the DC power jack (7 - 12V), the USB connector (5V), or the VIN pin of the board (7-12V). Supplying voltage via the 5V or 3.3V pins bypasses the regulator, and can damage your board. We don't advise it.

Maybe the knock off doesn't have the built in regulator?
Last edited by Heftiger on Sat Dec 06, 2014 10:09 am, edited 1 time in total.
#129032
Looking at your code, I'm assuming you could add a delay function to ramp up to high speed gradually over a second or two, giving a "soft start" to the controller right?
#129061
Heftiger wrote:Are you sure you need the voltage regulator? The following is from the Arduiino website for the uno:

Operating Voltage 5V
Input Voltage (recommended) 7-12V
Input Voltage (limits) 6-20V

5V.This pin outputs a regulated 5V from the regulator on the board. The board can be supplied with power either from the DC power jack (7 - 12V), the USB connector (5V), or the VIN pin of the board (7-12V). Supplying voltage via the 5V or 3.3V pins bypasses the regulator, and can damage your board. We don't advise it.

Maybe the knock off doesn't have the built in regulator?


In my case, yes, the particular arduino I used didnt' have an on-board voltage regulator (arduino nano), but if you use an uno, or one of the other larger form factors, yes, you will have the regulator on board.

if you plan to use more than 12 volts as your power source, I would highly recommend a switching regulator (as opposed to the linear voltage reg. built-in to arduino)
#129062
toycrusher wrote:Looking at your code, I'm assuming you could add a delay function to ramp up to high speed gradually over a second or two, giving a "soft start" to the controller right?


The soft start is already there. Basically the pwm rate is slowly increased. When you first press the pedal, you hear an increasing whine (like what you hear from most cordless power drills when you gradually press the trigger) before the car starts moving. You hear the same thing (gradually decreasing) when you let go of the pedal.
Last edited by momsmechanic on Mon Dec 08, 2014 11:57 am, edited 1 time in total.
#129089
momsmechanic wrote:I thought about ways to implement some kind of speed detection, but I couldn't find anything simple and cheap (and easily reversible). One thing I considered, which you don't mention, is using some kind of 3-axis accelerometer to determine speed (and even detect angle of the vehicle i.e. about to tip over), but this was neither cheap, not simple. I wanted to get up and running quickly.


The easiest way to measure speed is to measure the RPM of the motor or one of the gears. If you measure the speed of one of the gears in the gearbox, the closer to the motor the better. Just because it gives you the best resolution and fastest measurement response time. I think if I were trying to measure speed on an actual power wheel, I'd attach a magnet to the first stage gear in the gearbox and use a hall effect sensor attached to the outside of the gearbox case. Then you can use one of the timers on the AVR chip to measure the period of the signal from the hall effect sensor.

Accelerometers are really good at measuring short term changes in speed, but they aren't a good choice for measuring speed over time. That's because the inherent errors in accelerometers accumulate over time when you try to measure speed over more than a few seconds. They would be very good at detecting a crash or the car turning over.

I've been experimenting with IMUs for implementing geo-fencing. An IMU is a 3 axis accelerometer, 3 axis gyro, and 3 axis compass in a single chip, IMU technology has moved forward rapidly in the last few years due to their use in cell phones. They allow you to fully characterize all aspects of motion very accurately. Specifically they complement GPS data very well, because the IMU gives you very accurate info about immediate changes in direction and speed and the GPS is good at providing a longer term view of position and speed that doesn't suffer from the accumulating error issues of the IMU. So combining the info together is quite useful.

momsmechanic wrote:Out of curiosity, how did you implement your speed sensor?


I printed an optical wheel onto clear plastic film using a laser printer that's made up of clear and black segments. Then I glued it to the pinion gear on one of the motors. Then I use IR optical interrupter to generate a square wave that's proportional to the rotational speed of the motor. That signal feeds some TTL counter chips in the electronics. There is also a hardware timer implemented in TTL logic that latches the counters into an 8 bit latch at a predetermined interval and resets the counter. All of that TTL logic could be replaced by the counter function of pretty much any timer/counter module in any modern microcontroller.

Image

momsmechanic wrote:I also thought about implementing some kind of current detection, so I could still limit top speed, but add extra power when needed (i.e. when going uphill, or starting from stop)


I doubt there is a good correlation between current and speed. Current is going to vary much more dramatically based on whether you're going uphill, downhill, on pavement, or in grass.
#129095
MtbMacgyver wrote:The easiest way to measure speed is to measure the RPM of the motor or one of the gears. If you measure the speed of one of the gears in the gearbox, the closer to the motor the better. Just because it gives you the best resolution and fastest measurement response time. I think if I were trying to measure speed on an actual power wheel, I'd attach a magnet to the first stage gear in the gearbox and use a hall effect sensor attached to the outside of the gearbox case. Then you can use one of the timers on the AVR chip to measure the period of the signal from the hall effect sensor.

That's a pretty good idea to put a magnet on one of the gears. I think a magnet on one of the wheels might not turn fast enough to get a decent reading on speed.

MtbMacgyver wrote:Accelerometers are really good at measuring short term changes in speed, but they aren't a good choice for measuring speed over time. That's because the inherent errors in accelerometers accumulate over time when you try to measure speed over more than a few seconds. They would be very good at detecting a crash or the car turning over.

I've been experimenting with IMUs for implementing geo-fencing. An IMU is a 3 axis accelerometer, 3 axis gyro, and 3 axis compass in a single chip, IMU technology has moved forward rapidly in the last few years due to their use in cell phones. They allow you to fully characterize all aspects of motion very accurately. Specifically they complement GPS data very well, because the IMU gives you very accurate info about immediate changes in direction and speed and the GPS is good at providing a longer term view of position and speed that doesn't suffer from the accumulating error issues of the IMU. So combining the info together is quite useful.

Have you heard of Ardupilot? There's a variant called ArduRover for autonomous vehicles, a little too pricey for my tastes, but it sounds like all the hardware work has already been done.


MtbMacgyver wrote:I printed an optical wheel onto clear plastic film using a laser printer that's made up of clear and black segments. Then I glued it to the pinion gear on one of the motors. Then I use IR optical interrupter to generate a square wave that's proportional to the rotational speed of the motor. That signal feeds some TTL counter chips in the electronics. There is also a hardware timer implemented in TTL logic that latches the counters into an 8 bit latch at a predetermined interval and resets the counter. All of that TTL logic could be replaced by the counter function of pretty much any timer/counter module in any modern microcontroller.

Image


Very nice.

MtbMacgyver wrote:
momsmechanic wrote:I also thought about implementing some kind of current detection, so I could still limit top speed, but add extra power when needed (i.e. when going uphill, or starting from stop)


I doubt there is a good correlation between current and speed. Current is going to vary much more dramatically based on whether you're going uphill, downhill, on pavement, or in grass.


I originally thought of using the current detection just to see how much power was actually being used. I thought I could also use it as some kind of feedback, but this would require experimentation and I as you said, it wouldn't be a direct correlation to speed. I didn't have all that much time to mess around with this, so I never bothered.

Ultimately I decided to keep it as simple as possible. Down the road I might add some kind of interface so I can change parameters without having to re-program the chip, but so far the settings I've picked seem to be satisfactory.
#129099
momsmechanic wrote:Have you heard of Ardupilot? There's a variant called ArduRover for autonomous vehicles, a little too pricey for my tastes, but it sounds like all the hardware work has already been done.


I'm somewhat familiar and have looked at it some, but it's really solving a different scenario. They are solving how to accurately navigate a per-determined course autonomously using IMU and GPS sensors. The main scenario I'm really concerned with is being able to assign a virtual set of boundaries, such as someone's yard, and not allow the car to go outside the "virtual" fence. While not easy, the scenario I'm concerned with is actually a good bit simpler than the general autonomous navigation (drone) scenario that's the focus of Ardupilot and it's spinoffs. Because I'm simply trying to block certain navigations input by the user (the child driving the car), where they are creating the navigation actions.

I do agree that I may be able to re-use some pieces from the Ardupilot projects. But it would most likely be parts of the software. The hardware for this just isn't that difficult and I'd rather keep it as simple as possible and have full control over the hardware design.
User avatar
By Evan
#130369
momsmechanic wrote:
MtbMacgyver wrote:That's a pretty good idea to put a magnet on one of the gears. I think a magnet on one of the wheels might not turn fast enough to get a decent reading on speed.
But several magnets would increase resolution, right? I wonder if taking speed off one of the non-driven wheels would be advantageous in situations where there is wheelspin on the driven wheels. Maybe a bad idea since that would allow even more wheelspin.
User avatar
By Evan
#130387
Great write-up by the way. We just got a Lil Quad for our son's 1st birthday and he seems to enjoy it except for how abrupt the start is, especially indoors. I'd like to smooth out the start and figured I'd add reverse and 12v in the future, but perhaps I should just tackle it all at once since the Arduino would allow me to run 12v at lower speeds. I guess I'm off to shop for parts. In addition to what you've used, I need to source controls for fwd/rev and maybe a high/low as well.
#132886
Last week I finally got around to taking some video of my Modified Power wheels Jeep.

In it's current state, there's a solderless breadboard and a mess of wires under the seat. When I eventually get around to it, I'll solder together and properly mount everything down.

The whine you hear is the motor controller ramping up. If you have a newish cordless drill, you'll recognize that sound.

#140809
Resurrected this as I was just returning to life after a darn near grabber I had when I was quoted to duplicate the sawblade soft start board......
" Can confirm your looking around 1-3k for layout/ software, plus another 1-2k for material and assembly for 1 board."

So a $100 board sounds fabulous right now!
Is this something that some one that feels he's reading a foreign language could build? Until this post I'd never payed much attention to ardruino talk.
#145296
Hi,

Sorry to be posting in a long dead thread but I thought I should update those who may try using the code here for their power wheels project.

I took the code here and tried using it with an arduino/HBridge setup and got really bizarre behaviour when I shifted the car into reverse.

I ran the code thru an arduino simulator and observed the same bizarre (unsafe!) behaviour with the car moving in the wrong direction uncommanded.

At any rate, I won't bore you with the technical details but one of the root causes was the "currentmode" variable was defined as a byte, yet the reverse command is a negative number.... this created aberrant behaviour.


At any rate, I've tweaked the code a bit and added some debugging stuff to it. You can set the "turnonBlinking" variable to true to have the light on your arduino blink out the command it has received. This is good for troubleshooting wiring issues etc.... turn it back off when you're ready to make the final upload.

I also added bounds checking to the PWM speed. Since it is an INT it *could* exceed 255 or -255 if the accel rate is not even multiple of the max speed..... basically if it is 255 or above, it just sets it to 255.... (trying to set a value of something higher than 255 creates weird/error behaviour).

I also have in the setup how to change the frequency of the PWM signal. There are different reasons/theory to use varying signal but I chose 4kHz... since the car will be running at full throttle most of the time (255), it doesn't matter a whole lot. I will leave it to you to research. Just note the H bridge I'm using (as the original author is using) has a maximum frequency that is below the max of the arduino.... don't really know what happens if you exceed it.


So here's the code.... hope it helps someone else out. It is a bit "raw", unclean and messy than I normally like to do but it works in both a simulator and real life :-).



Code: Select all// Variables, Defines
/*****************************************************************************************************************************************/
// Direction
#define forward 1
#define stopped 0
#define reverse -1

// Commands
#define cmd_none   0
#define cmd_fwdlo  1
#define cmd_fwdhi  3
#define cmd_rev    4

// Input definitions
#define ON  LOW

// Input pin definitions
#define fwdpin1 49  // Low speed
#define fwdpin2 51 // High speed
#define revpin  48  // Reverse

// Output pin definitions
#define fwdpwm 9   // PWM for forward
#define revpwm 10  // PWM for reverse

// Variables
int currentmode=stopped;  // To store current direction of motion
int pwmspeed=0;            // To store current commanded speed: value may be from -255 (reverse) to 255 (forward). Zero means stopped
byte command=0;              // to store Commands
byte prevcommand =0 ;     //for blinking debuging
bool blink = true;
bool turnonBlinking = false;

// Values for accel/decel/braking
#define accel_ratelo  8
#define accel_ratehi  14
#define decel_rate    10
#define brake_rate    13

// Value for delay when changing direction without stopping first
#define directionchangedelay 500

// values for maximum commanded motor speed (maximum is 255 for forward directions, and -255 for reverse)
#define maxfwd1  128
#define maxfwd2  255
#define maxrev  -110

/*****************************************************************************************************************************************/
 
void setup()
{
  // Set up input & output pin modes
 
  /* using pullup/down (like below) is a good idea as it keeps suprious voltage/signals
  * from the enviroment causing pins to change state. When that happens, uncommanded
  * movement of the car can happen resulting in possible dangerous things happening.
  * In that vein, since this is a "drive by wire" system, I would highly recommend
  * putting a switch on the console that turns everything off (disconnects battery)
  * and tell your kids to flip that switch if weird stuff starts happening.
  */
 
  pinMode(fwdpin1,INPUT_PULLUP);
  pinMode(fwdpin2,INPUT_PULLUP);
  pinMode(revpin,INPUT_PULLUP);
  pinMode(fwdpwm,OUTPUT);
  pinMode(revpwm,OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  /************** SET PWM frequency. default is 450hz  **********************/

  // check out this site for lots more info:
  // http://arduino-info.wikispaces.com/Arduino-PWM-Frequency

  //TCCR2B = TCCR2B & B11111000 | B00000010; //4 kHz uno
  //TCCR2B = TCCR2B & B11111000 | B00000001; //32 kHz uno
 
  TCCR2B = TCCR2B & B11111000 | B00000010; //4 khz mega 9&10

  //FOR PINS PWM PINS 5&6 only....
  //TCCR0B = TCCR0B & B11111000 | B00000010; 8 for PWM frequency of  7812.50 Hz
}
 
void loop()
{
   //read the pin statuses
   command=readCommand();
   if (command != prevcommand) //this basically sets it to only blink one time when the command state changes.
   {
      prevcommand=command;
      blink=true;
   }
   switch(command)
   {
      case cmd_none:
         {
            if(blink)
            {
               blinkLight(1);
               blink=false;
            }
            if(currentmode != stopped)
            {
               slowdown();
            }
            break;
         }
      case cmd_fwdlo:
         {
            if(blink)
            {
               blinkLight(2);
               blink=false;
            }
            forwardlo();
            break;
         }
      case cmd_fwdhi:
         {
            if(blink)
            {
               blinkLight(3);
               blink=false;
            }
            forwardhi();
            break;
         }
      case cmd_rev:
         {
            if(blink)
            {
               blinkLight(4);
               blink=false;
            }
            reverselo();
            break;
         }
      default:
         {
            //Error! ALL STOP!
            allstop(); //let's stop before blinking the light :-)
            blinkLight(5);
         
            break;
         }
   }
}

/*****************************************************************************************************************************************/
int readCommand() // Read the input pins and return a value for the current input state
{
   int count=0;
   if(digitalRead(fwdpin1)==ON)
   {
      count+=1;
      
   }
   if(digitalRead(fwdpin2)==ON)
   {
      count+=2;
   }
   if(digitalRead(revpin)==ON)
   {
      count+=4;
   }
   return count;
}
/*****************************************************************************************************************************************/
/*****************************************************************************************************************************************/
void slowdown() // slows vehicle down when pedal is released
{
   
   if(pwmspeed>0) // motor is currently set to forward
   {
      pwmspeed-=decel_rate;
      if(pwmspeed<0)
      {
         pwmspeed=0;
      }
   }
   else if(pwmspeed<0) // motor is current set to reverse
   {
      pwmspeed+=decel_rate;
      if(pwmspeed>0)
      {
         pwmspeed=0;
      }
   }
   commandMotor();
}
/*****************************************************************************************************************************************/
void forwardlo() // moves vehicle foward up to low speed maximum
{
   
   if(currentmode==stopped) // go from stopped to fwd1
   {
      currentmode=forward;
      acceleratehi();
   }
   else if(currentmode==reverse) // go from reverse to fwd 1
   {
      brake();
   }
   else if(pwmspeed>maxfwd1) // slow from fwd2 down to fwd1
   {
      slowdown();
   }
   else if(pwmspeed<maxfwd1)
   {   // continue to accelerate to fwd1
      acceleratehi();
   }
}
/*****************************************************************************************************************************************/
void forwardhi()
{
   
   if(currentmode==stopped) // go from stopped to fwd2
   {
      currentmode=forward;
      acceleratelo();
   }
   else if(currentmode==reverse) // go from reverse to fwd2
   {
      brake();
   }
   else if(pwmspeed<maxfwd2)
   {   // continue to accelerate to fwd2
      acceleratelo();
   }
}
/*****************************************************************************************************************************************/
void reverselo()
{
   if(currentmode==stopped)   // go from stopped to reverse
   {
      currentmode=reverse;
      acceleratelo();           // change to acceratehi() if you want to reverse at a quicker rate!
   }
   else if(currentmode==forward) // go from fwd1/2 to reverse
   {
      brake();
   }
   else if(pwmspeed>maxrev)        // continue to accelerate to reverse
   {
      acceleratelo();           // change to acceratehi() if you want to reverse at a quicker rate!
   }
}
/*****************************************************************************************************************************************/
void allstop() // Emergency brake! Used when Error condition detected
{
   pwmspeed=0;
   commandMotor();
   currentmode=stopped;
   delay(3000); // delay before starting up again
}
/*****************************************************************************************************************************************/
/*****************************************************************************************************************************************/
void acceleratehi()// First gear! (also may be used for reverse if you want to reverse faster)
{
   
   if(currentmode==forward)
   {
      pwmspeed+=accel_ratehi;
   }
   else
   {
      pwmspeed-=accel_ratehi;
   }
   commandMotor();
}
/*****************************************************************************************************************************************/
void acceleratelo() // Second gear! (hence lower acceleration); note, also used for reverse
{
   if(currentmode==forward)
   {
      pwmspeed+=accel_ratelo;
   }
   else
   {
      pwmspeed-=accel_ratelo;
   }
   commandMotor();
}
/*****************************************************************************************************************************************/
void brake(){
   // Stop at high rate, used when lever is changed direction and pedal is pressed before vehicle has come to a stop.
   if(pwmspeed>0)  // slow from forward direction
   {
      pwmspeed-=brake_rate;
      if(pwmspeed<0)
      {
         pwmspeed=0;
      }
   }
   else if(pwmspeed<0)  // slow from reverse direction
   {
      pwmspeed+=brake_rate;
      if(pwmspeed>0)
      {
         pwmspeed=0;
      }
   }
   commandMotor();
   if(pwmspeed==0) // add a delay (that'll teach 'em not to mess around with the lever!)
   {
      delay(directionchangedelay);
   }
}
/* */

void blinkLight(int times)
{
   if (turnonBlinking) // for debugging. turn off with global variable
   {
     for (int x=0;x<times;x++)
     {
        digitalWrite(LED_BUILTIN, HIGH);
        delay(150);                       
        digitalWrite(LED_BUILTIN, LOW); 
        delay(150);
        
     }
   }
}



/*****************************************************************************************************************************************/
/*****************************************************************************************************************************************/
void commandMotor()
{
 
   /* Bounds check, if greater than max, set it to 255 max.
   * This is need if the accel/decel rate is not a perfect multiple of the max speed(s)
   * Good safety measure anyways since the PWM is limited to a byte value of 255 max
   * yet the pwm is set to an int.
   * Bizarre (aka unsafe) stuff will happen if you try to set the PWM value > 255.
   */
   if (pwmspeed > 254) //bounds check, if greater than max, set it to max. This is need if the accel/decel rate is not a perfect multiple of the max speed(s)
   {
      
      pwmspeed=255;
   }
   
   if (pwmspeed < -254) // same deal, except negative.
   {
      
      pwmspeed = -255;
   }
   
   // send the command to the motor
   if(pwmspeed==0)
   {   // All stopped
      analogWrite(fwdpwm,0);
      analogWrite(revpwm,0);
      currentmode=stopped;
   }
   else if(pwmspeed>0)
   {   // forward motion
      analogWrite(revpwm,0);
      analogWrite(fwdpwm,pwmspeed);
   }
   else
   {   // reverse motion
      analogWrite(fwdpwm,0);
      analogWrite(revpwm,-1*pwmspeed);
   }
   delay(50);
}
/*****************************************************************************************************************************************/



#145728
Good catch Maxpower!!

I've got a few different arduinos kicking around, and I'm currently using the 32-bit Due for the F150. I've stopped using the basic INT/BYTE variable declarations, and have switched to uint8_t/uint16_t instead. I've spent way too much time troubleshooting problems that were from a variable assignment because i reused a library/sketch that was written for 8-bit registers.
#146595
maxpower wrote:Hi,

Sorry to be posting in a long dead thread but I thought I should update those who may try using the code here for their power wheels project.

I took the code here and tried using it with an arduino/HBridge setup and got really bizarre behaviour when I shifted the car into reverse.

I ran the code thru an arduino simulator and observed the same bizarre (unsafe!) behaviour with the car moving in the wrong direction uncommanded.

At any rate, I won't bore you with the technical details but one of the root causes was the "currentmode" variable was defined as a byte, yet the reverse command is a negative number.... this created aberrant behaviour.


Thanks for posting this, it's been a while since I wrote this code, so I don't fully remember everything about it. However I did notice you seem to have a typo on your pin definitions, unless your Arduino actually has 51 pins.

I'll post an update to my original post.

I know this thread is getting kind of old by now b[…]

Quad Damage (1st gear delete mod)

Chart, that rubber grip looks like it would eat th[…]

If you're using stock motors and gearbox be carefu[…]

Fire Rescue Jeep Major Overhaul!

Oh, its is gonna be a paw patrol police jeep!

HobbyMasters Udemy Course