Arduino 0-5v in to 0-5v out Throttle Interface

Sine

1 mW
Joined
Mar 10, 2019
Messages
16
I made an Arduino based throttle interface. It allows you to take 0-5v input from either Hall or Potentiometer throttles, and alter the output curve to anything you'd like. I'm using it to smooth out the throttle at the lower range.

You'll need an Arduino (Uno is what I used, Nano should work as well), a throttle and a MCP4725 Digital-To-Analog converter (DAC).

The currently programmed curve roughly follows this formula.

y = -0.0333(x)^4 + 0.2757(x)^3 - 0.468(x)^2 + 0.605(x)

Where x is the input voltage, and y is the output voltage. It looks like this.

ard.png

Throttle Connection:

Arduino Side <> Throttle Side:
5V<>Throttle Positive
GND<>Throttle Ground
A0<> 0-5v Throttle Signal

MCP4725 DAC:

Arduino Side <> MCP4725 DAC Side
GND<>GND
5v<> VCC
A4<>SDA
A5<>SCL

THe MCP4725 OUT and GND will go to your controller.

How it works:

The Arduino A0 Pin is an analog to digital input, it can sense voltages 0-5v at 10 bit resolution, this means that it has available to it 1024 'steps' that represent 0.0049v each. The Arduino via the MCP library converts these steps into integers (numbers that range from 0-1023).

The MCP4725 has 12 bits of resolution, or 4096 steps of resolution, represented by integers 0-4095 @ 0.0012v per unit.

I used Excel to calculate the input/output for all 1024 possibilities of input, then found the closest integer that matches with 4096 scale. If you want to make your own curve, you'll need to plot some points and have Excel graph the trendline, give you the formula and you recalculate the appropriate output integers.

The Arduino can do this VERY quickly, there's no perceptible latency between input/output changes. However, I haven't measured what this latency actually is.

Future possibilities:

Throttle Smoothing
Minimum throttle movement to cause an output change
Feedback loop with other sensors (traction control module? Tip-over cut off, etc.)


NOTE:

Hall type throttles will output ~0.85v - ~4.3v with 5v input. A pot can get you closer to the full voltage range, so keep this in mind that your effective curve will be different between pot/hall throttles and what range of the curve you're subject to.

Code:
/**************************************************************************/
/*! 
  Program takes in 0-5v linear input from Hall or Potentiometer throttle.

  Output is 0-5v non-linear according to function:
  y = -0.0333(x)^4 + 0.2757(x)^3 - 0.468(x)^2 + 0.605(x)

  AnalogRead() has 10 bits of resolution, 0-1023 int, .0049v per unit @5v
  dac.SetVoltage has 12 bits of resolution, 0-4095 int, .0012 per unit @5v
*/
/**************************************************************************/

#include <Wire.h>
#include <Adafruit_MCP4725.h>

Adafruit_MCP4725 dac;


int throttleInPin = A0;
int voltInInt = 0;
const int voltOutIntLUT[] PROGMEM = {0,3,5,8,10,13,15,17,20,22,24,27,29,31,33,36,38,40,42,44,46,48,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,80,82,84,86,88,90,91,93,95,97,99,100,102,104,106,107,109,111,112,114,116,117,119,121,122,124,125,127,129,130,132,133,135,136,138,139,141,142,144,145,147,148,150,151,153,154,156,157,159,160,161,163,164,166,167,168,170,171,172,174,175,177,178,179,181,182,183,185,186,187,189,190,191,192,194,195,196,198,199,200,202,203,204,205,207,208,209,210,212,213,214,216,217,218,219,221,222,223,224,226,227,228,229,231,232,233,234,236,237,238,240,241,242,243,245,246,247,248,250,251,252,254,255,256,257,259,260,261,263,264,265,266,268,269,270,272,273,274,276,277,278,280,281,282,284,285,286,288,289,291,292,293,295,296,298,299,300,302,303,305,306,307,309,310,312,313,315,316,318,319,321,322,324,325,327,328,330,331,333,334,336,338,339,341,342,344,346,347,349,350,352,354,355,357,359,360,362,364,365,367,369,371,372,374,376,378,379,381,383,385,387,389,390,392,394,396,398,400,402,404,405,407,409,411,413,415,417,419,421,423,425,427,429,431,433,435,438,440,442,444,446,448,450,452,455,457,459,461,464,466,468,470,473,475,477,479,482,484,486,489,491,494,496,498,501,503,506,508,511,513,516,518,521,523,526,528,531,533,536,539,541,544,547,549,552,555,557,560,563,566,568,571,574,577,580,582,585,588,591,594,597,600,603,606,609,612,615,618,621,624,627,630,633,636,639,642,645,648,652,655,658,661,664,668,671,674,677,681,684,687,691,694,697,701,704,708,711,715,718,722,725,729,732,736,739,743,746,750,753,757,761,764,768,772,775,779,783,787,790,794,798,802,806,810,813,817,821,825,829,833,837,841,845,849,853,857,861,865,869,873,877,881,886,890,894,898,902,906,911,915,919,923,928,932,936,941,945,949,954,958,963,967,972,976,980,985,989,994,999,1003,1008,1012,1017,1021,1026,1031,1035,1040,1045,1050,1054,1059,1064,1069,1073,1078,1083,1088,1093,1097,1102,1107,1112,1117,1122,1127,1132,1137,1142,1147,1152,1157,1162,1167,1172,1177,1182,1188,1193,1198,1203,1208,1213,1219,1224,1229,1234,1240,1245,1250,1256,1261,1266,1272,1277,1282,1288,1293,1299,1304,1310,1315,1321,1326,1332,1337,1343,1348,1354,1359,1365,1371,1376,1382,1388,1393,1399,1405,1410,1416,1422,1428,1433,1439,1445,1451,1457,1462,1468,1474,1480,1486,1492,1498,1504,1510,1515,1521,1527,1533,1539,1545,1551,1557,1564,1570,1576,1582,1588,1594,1600,1606,1612,1619,1625,1631,1637,1643,1650,1656,1662,1668,1674,1681,1687,1693,1700,1706,1712,1719,1725,1731,1738,1744,1751,1757,1763,1770,1776,1783,1789,1796,1802,1809,1815,1822,1828,1835,1841,1848,1854,1861,1867,1874,1881,1887,1894,1901,1907,1914,1920,1927,1934,1940,1947,1954,1961,1967,1974,1981,1987,1994,2001,2008,2015,2021,2028,2035,2042,2049,2055,2062,2069,2076,2083,2090,2096,2103,2110,2117,2124,2131,2138,2145,2152,2158,2165,2172,2179,2186,2193,2200,2207,2214,2221,2228,2235,2242,2249,2256,2263,2270,2277,2284,2291,2298,2305,2312,2319,2326,2333,2340,2348,2355,2362,2369,2376,2383,2390,2397,2404,2411,2418,2425,2433,2440,2447,2454,2461,2468,2475,2482,2489,2497,2504,2511,2518,2525,2532,2539,2546,2554,2561,2568,2575,2582,2589,2596,2604,2611,2618,2625,2632,2639,2646,2653,2661,2668,2675,2682,2689,2696,2703,2711,2718,2725,2732,2739,2746,2753,2760,2768,2775,2782,2789,2796,2803,2810,2817,2824,2831,2838,2846,2853,2860,2867,2874,2881,2888,2895,2902,2909,2916,2923,2930,2937,2944,2951,2958,2965,2972,2979,2986,2993,3000,3007,3014,3021,3028,3035,3042,3049,3056,3063,3069,3076,3083,3090,3097,3104,3111,3118,3124,3131,3138,3145,3152,3158,3165,3172,3179,3185,3192,3199,3206,3212,3219,3226,3232,3239,3246,3252,3259,3266,3272,3279,3285,3292,3298,3305,3312,3318,3325,3331,3338,3344,3350,3357,3363,3370,3376,3383,3389,3395,3402,3408,3414,3420,3427,3433,3439,3445,3452,3458,3464,3470,3476,3483,3489,3495,3501,3507,3513,3519,3525,3531,3537,3543,3549,3555,3561,3566,3572,3578,3584,3590,3596,3601,3607,3613,3618,3624,3630,3635,3641,3647,3652,3658,3663,3669,3674,3680,3685,3691,3696,3701,3707,3712,3717,3723,3728,3733,3738,3743,3749,3754,3759,3764,3769,3774,3779,3784,3789,3794,3799,3804,3808,3813,3818,3823,3828,3832,3837,3842,3846,3851,3855,3860,3864,3869,3873,3878,3882,3886,3891,3895,3899,3904,3908,3912,3916,3920,3924,3928,3932,3936,3940,3944,3948,3952,3956,3960,3963,3967,3971,3974,3978,3982,3985,3989,3992,3996,3999,4002,4006,4009,4012,4015,4019,4022,4025,4028,4031,4034,4037,4040,4043,4046,4049,4051,4054,4057,4059,4062,4065,4067,4070,4072,4074,4077,4079,4081,4084,4086,4088,4090,4092,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094,4094};
int voltOutInt = 0;

