Automatic Transmission Controller

No, I am not the guy from the movie but I do like Huey Lewis & The News.

I have a question about the feasibility of using an Arduino to control an automatic transmission with paddle switches. I have to admit I know absolutely nothing about programming electronic control systems but I am handy with electrics and spanners.

The transmission uses 2 x 12v solenoids - the 4 combinations of solenoids states achieve 4 forward gears

  • 1st Gear - S1 ON / S2 OFF
  • 2nd Gear - S1 ON / S2 ON
  • 3rd Gear - S1 OFF / S2 ON
  • Overdrive - S1 OFF / S2 OFF

Park, Reverse and Neutral are engaged mechanically by the selector lever but, once in Drive, all changes are electronic. Obviously this is controlled by a factory computer in the car, but I would like to have manual control over the system.

The trigger consist of 2 inputs - Input 1 triggers an upshift, Input 2 triggers a downshift. Using the solenoid states shown above, I would expect the logic to go something like this...

Sequence of triggers from Input 1 (upshift)
If state = 1st Gear, change to 2nd Gear
If state = 2nd Gear, change to 3rd Gear
If state = 3rd Gear, change to Overdrive
If state = Overdrive, do nothing

Sequence of triggers from Input 2 (downshift)
If state = 1st Gear, do nothing
If state = 2nd Gear, change to 1st Gear
If state = 3rd Gear, change to 2nd Gear
If state = Overdrive, change to 3rd Gear

This should allow the next gear in sequence, regardless whether shifting up or down, to be selected, and prevent the system from going any further once the lowest or highest gears have been reached.

Any advice as to whether this is possible with an Arduino would be great. Based on what I've seen, this is a small ask from such a powerful circuit, but making this circuit work using relays is melting my brain.

Many thanks!

Bog standard state machine coding with state change detection on the buttons. Read about State Machines here, here, or here. Here is the Arduino reference on switch...case, which is a useful coding technique when "if" gets a bit cumbersome, and this is how to poll for a button to change state.

Interestingly, the logic for this project is almost identical (maybe even actually identical) to this thread's which is about a quiz on an lcd with only yes/no answers.

On entering each state, set the solenoids, and listen for a new press of either button, then leave the state to the next one depending on the button.

No, I am not the guy from the movie but I do like Huey Lewis & The News.

That one's lost on me.

There’s something in the Microchip / Atmel datasheets about the underlying Arduino chip being specifically excluded from automotive use, btw.

jubukraa:
There's something in the Microchip / Atmel datasheets about the underlying Arduino chip being specifically excluded from automotive use, btw.

In addition, your insurers would probably not be very happy with you if you intend to use the car on public roads.

You would need to ensure that the paddle switches are debounced: if you get phantom signals changing up, oh well, but if you get them changing down, the resulting changes could blow the engine. I think I'd want to validate the RPM before executing a change.

1 Like

Thanks to all for your advice.

I've had manualised-automatic transmissions using ratchet shifter in the past and you accidentally grabbing a gear in the wrong direction is always a possibility. Does the Arduino have the ability to use and RPM input signal to lockout downshifts - i.e if RPM > 4500, inhibit downshift?

Having never used an Arduino before, I have no idea if these units are known to be glitchy or unreliable...

"Atmel products are not suitable for, and shall not be used in, automotive applications. Atmel products are not intended, authorized, or warranted for use as components in applications intended to support or sustain life".

I get that, however I would imagine that this is because the ability to program these units is limitless and comes down to the quality of coding put into it - and rigorous (or lack thereof) testing.

@jubukraa

patrick_bateman:
Does the Arduino have the ability to use and RPM input signal to lockout downshifts - i.e if RPM > 4500, inhibit downshift?

It has the ability to make such a decision, given you can get the rpm value into the Arduino. How to do that is beyond my experience. But in my mind I have programmed your project, just using a potentiometer as a surrogate tach. The coding's pretty simple.

patrick_bateman:
I get that, however I would imagine that this is because the ability to program these units is limitless and comes down to the quality of coding put into it - and rigorous (or lack thereof) testing.

No, I don't think it's that. As far as I know, they have a companion range of products certified for automotive use. I'm pretty sure they could disclaimer-their-way-out of any liability due to defective programming of what they supply as an empty bucket.

I just attached my code in the other thread I mentioned, here.

Have a look at it, since as I say the logic's pretty much what you want. (Go into a state, do stuff (that one put a message on an lcd, yours would set relays), and exit to some other state depending on the state of the buttons (where those are yes/no, yours are up/down.)

(It's not checking rpm of course :wink: but that would be easy to code, assuming there's a way of physically interfacing to the car to get a tach signal.)

Can bus is a way to get rpm (and much more) as long as the vehicle isn't antique.

1 Like

Its on a 1991 Toyota pre-CANbus so the G signal (camshaft position sensor) could be tapped into. Does the Arduino accept inductive AC inputs or does it need to be rectified?

patrick_bateman:
Its on a 1991 Toyota pre-CANbus so the G signal (camshaft position sensor) could be tapped into. Does the Arduino accept inductive AC inputs or does it need to be rectified?

It sure needs to be “something”-ed :wink: but I have no idea what that would be. Others will, no doubt.

You can mimic this whole thing off the car with a couple of buttons and a pot getting read on an analog input as an ersatz tach, and some leds as surrogate relays. At least you can get your head around the logic of the coding.

I am watching tutorials now - thanks for your help

Here as a Proof-of-Concept is a sketch that does what you want to do. It uses a potentiometer as a stand-in tacho, with its analog readings of 0-1023 mapped to 0-7000 rpm for testing purposes. The solenoids are 2x leds, and there’s an led for each gear.

Arduino powers up into PRN mode, and leaves there for D when the gear lever is moved to D. (You didn’t say what should happen if the lever is moved out of D at any stage, so I haven’t coded that. Right now it stays in D and the paddles work, even if it’s moved out of D.)

// https://forum.arduino.cc/index.php?topic=682363
// 6 may 2020

/*
  The transmission uses 2 x 12v solenoids - the 4 combinations of solenoids states achieve 4 forward gears

    1st Gear - S1 ON / S2 OFF
    2nd Gear - S1 ON / S2 ON
    3rd Gear - S1 OFF / S2 ON
    Overdrive - S1 OFF / S2 OFF

  Park, Reverse and Neutral are engaged mechanically by the selector lever but, once in Drive, all changes are electronic. Obviously this is controlled by a factory computer in the car, but I would like to have manual control over the system.

  The trigger consist of 2 inputs - Input 1 triggers an upshift, Input 2 triggers a downshift. Using the solenoid states shown above, I would expect the logic to go something like this...

  Sequence of triggers from Input 1 (upshift)
  If state = 1st Gear, change to 2nd Gear
  If state = 2nd Gear, change to 3rd Gear
  If state = 3rd Gear, change to Overdrive
  If state = Overdrive, do nothing

  Sequence of triggers from Input 2 (downshift)
  If state = 1st Gear, do nothing
  If state = 2nd Gear, change to 1st Gear
  If state = 3rd Gear, change to 2nd Gear
  If state = Overdrive, change to 3rd Gear
  Does the Arduino have the ability to use and RPM input signal to lockout downshifts - i.e if RPM > 4500, inhibit downshift?
*/

// so this one has up and down buttons and a pot as a pretend tacho

//states
enum {ST_PRN, ST_D1, ST_D2, ST_D3, ST_D_OD} currentGear = ST_PRN;
// ala https://www.gammon.com.au/statemachine

bool goingUp = false;
bool goingDown = false;

const byte goingUpPin = 8;
bool goingUpState;
bool lastgoingUpState;
const byte goingDownPin = 9;
bool goingDownState;
bool lastgoingDownState;

//leds to indicate which solenoid is on, and current gear
const byte sol1 = 2;
const byte sol2 = 3;
const byte firstGearLed = 4;
const byte secondGearLed = 5;
const byte thirdGearLed = 6;
const byte ODGearLed = 7;
// and the ersatz tacho
const byte tacho = A0;
int tachoVal;
//gear lever
// a switch from pin to ground, if it's LOW it's in D, if HIGH it's PRN
const byte gearLever = 15;

//solenoid logic
#define ON HIGH
#define OFF LOW

void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println("*** gear box ***");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(sol1, OUTPUT);
  pinMode(sol2, OUTPUT);
  pinMode(firstGearLed, OUTPUT);
  pinMode(secondGearLed, OUTPUT);
  pinMode(thirdGearLed, OUTPUT);
  pinMode(ODGearLed, OUTPUT);
  pinMode(gearLever, INPUT_PULLUP);
  pinMode(goingUpPin, INPUT_PULLUP);
  pinMode(goingDownPin, INPUT_PULLUP);
  //initialize button states
  goingUpState = digitalRead(goingUpPin);
  lastgoingUpState = goingUpState;
  goingDownState = digitalRead(goingDownPin);
  lastgoingDownState = goingDownState;

  delay(1000);
  Serial.println("setup() done");
  Serial.println(" ");
  Serial.println("Starting in PRN, move lever to D");
}

void loop()
{
  tachoVal = map(analogRead(tacho), 0, 1023, 0, 7000);
  goingUp = checkgoingUpButton();
  goingDown = checkgoingDownButton();
  changeGear();
} //loop

void changeGear()
{
  switch (currentGear) //ST_PRN, ST_D1, ST_D2, ST_D3, ST_D_OD
  {
    case ST_PRN:
      //Serial.println("   prn");
      //all gear leds off
      digitalWrite(firstGearLed, OFF);
      digitalWrite(secondGearLed, OFF);
      digitalWrite(thirdGearLed, OFF);
      digitalWrite(ODGearLed, OFF);
      //no idea what solenoids should be doing in this state
      digitalWrite(sol1, OFF);
      digitalWrite(sol2, OFF);

      //here all we check is the lever and go to to ST_D1 if it's not in P, R or N
      if (!digitalRead(gearLever))
      {
        currentGear = ST_D1;
        Serial.println("   Going out of PRN, use the up and down buttons");
      }

      //the up and down buttons are ignored

      break;

    case ST_D1:
      //solenoids on/off, first gear led
      digitalWrite(sol1, ON);
      digitalWrite(sol2, OFF);
      digitalWrite(firstGearLed, ON);
      digitalWrite(secondGearLed, OFF);
      digitalWrite(thirdGearLed, OFF);
      digitalWrite(ODGearLed, OFF);

      if (goingUp) //this would only have been returned true by checkYesButton() if the goingUp button was pressed
      {
        currentGear = ST_D2;
        goingUp = false;
      }

      //going down is ignored in first gear

      break;

    case ST_D2:
      //solenoids on/on, second gear led
      digitalWrite(sol1, ON);
      digitalWrite(sol2, ON);
      digitalWrite(firstGearLed, OFF);
      digitalWrite(secondGearLed, ON);
      digitalWrite(thirdGearLed, OFF);
      digitalWrite(ODGearLed, OFF);

      if (goingDown && tachoVal < 4500) //this would only have been returned true by checkgoingDownButton() if the goingDown button was pressed
      {
        currentGear = ST_D1;
        goingDown = false;
      }

      if (goingUp) //this would only have been returned true by checkYesButton() if the goingUp button was pressed
      {
        currentGear = ST_D3;
        goingUp = false;
      }
      break;

    case ST_D3:
      //solenoids off/on, third gear led
      digitalWrite(sol1, OFF);
      digitalWrite(sol2, ON);
      digitalWrite(firstGearLed, OFF);
      digitalWrite(secondGearLed, OFF);
      digitalWrite(thirdGearLed, ON);
      digitalWrite(ODGearLed, OFF);

      if (goingDown && tachoVal < 4500) //this would only have been returned true by checkgoingDownButton() if the goingDown button was pressed
      {
        currentGear = ST_D2;
        goingDown = false;
      }

      if (goingUp) //this would only have been returned true by checkYesButton() if the goingUp button was pressed
      {
        currentGear = ST_D_OD;
        goingUp = false;
      }
      break;

    case ST_D_OD:
      //solenoids off/off, overdrive gear led
      digitalWrite(sol1, OFF);
      digitalWrite(sol2, OFF);
      digitalWrite(firstGearLed, OFF);
      digitalWrite(secondGearLed, OFF);
      digitalWrite(thirdGearLed, OFF);
      digitalWrite(ODGearLed, ON);

      if (goingDown && tachoVal < 4500) //this would only have been returned true by checkgoingDownButton() if the goingDown button was pressed
      {
        currentGear = ST_D3;
        goingDown = false;
      }

      //going up is ignored in over drive gear
      break;

  }//switch
}//changeGear

