The Openpilot Community needs your help to continue to keep opc.ai's lights on and support the path to Workbench v0.2. With only a one person crew and without commercial funding it's not always financially feasible to fund these services out of pocket. Please consider becoming a Patreon supporter of the Openpilot Community project and receive exclusive perks and benefits!
Become a patreon Learn more Maybe Later
Real-Time Tuning Guide for OpenPilot
• Real-Time Tuning changes are EXTREMELY EXPERIMENTAL and are considered for DEVELOPMENT USERS ONLY who are aware of the risks involved.
• Changing parameters “on the fly” is extremely risky!
• You should only use real-time tuning from the passenger seat and a driver should be carefully monitoring the car with HANDS ON THE WHEEL AT ALL TIMES.
• The latest commits to the real-time tuning code and the related files can probably be found here:
New (0.5.6): https://github.com/James-T1/openpilot/commits/Gernby-FFAR-Stinger
Old (0.5.5): https://github.com/James-T1/openpilot/commits/alca-dev
• If you aren't on a Hyundai/Kia vehicle you will need to port the real-time tuning changes to controlsd.py and the related helper files (latcontrol.py, vehiclemodel.py, pathplanner.py, etc) to your fork. See the end of the article for some porting notes that may or may not be helpful.
• You will also need the two real-time tuning python scripts: rtt_cl_interface.py and rtt_pickle_print.py
• The first time you start the car with the changes to controlsd it will create the '/data/.openpilot_rtt_params.pkl' real-time tuning file in your /data/ folder.
• To begin live tuning you simply need to start the car, "cd /data/openpilot/selfdrive", and run: "python rtt_cl_interface.py"
• Press CTRL-C and then hit Enter at any prompt to quit the tuning script.
• I usually also monitor the openpilot tmux session in a separate terminal window just to keep an eye on things there.
• Print a pretty list of your real-time tuning parameters by running: "python rtt_pickle_print.py"
• To start over from the default values in interface.py, just kill openpilot and then delete the "/data/.openpilot_rtt_params.pkl” file. When you restart openpilot and successfully connect to your car (fingerprint recognized) the real-time tuning parameter file will be re-created from the default parameters. If you just delete the file without killing openpilot first the file will be re-created from the values in memory at the time and failsafe values (probably not what you were trying to accomplish).
• Kp and Ki are Python lists of values at various speed ranges that can be set by the user.
• KpBP and KiBP are the boundary points with the speeds that the values are interpolated between.
• KpV and KiV are the values used at each of the boundary speeds. Kp and Ki are interpolated by Openpilot for other speeds.
• If your current tune uses a single value in the lists, then you will have to use a single value while using real-time tuning.
• If you want to use more values with more speed ranges to interpolate Kp and Ki between, then you will need to update interface.py with more boundary points and values in each list.
• IMPORTANT: Any time you change the length of the Kp/Ki lists in interface.py, YOU MUST DELETE the "/data/.openpilot_rtt_params.pkl" file, restart Openpilot, and then start the car to create a new "/data/.openpilot_rtt_params.pkl” file from the stock parameters. There is no error checking for a mis-match in list lengths in the real-time tuning script, so you will end up overwriting the new length lists with the old length lists if you do not delete the real-time tuning file first!
• Lists of values can be entered in any of the following forms with any number of values (1 or more) with any amount of whitespace (or no whitespace) between the values: Single value in list = 0.15, or [0.15] Multiple values in list = .15,.2,.25,.3 or .15, .2, .25, .3 or [.15,.2,.25,.3] or [ .15, .2, .25, .3 ]
Begin with these parameters:
• Feel free to use your own parameters if you have some that are already working, but it’s also fun to start from “scratch” and experiment to learn the full impact of each change.
• Start with Kp = 0.25
• Start with Ki = 0.03 (Set low on purpose)
• Start with Kf = 0.00003 (Set low on purpose)
• Start with steerActuatorDelay = 0.1 (unless someone else has already found a closer value for your car)
• Start with steerRatio = factory spec
• Start with steerRateCost = 0.5
• Start with tireStiffness values of whatever you have stock in interfaces.py. Honda civic defaults are around 200000.
Drive on a straight road with OP engaged. Kp will be the first parameter that we adjust, starting from Kp = 0.25
• If OP is oscillating back and forth around center, it will either be a slow or fast oscillation depending on how high/low your Kp is. We're looking for a small amount of slow-ish oscillation.
• Increase Kp to 0.5, then decrease to 0.1. Choose the "best" one and split the difference between it and 0.25. Set Kp to the new value in the middle.
• You're looking for no fast wobble around center. You want a lazy wobble around center, or ideally a fairly solid hold on center without any abrupt movements.
• Choose the best of 0.25, the extreme value, and the new "split difference" value. Split the difference again in the best direction and continue this process until Kp is optimized.
• You may need to re-tune this at slow speeds (10mph) and fast speeds (60+mph) and possibly even use speed-dependent Kp values as mentioned in the "Background" section above.
• If there are high winds or the road has significant camber then you may experience the car drifting to one side and OP adjusting the wheel only in one direction (always adjusts to the right, etc). This is okay. Keep focused on back AND forth oscillations of the wheel take take you across the center of the lane (slow or fast).
• Don't drive yourself too crazy on this, as we still need to tune steerActuatorDelay to get the best performance.
• steerActuatorDelay adjusts the starting orientation of the car which is fed into the MPC in order to account for the delay between the measurements and the response to a commanded output. The delaycurvature_factorsteerRatio product needs to match the response of your car.
• steerActuatorDelay should be adjusted in the range of 0.025 to 0.200 in 0.025 increments (0.025 - 0.050 - 0.075 - 0.100 - 0.125, etc)
• Find the setting that provides the least amount of wobble around center. You should see a dramatic difference between 0.025 and 0.200, and somewhere in-between should be a "best" setting.
• Some truly bad MDPS systems may even need delays above 0.200?
Adjust Kp slightly up and down to see if you can further optimize it now that the ActuatorDelay is set. Adjust Ki to help with constant offsets like wind, cambered roads, etc.
• Increase Ki to 0.2, then try 0.1, 0.05, etc. Find the value just before it begins to do a slow overshoot, correct, overshoot, correct pattern.
• Again, you're looking for no movement around center or a very slow and gentle movement around center.
Now try taking some turns and adjust Kf.
• First make sure that OP is properly identifying the lane lines in the turn you are attempting to take. Not just the green path, but the actual lane lines on each side as well.
• If you're having an issue initiating and holding turns, try increasing Kf. 0.00006 is the typical value used, and somewhere between 0.00003 and 0.00010 will probably be appropriate.
• If you increase Kf to help in turns, you may need to decrease Kp slightly if oscillations have increased. If you have increased Kf too much then it may not be possible to compensate with Kp changes.
• There is a balancing act between Kf/Kp/Ki that you are trying to find.
• If the car is too far right in the lane, try decreasing camera offset from the stock value of 0.06 to something like 0.03 or 0.0.
• If the car is too far left in the lane, try increasing camera offset by 0.03 at a time.
Adjusting tireStiffness changes the curvature_factor used in the MPC.
• Feel free to play with the tireStiffness values. The stock Honda civic values are around 200,000. Yours may be slightly higher or lower.
• Values between 50000 - 300000 are probably worth playing with.
• While tuning, try to keep them at the same value as generally they end up pretty close to each other anyway (within 5-10%)
Adjusting steerRateCost will affect how eager the car is to make sudden direction changes.
• steerRateCost around 0.7-1.0 will feel very sluggish and unwilling to make direction changes.
• steerRateCost around 0.5 is a nice median.
• steerRateCost around 0.3 or less will feel extremely darty as the lane has minor deviations or the path changes.
• steerRatio will have a large impact due to it essentially scaling Kf/Kp/Ki together (steerRatio is multiplied by the MPC's calculated steering angle delta, and this result is then multiplied by the gains).
• Changing steerRatio will require scaling Kf/Kp/Ki as well in order to regain the tuned performance. It will be a dramatic change.
• I don't bother changing steerRatio from spec once Kp and Kf have been tuned since the only other minor impact on lateral control it has is on the VehicleModel slip factor / curvature_factor calculation which is then fed into the MPC & the actuator delay orientation calculation.
• My advice: leave it alone
latPidDeadzone shouldn't need to be messed with (defaults to 0).
• Experiment at your own risk.
• "What's the easiest way to get JamesT's live tuning mod running on the Prime?"
"Probably some version of cherry-picking the git commits involving real-time tuning. I've tried to name them all "Real-Time Tuning: ", but I know I missed that on the last commit that patched a bug (it was done in a hurry)"
There are additional later commits that create a python socket server that has an extremely basic API for building remote real-time tuning applications for phones, tablets, etc. There's no real documentation on the API. You literally just send a "sendData" message when you want it to send back the tuning file data. It will send a big message full of the rtt tuning file data including each parameter/value combo separated with exclamation points, like this: steerKpV:L1:0.15!steerKiV:L1:0.10!steerKf:V:0.00009!
When you send data back to the socket server you return it in the same format, but as a single parameter at a time. The data format is: ParamName::value
: V = single float value, L1 = list of length 1 (which is sent as a single float value and then converted back to a list on the server side), L2= list of length 2 or more (sent as comma separated values)
So typical messages might be something like: