RC Tractor help

Hello fellow robonauts. Please help.

I'm making my ride-on lawnmower/tractor into a remote drive system. It's a Kubota BX23 and will use a linear actuator to activate the gas pedal(forward and reverse). Also a stepper motor to turn the hydraulic steering unit.

I'm using a MegaMoto board for the actuator, from http://RobotPower.com. And a Big Easy Driver from http://SparkFun.com for the stepper motor. The micro-controller is a SparkFun RedBoard. The transmitter/receiver is a 6 channel 2.4gHz digital remote.

I'm having trouble with the flow control of the actuator, perhaps different eyes can find my error.

Attached is the code I've written up to this point. It seems to correctly read the receiver and give back valid PWM values. It currently does not move the actuator.

I think my problem is nested somewhere in my "if" statements. It was working at one point, ie the actuator moved, but had some bounce at end of stroke and at the pre-defined set points. It's been suggested that the PID library may help here.

I'd also like the actuator to accelerate and "de-accelerate", but had trouble incorporating that into my code. I've also considered using the AccelStepper library since I'll be using that to control the stepper motor after I get this actuator working.

Although I've taken some programming courses, I would not call myself a programmer by any means, and it's been a while, please forgive any laughable errors in code.

All constructive help, suggestions, examples or comments are welcome.
Thank you.
-Aaron

RC_control_megamoto_081715.ino (11.1 KB)

const float nuetral = constrain(nuetral, 465.0, 475.0);
const float fullRetract = constrain(fullRetract, 770.0, 780.0);
const float halfRetract = constrain(halfRetract, 610.0, 620.0);
const float halfExtend = constrain(halfExtend, 355.0, 365.0);
const float fullExtend = constrain(fullExtend, 251.0, 261.0);

What is this crap? What value are you actually constraining? For instance, what is the value of nuetral before the constrain() macro operates on it?

I think my problem is nested somewhere in my "if" statements.

Without seeing your serial output, we'd have no way of knowing.

        Retracting = true;
        Extending = false;

If the actuator is not retracting, it is either holding still or extending, isn't it? ONE variable is sufficient, and eliminates the possibility of setting two variables wrong.

I'd suggest some functions that return boolean values.

if(ch3 > 50 && ch3 <= 110

Makes no sense.

if(lowThrottle())

Makes a lot more sense. You can hide the fact that xh3 doesn't mean shit in the function(s). (Or, you could give ch3 a meaningful name.)

If ch3 represents something other than throttle, or 50 to 110 doesn't mean low, then, by all means, use a different function name.

    if(pwm <= 0) //constrains low end to 0
    {
      pwm = 0;
    }
  else if(pwm >= 245) //constrains high end to 245
  {
    pwm = 245;
  }

So, suddenly, you don't like the constrain() macro?

PaulS:
What is this crap? What value are you actually constraining? For instance, what is the value of nuetral before the constrain() macro operates on it?

I was trying to constrain target positions to a range so that when the actuator feedback jumps between 755-756, the actuator itself doesn't bounce at that position. The actual neutral value is 470.5.

Without seeing your serial output, we'd have no way of knowing.

True, true. I'll post my serial output later today.

If the actuator is not retracting, it is either holding still or extending, isn't it? ONE variable is sufficient, and eliminates the possibility of setting two variables wrong.

Right again. That portion came from some sample code if found elsewhere. Good call.

I'd suggest some functions that return boolean values.

I plan on doing that, but wanted to get working code first.

if(ch3 > 50 && ch3 <= 110

Makes no sense.

if(lowThrottle())

Makes a lot more sense. You can hide the fact that xh3 doesn't mean shit in the function(s). (Or, you could give ch3 a meaningful name.)
If ch3 represents something other than throttle, or 50 to 110 doesn't mean low, then, by all means, use a different function name.

Agreed.
Yes, ch3 is throttle, and 50 to 110 is low. So it made it little sense right.

So, suddenly, you don't like the constrain() macro?

I changed those constants to constrain after writing the other code. In an effort to eliminate the bounce in the actuator. Didn't work however. Now that I think more about it, can a const even be constrained?

Anyway, I'll keep at it. Thank you PaulS.

Now that I've had my coffee, if the actuator is not retracting, yes, it's either holding or extending, but w/o the 2nd variable, how do we which one it's doing?

Ok, so trying to make the preset positions a range using constrain didn't work, when I took those out the actuator moves again, mostly like I want it to.

But there is still bouncing at those positions.

I need suggestions for a better way. Because the actuator feedback floats a tiny bit, it needs to stop within a target position range.

Here is the code that I think is causing the bounce.

  //Move Tractor in Reverse
    else if(ch3 > 50 && ch3 <= 110 && ch5 >= 150)
    {// if ch3 is 1/4 stick and ch 5 is high
      targetPos = halfExtend; //set to move in reverse at half speed
      Serial.print("Target: ");
      Serial.println(targetPos);
      digitalWrite(enableMM_pin, HIGH);
      delay(100);
      if(targetPos > currentPos) //if target more than current
      {
        Retracting = true;
        Extending = false;
        digitalWrite(pwmA_pin, HIGH);
        digitalWrite(pwmB_pin, LOW);
        Serial.print("Retracting to: ");
        Serial.println(targetPos);
      }
      else if(targetPos < currentPos) //if target less than current
      {
        Retracting = false;
        Extending = true;
        digitalWrite(pwmA_pin, LOW);
        digitalWrite(pwmB_pin, HIGH);
        Serial.print("Extending to: ");
        Serial.println(targetPos);
      }
    }

Here is my serial output.
Ch3: 100 Ch5: 219 Ch6: 219 Current: 382
Armed Target: 360
Extending to: 360
Ch1: 106 Ch3: 100 Ch5: 219 Ch6: 219 Current: 370
Armed Target: 360
Extending to: 360
Ch1: 106 Ch3: 100 Ch5: 219 Ch6: 219 Current: 359
Armed Target: 360
Retracting to: 360
Ch1: 106 Ch3: 100 Ch5: 219 Ch6: 219 Current: 351
Armed Target: 360
Retracting to: 360
Ch1: 106 Ch3: 100 Ch5: 219 Ch6: 219 Current: 362
Armed Target: 360
Extending to: 360
Ch1: 109 Ch3: 100 Ch5: 219 Ch6: 219 Current: 369
Armed Target: 360
Extending to: 360
Ch1: 106 Ch3: 100 Ch5: 219 Ch6: 219 Current: 358
Armed Target: 360
Retracting to: 360
Ch1: 106 Ch3: 100 Ch5: 219 Ch6: 219 Current: 351

You can see in red where it switches conditions due actuator overshoot, or floating analog input.

Now that I've had my coffee, if the actuator is not retracting, yes, it's either holding or extending, but w/o the 2nd variable, how do we which one it's doing?

What kind of variable can only hold two values? An int could hold -1 for retracting, 0 for holding still, and 1 for extending.

I don't follow banging PWM pins on or off. The reason for using PWM is to enable sneaking up on a position. You don't drive you car with the throttle to the floor, and half way into the garage slam on the brakes, do you? Why are you driving the actuator that way?

FYI, a Kubota BX23 is a 1000kg tractor (!) with a hydrostatic transmission. It's not a "gas pedal" or throttle he's moving -- he's moving the forward/reverse control lever which is linked to a bi-directional, variable displacement, hydraulic pump. The diesel engine will be running at a pretty consistent 3000RPM the entire time.

Whatever linear actuator he's using apparently has a potentiometer feedback. A hydrostatic transmission can handle jerk-y starts and stops but I doubt the linear actuator moves quickly enough to do that.

Right on the money Chagrin.

The actuator moves quickly enough to be responsive, but not so fast it will cause fast starts or stops in the transmission. The actuator itself is a DC motor with screw drive, so I'm not using PWM to drive it, just simple digital.
My problem is coding some kind of hysteresis so the actuator doesn't "bounce" at its target position.

The stepper I'm using is being driven off the Big Easy Driver from SparkFun, and does use PWM for accelerations. (Using the AccelStepper library.)

I'll be working on this project again over Labor Day weekend, and will post updates to my code and results of the testing.

Thank you all, and keep the suggestions coming.

acciomn:
The actuator moves quickly enough to be responsive, but not so fast it will cause fast starts or stops in the transmission. The actuator itself is a DC motor with screw drive, so I'm not using PWM to drive it, just simple digital.

:o :o :o

I would highly suggest you rethink your system. It's an accident waiting to happen!

Your actuator - if it is like most (but not all) linear actuators - most likely can't be back-driven. That is, once it is at one set position, it can't be changed by any external force against it. Normally, this is something you want. But not for acceleration control on a gas powered machine.

What would happen if something failed - for instance, the electrical connector vibrates loose from the actuator or controller, or the wiring to the motor breaks due to vibration, or any number of other possibilities - all when you least expect it?

Now you have a several-hundred pound machine - albeit lumbering slowly along (well - depends on where the accelerator got stuck, and the gear the mower is in, and what its top speed is) - with spinning blades of death - and little or no control.

Puppy in the way? No problem, right? Cat? Goodbye. Child? Who cares, right?

All robotics systems, beyond desktop rover sized, need to have mechanisms to help prevent injury and property damage as they increase in size. The kind of robotic system you are creating - that is, a large and heavy one, and especially one powered by an engine - need to have the utmost in safety systems.

In fact - for such systems - I would argue that safety needs to be designed in at the very beginning - that is, planning fail safes for as many scenarios as one can imagine - both at a hardware level, and at a software level - before coding any logic, or anything else. This needs to be extremely well planned, then discussed with others to ensure you haven't missed anything. Then this system needs to be implemented first.

In your case, you need an accelerator actuation system that - should power or something else fail - returns back to zero acceleration. You likely also need a valve on the fuel system to auto-shutdown the fuel supply (alternatively - and maybe easier to implement - something to shutoff the air supply would work too). You need mechanisms - electrical, mechanical, software, hands-on, and remotely controlled - methods to allow you to instantly shut-down the system should it go out of control - there needs to be a big red stop button on the thing that is easily reachable (but out of the way of any dangerous spinning parts) by anybody who needs to shut it down. There might also need to be a "pull to deactivate" switch or similar (like you find on jet-skis) - though this is usually only needed for machines that can move quicker than one can walk or run - which may not be the case here. These shut-down mechanisms must be fail-safe as well - once activated, they should cut the power to everything - and must require a willful, manual reset before the robot will run again.

Your software needs to have proper structure, so that there is a safety and security "module" or "library" or "class" - something that any other part of the system can query or activate as needed, and that activation can be total or tiered (so the robot can selectively shut-down parts of the system, if needed - if it determines that there is an issue - like a broken blade or something - that would disable a function, but it could still "go home" if the steering and movement controls still worked). It should also have the ability to report it's status (both by push, and by request) - and ultimately be able to "call for help" - both via a remote means (RF or similar) as well as by audio/visual means (flashing light, siren, alarm, etc).

Lastly - all testing on the robot - especially one of this nature - if you aren't already doing it - should be done with the wheels off the ground, in the initial phases of the project. There are more than a few anecdotal stories out there of people who have built larger robots, doing their software/hardware testing, and something goes wrong, and the robot goes careening down a hallway, only to be stopped by a wall (generally causing a few hundred dollars in damage). Fortunately, I haven't heard of any hobby robots seriously injuring their builders - but I am sure injury has happened; I know for a fact more than one repairman of industrial robots have been killed because of a failure in lockout/tagout - the precedent is there.

Use your linear actuator (or a similar one - if you need a longer travel length or such) to control the steering; use some other mechanism - one that can fail "closed" to no acceleration - to control the fuel. I know this all might seem like overkill, but it honestly won't should it all go wrong down the road.

Good luck with your project, and I hope it turns out well.

:slight_smile:

Not sure what type of linear actuator setup you are using, but the below actuator controller might make controlling the actuator easier.

http://www.robotshop.com/en/firgelli-technologies-linear-actuator-control-board.html

Hi cr0sh,

Thank you for the detailed post. I've thought of some safety systems, but a fuel shutoff would be a very beneficial addition. The program will have remote shutoff, etc. and the actuator can free-wheel so the gas return spring will move back to neutral.
I'll definitely incorporate some kind of external hard kill switch, in case the electronics fail.

That being said, this project is being made for my father, so he can mow his 3 acre meadow. It won't be used anywhere that serious injury to others is likely.
Cheers,
-acciomn

acciomn:
Thank you for the detailed post. I've thought of some safety systems, but a fuel shutoff would be a very beneficial addition. The program will have remote shutoff, etc. and the actuator can free-wheel so the gas return spring will move back to neutral.
I'll definitely incorporate some kind of external hard kill switch, in case the electronics fail.

Well - that's good to hear; so many people build projects like this, and in the excitement of the construction and designing, they fail to think about the implications when something goes wrong. Planning and implementation doesn't get done, then when a problem arises (hopefully in such a manner that someone doesn't get hurt) - they try to implement the safety systems after the fact, which can be a near impossible task to take on without a complete code refactoring. Similar situations arise in computer software security all the time; instead of taking the time and investing the money up-front for solid security, that is left until last (or not at all), and only thought about after hackers have already stolen all the money and information.

acciomn:
That being said, this project is being made for my father, so he can mow his 3 acre meadow. It won't be used anywhere that serious injury to others is likely.

Those are "famous last words" - take the time to design it in now, and you won't have to worry about it later. You can't close the barn doors after the horses have already run away...

You can't close the barn doors after the horses have already run away...

Sure you can. The horses won't mind. They're long gone. 8)