Skip to content

Fix underpowered starter torque: mutation bug, hesitation tuning, engagement & compression#13

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1776651559-fix-starter-torque
Open

Fix underpowered starter torque: mutation bug, hesitation tuning, engagement & compression#13
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1776651559-fix-starter-torque

Conversation

@devin-ai-integration
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot commented Apr 20, 2026

Summary

Fixes 5 issues causing the starter motor to feel underpowered during cranking. The root cause was a combination of a progressive torque mutation bug and overly aggressive reduction factors that compounded to deliver as little as ~15% of base torque in cold-start scenarios.

Changes:

  1. Fix starterTorque mutation bug (line 2645-2646): device.starterTorque was being mutated every frame during misfires (device.starterTorque = device.starterTorque + misfireTorque + oscillation), causing progressive weakening throughout cranking. Now uses a local variable effectiveMisfireTorque to preserve the original device property.

  2. Reduce struggle phase duration (line 2354): Was a fixed 14-14.8s at reduced torque. Now scales with engine temperature: 3-4s when warm, up to 7s when very cold (-20°C). Uses coldFactor derived from engineTempC.

  3. Raise hesitation factor floor (line 2362): Changed from 0.5 + pulse * 0.4 (50-90% torque) to 0.7 + pulse * 0.25 (70-95% torque). The starter no longer drops to half-power during the struggle phase.

  4. Raise engagement factor start (line 1679): Changed from 0.6 + 1.7 * curve to 0.8 + 1.2 * curve. Initial crank now starts at 80% torque instead of 60%, giving a stronger first turn.

  5. Reduce compression stroke resistance when cold (line 2966): Changed from (2.0 - tempEffect) to (1.5 - tempEffect * 0.5). Cold compression resistance was stacking too aggressively with the other reduction factors.

Note: The first commit updates combustionEngine.lua to the current working version (v1.6) which includes glow plugs, carburetor integration, engine failure system, and expanded fuel database. The second commit contains the actual starter torque fixes.

Review & Testing Checklist for Human

  • Test cold start cranking — Start a vehicle at low temperature (~0°C or below) and verify the starter can turn the engine over without feeling stuck. Compare against pre-fix behavior.
  • Test warm start cranking — Verify warm starts feel snappy and the struggle phase (3-4s) doesn't feel too long or too short.
  • Extended cranking test — Hold the starter for 10+ seconds and verify torque doesn't progressively weaken (the mutation bug fix). The starter should maintain consistent strength.
  • Diesel cold start — Diesels have different tempEffect coefficients (0.6 + normalizedTemp * 0.6), verify they still feel appropriately harder to start when cold.
  • Flood scenario — Flood the engine and verify the starter still feels reasonable (flood reduction is unchanged, but the other fixes should give more headroom).

Notes

  • The starterMaxAV default multiplier (idleRPM * 0.5 on line 4510) was left unchanged since the user noted this was set for testing purposes. This can be tuned independently.
  • The 10% per-frame misfire chance during hesitation (line 2374) was left unchanged — the raised floor means these dips go to ~14-29% of base instead of ~10-27%.
  • All values are tunable via jbeamData overrides (starterTorque, starterMaxRPM, etc.) for per-vehicle adjustments.

Link to Devin session: https://app.devin.ai/sessions/bc7edecbb1a84a2a82236338bb6a8c45
Requested by: @lonewolf0708


Open in Devin Review

devin-ai-integration bot and others added 2 commits April 20, 2026 02:19
Co-Authored-By: BtaWlf <nharvey53@hotmail.com>
…agement & compression

- Fix starterTorque mutation bug: use local variable instead of mutating
  device.starterTorque each frame during misfires (was causing progressive
  weakening during cranking)
- Reduce struggle phase from 14s fixed to 3-7s scaled with temperature
  (colder = longer, warmer = shorter)