void setup(void) {
  Serial.begin(19200); //test code
  pinMode(throttleInPin,INPUT);
  dac.begin(0x60); // *You'll need to update this to the I2C address for your MCP*
}

void loop(void) {
  voltInInt = analogRead(throttleInPin);
  voltOutInt = pgm_read_word(&voltOutIntLUT[voltInInt]);
  dac.setVoltage(voltOutInt,false); 
  Serial.print("Vin: "); //test code
  Serial.print(0.0049 * voltInInt); //test code
  Serial.print(","); //test code
  Serial.print ("Vout is: "); //test code
  Serial.println (.0012 * voltOutInt); //test code
  delay (1);  //test code
  }
 
You could probably get away without the DAC if you use a PWM pin and a simple Low Pass Filter on it. It depends on the impedance of the circuit you are connecting the throttle to since the LPF will have a much higher output impedance than the DAC. Just a thought.
 
Nonlinear controls are horrible. More than likely you just have a controller that doesn't do torque-request throttle. TRT is intrinsically very smooth. Get one that does and use that arduino to set the output for perfect linearity if it's not already good.
 
Volt_Ampere said:
You could probably get away without the DAC if you use a PWM pin and a simple Low Pass Filter on it. It depends on the impedance of the circuit you are connecting the throttle to since the LPF will have a much higher output impedance than the DAC. Just a thought.

I thought about it, but eventually I'll be incorporating more sensors/outputs, so this allows me to standardize on something that will work for all scenarios.
 
flat tire said:
Nonlinear controls are horrible. More than likely you just have a controller that doesn't do torque-request throttle. TRT is intrinsically very smooth. Get one that does and use that arduino to set the output for perfect linearity if it's not already good.

Controller does torque control. "Smoothness" is not what I'm trying to achieve (I should have said widening). It's mechanical resolution at the lower end of the range. The interface is infinitely tunable, so I'll be able to test and change.
 
Hello
I just started working on cruise control for e-bike.
Plan is to mount it in between throttle and controller. in case one signal from throttle will go straight to controller (your code will be perfect for that), case two- when CC button is pressed - cruise control is on - arduino will pickup signal from speed sensor and adjust output to controller to maintain that speed. Signal from throttle will override it and switch off cruise control. signal from brakes will switch off cruise control as well - same when CC button is pressed again.
 
fdx said:
Hello
I just started working on cruise control for e-bike.
Plan is to mount it in between throttle and controller. in case one signal from throttle will go straight to controller (your code will be perfect for that), case two- when CC button is pressed - cruise control is on - arduino will pickup signal from speed sensor and adjust output to controller to maintain that speed. Signal from throttle will override it and switch off cruise control. signal from brakes will switch off cruise control as well - same when CC button is pressed again.

Hi, I am currently working on upgrading my current EEB Enduro ebike with Hub Motor with a new Bafang BBHSD with a ASI BAC800 external controller along with an EggRider display. I am new with Arduino, but is currently working on an electronic shifter with an Arduino Nano and would love to also have cruise control, exactly like you have described above.

I would like to know if you can share your code for the cruise control for your ebike.

Here is a youtube video of my ebike in action from last summer before the upgrade...

[youtube]N3TJ9dg9GLA[/youtube]

Keep in touch...
Cheers
Dan
 
serious_sam said:
Sine said:
I made an Arduino based throttle interface.

Any progress on your throttle interface? You should post some more details, and any updates on the development.

Sorry, haven't been around in minute. I haven't touched this part in a while. I still need to finish my bike, which is almost done. There won't be any changes to this module for a while, I'll probably start without it while I work out the other bugs I'll surely encounter.
 
Back
Top