bool checkgoingUpButton()
{
  bool temp = false;
  // read the button:
  goingUpState = digitalRead(goingUpPin);

  if (goingUpState == LOW && lastgoingUpState == HIGH)
  {
    Serial.println("New goingUp ");
    temp = true;
    // Delay a little bit to avoid bouncing
    delay(50);
  }//change
  lastgoingUpState = goingUpState;
  return temp;
}//goingUp

bool checkgoingDownButton()
{
  bool temp = false;
  // read the button:
  goingDownState = digitalRead(goingDownPin);

  // compare the buttonState to its previous state
  if (goingDownState == LOW && lastgoingDownState == HIGH)
  {
    Serial.println("New goingDown ");
    temp = true;
    // Delay a little bit to avoid bouncing
    delay(50);
  }//change
  // save the current state as the last state, for next time through the loop
  lastgoingDownState = goingDownState;
  return temp;
}//goingDown

When the lever is in Park, Neutral and Reverse, a manual mechanical valve (connected to the gear lever) engages/disengages the appropriate clutches so solenoid activity is negated.

Thats a lot of work jubukraa - thanks for the time you've spent smashing that out. I am still working ym way through tutorials so once I am confident I can understand the code, I will have a go at setting this up on the bench with some LEDs.

We are a long way from trialling this in the car but its encouraging that this community has so much knowledge and is happy to share.

Thanks a million!

patrick_bateman:
Thats a lot of work jubukraa - thanks for the time you've spent smashing that out.

You're welcome: it was a fairly simple re-work of the sketch I had just done for that other thread.

patrick_bateman:
We are a long way from trialling this in the car

Disclaimer: include me out of the "we" there :wink: . I'm happy to help in a sort of abstract way where it's buttons and leds on the bench, but not going to take any responsibility for code that has to do with moving upwards of 2T of metal around.

I just saw this thread today and thought I'd share. You should take a look at this thread. This guy already did it and made working logic. He's been running it on his Toyota 2003 Tundra V8 with a340e transmission for a few years.

I was looking to doing this, but have not had time with everything going on. Perhaps you could figure it out and share. It may speed up your development. Only thing this code does not do is tap into RPM for safety to prevent downshifts that would result in over-revving.

If you figure it out, let me know. I'd love to have this for 2 Toyota's I have. Maybe I could even help you. I do coding for web such as PHP.

Automatic transmission control is more just switching gears.

Usually there is often also a line pressure control as well as a lockup torque converter.
If you don't control line pressure, either the clutches will wear out or the shifts may be violent.
Most line pressure solenoids are PWMd. The line pressure applied could be a function of the load applied, as in throttle position or preferably map sensor.

Precautions must be taken to not downshift under any circumstance if the engine RPM is to high.
Precautions must be taken not to downshift if the mile/hour is too high.

Paddle shifting code is easier than automatic shifting code.

My 4L80E controller has thousands of flawless miles under it's belt. But it's taken years of work, revisions, simulation, testing and 14,500 lines of code so far. Transmission controllers for real cars are not a beginner project. At a minimum, one should build numerous simulators to test everything out of the car.

I'm sure some will ask me for my code and design. For liability reasons that's not going to happen.

But I will be happy to make suggestions and possibly provide some example routines.

In my case the transmission controller also PWMs 6 fans, PWMs 2 fuel pumps, PWMs the alternator, has a canbus interface to the engine management, alarms, as well i/o to a 7" touch screen digital dash that lets me set one of 5 driving modes, change hundreds of parameters, display error information, log and more.

Here's a link to my car and controller build:
https://www.corvetteforum.com/forums/c3-tech-performance/3862459-turbo-c3-76-corvette-project-lsx-4l80e-4-link-real-street-driver-and-strip-car.html

There's alot to go through, but there is also lots useful electronics and transmission control info there.