- Raise hesitation factor floor from 50-90% to 70-95% torque range
- Raise engagement factor start from 60% to 80% for stronger initial crank
- Reduce compression stroke resistance multiplier when cold
  (2.0 - tempEffect -> 1.5 - tempEffect*0.5)

Co-Authored-By: BtaWlf <nharvey53@hotmail.com>
@devin-ai-integration
Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@lonewolf0708
Copy link
Copy Markdown
Owner

This definitely feels better, but still undergoing testing.

@devin-ai-integration
Copy link
Copy Markdown
Author

Glad to hear it's an improvement! Let me know if any of the values need further tuning after more testing — happy to adjust the struggle duration, hesitation floor, engagement ramp, or compression resistance as needed.

Copy link
Copy Markdown
Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 potential issues.

🐛 5 issues in files not directly in the diff

🐛 Case mismatch device:lockup() calls undefined method; should be device:lockUp() (combustionEngine.lua:610)

In checkHydroLocking at line 610, device:lockup() is called with a lowercase 'u'. The actual function is defined as lockUp (capital 'U') at combustionEngine.lua:524 and assigned to the device as device.lockUp = lockUp at combustionEngine.lua:4409. There is no device.lockup defined anywhere. When the engine hydrolocks (flood level exceeds threshold), this will cause a nil function call runtime error, preventing the hydrolock from being properly applied and crashing the update loop.


🐛 local dt = 1/60 shadows the function parameter dt, breaking all subsequent time-dependent calculations (combustionEngine.lua:907)

At line 907, local dt = 1 / 60 redeclares dt as a local variable inside updateGFX(device, dt), shadowing the actual frame delta time passed as a parameter. All code after this line within updateGFX — including ignition error timers (combustionEngine.lua:1086-1105), stall timer (combustionEngine.lua:1133), rev limiter timer (combustionEngine.lua:1142), over-rev/over-torque damage accumulation (combustionEngine.lua:1148,1218), afterfire fuel delay pushes (combustionEngine.lua:1364-1367), thermal updates (combustionEngine.lua:1385), and idle AV smoothers (combustionEngine.lua:1391-1396) — all use a hardcoded 1/60s timestep regardless of the actual frame rate. This causes incorrect timing behavior at any frame rate other than 60fps.


🐛 Impossible condition prevents engine shut-off sound from ever playing (combustionEngine.lua:1116-1117)

At lines 1116-1117, the condition requires device.outputAV1 < device.idleAV * 1.1 AND device.outputAV1 > device.idleAV * 1.1 simultaneously. A value cannot be both strictly less than and strictly greater than the same number, so this condition is always false. The shut-off sound will never play. The original code used < device.idleAV * 0.95 and > device.idleAV * 0.5, which defined a valid RPM window.


🐛 Undefined variable misfireAmount causes runtime crash during flood misfires (combustionEngine.lua:3098)

The variable misfireAmount is referenced at lines 3098, 3105, and 3122 but is never defined in the enclosing scope. When a misfire occurs during engine flooding (flood level > 0.1), the code reaches string.format("Misfire! Amount: %.2f, ...", misfireAmount, ...) at line 3098, which will error because misfireAmount is nil and %.2f requires a number. Even if the log were skipped, line 3105 (if misfireAmount < 0.85) would also error comparing nil with a number. This crashes the torque update loop whenever the engine is flooded.


🐛 Operator precedence bug makes coast-down initialization dead code (combustionEngine.lua:3020)

At line 3020, the condition device.starterEngagedCoef == 0 and not device.starterEngagedCoef == 1 is parsed by Lua as (device.starterEngagedCoef == 0) and ((not device.starterEngagedCoef) == 1). Since device.starterEngagedCoef is a number (always truthy in Lua), not device.starterEngagedCoef evaluates to false, and false == 1 is always false. The entire condition is therefore always false, so coastDownRPM and coastDownTime are never initialized.

View 7 additional findings in Devin Review.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant