Page 1 of 1

Looking for help with out of memory errors

Posted: Sun Aug 12, 2018 6:07 am
by davef_dci
Hey folks,

I am trying to implement some Shift2X stuff and my program has begun to behave weirdly. I was getting sporadic out of memory errors and I cut out some stuff - but the program will run for a while and then act up oddly which I am assuming means out of memory stuff.

I'm pretty novice at LUA and I was wondering if you had any suggestions on streamlining this to reduce memory usage.

I am running this through a minifier - so that strips out all the comments and such.

I was thinking of abandoning the Shift2X routines and simply writing to the LEDs. That would be a bummer but it seems like the Shift2X stuff is when I started to get issues.

Is there any way to determine how much memory this program will use and how close I am to running into memory errors?

Any suggestions (that sort of maintain functionality) would be really appreciated.

Code: Select all

--Udder Chaos Lua Script File 
-- Revision Log 
-- Version   Date    Description 
-- 1   April 17  Road America - first Race
-- 2   August 17 Gingerman Race
--     Removed piggy back gages
--     Added brake sensor 
--     Adding CAN bus functionalty to OBDII
--     Adding shift light sensor
--    8-15 added can Sniffer
--    brake light script
-- 3  Road America Second Race
--    added virtual channel for brakes and gears
-- 4  April 2018 Road America - First Race
--    Adding in Shift2X LED display
--    Debug of brake light delay and trying to add the CAN bus back in 
--    Remove can bus 

-- Useful Reference Stuff: - channels start at 0 (i.e. AN1 = channel 0)
--   AN1 = OIL PRESSURE
--   AN2 = TRANS TEMP
--   AN3 = OIL TEMP
--   AN4 = H20 TEMP
--   AN5 = FUEL 
--   AN6 = 02
--   AN7 = MAP
--   RPM1 = TACH
--   Shift2X is on CAN1

--   debug = true  -- flag used to turn on various rountines when debugging the program - uncomment if needed

-- Adding virtual Channels 
   fuel_damped = addChannel("Fuel_Level", 10, 1, 0,12.6,"%")  -- Fuel_damped is a virtual channel that smooths out fuel sloshing
   brake_status = addChannel("Brake_stat", 10, 0)  --- A virtual channel used to report when the brake is pressed for logging. 
   gearId = addChannel("Gear",5)  -- A virtual channel used to track which gear we are in.  

-- Fuel Anti-sloshing routine stuff 
   maxAvg = 75 --change this to make a bigger averaging window
   fuelAvg={} -- define fuelAvg as a LUA array 
   fuel_damped_Index = 1

-- Function updateFuelAverage - called by tick - smooths out fuel 
function updateFuelAvg(value)
  local i
  if #fuelAvg == 0 then
    --initialize averaging table
    for i = 1, maxAvg do fuelAvg[i]=0 end
  end
  fuelAvg[fuel_damped_Index] = value
  fuel_damped_Index = fuel_damped_Index + 1
  if fuel_damped_Index > maxAvg then fuel_damped_Index = 1 end
  local sum = 0
  for i = 1, #fuelAvg do
    sum = sum + fuelAvg[i]
  end
  setChannel(fuel_damped, sum / maxAvg)
end

-- Function check_gear updates the gear position - called every tick 
function check_gear() 
-- Constants for Gear Determination
-- Put these directly into code to save memory 
-- local _1stGear = 3.54
-- local _2ndGear = 2.13
-- local _3rdGear = 1.36
-- local _4thGear = 1.03
-- local _5thGear = .81
-- local FinalDrive = 3.94
local TireDia = 23.0  -- in inches
local gearErr = 0.1--allowable error of gear ratio to allow for measurement variation
local rpmSpeedRatio = 0
local gearPos = 0 --initialized to 0 so if it doesn't work you know
local speed = getGpsSpeed()
local rpm = getTimerRpm(0)

if speed > 10 then
    --makes sure your rolling so as not to divide by 0 
   rpmSpeedRatio = (rpm/speed)/(FinalDrive*1056/(TireDia*3.14159))
   if &#40;&#40;3.54 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 1 end
   if &#40;&#40;2.13 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 2 end
   if &#40;&#40;1.36 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 3 end
   if &#40;&#40;1.03 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 4 end
   if &#40;&#40;.81 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 5 end
else gearPos = 0 end
setChannel&#40;gearId, gearPos&#41; --outputs to virtual channel
end

-- ShiftX2 is connected to CAN1. 0=CAN1, 1=CAN2
sxCan = 0

-- 0=first ShiftX2 on bus, 1=second ShiftX2 &#40;if ADR1 jumper is cut&#41;
sxId=0

--how often ontick is updated
tickRate=10

--Brightness, 0-100. 0=automatic brightness
sxBright=0

function sxOnUpdate&#40;&#41;
  
-- To keep things simple for the driver we are not attempting to map LEDs to specific warnings or danger conditions. If ANY 
-- threshold is exceeded, the two end LEDs on the ShiftX will light up &#40;yellow for warning - red for danger&#41;.  The driver 
-- should be able to see what the specific problem is by looking at the gages.  

local warning = false  -- Boolean variable tracking warning threshold has been exceeded. 
local danger = false  -- Boolean variable tracking that danger threshold has been exceeded. 

--     Thresholds These are in here for convenience and must be updated in the code below
--                                       Warning     Danger 
--     AN1 &#40;Channel 0&#41; = OIL PRESSURE     35          20    &#40;PSI&#41;
--     AN2 &#40;Channel 1&#41; = TRANS TEMP       185         200   &#40;Degrees F&#41;
--     AN3 &#40;Channel 2&#41; = OIL TEMP         220         250   &#40;Degrees F&#41;
--     AN4 &#40;Channel 3&#41; = H20 TEMP         212         230   &#40;Degrees F&#41; 

-- Go get the readings from the analog gages for Oil pressure, Trans Temp, Oil Temp and coolant temp 
 oil_pressure = getAnalog&#40;0&#41;
 trans_temp = getAnalog&#40;1&#41;
 oil_temp = getAnalog&#40;2&#41;
 H20_temp = getAnalog&#40;3&#41;
 
 if debug then println&#40;'oilpressure = '..oil_pressure&#41; end 

 if oil_pressure < 35 then warning = true
  end
  if oil_pressure < 20 then danger=true
  end
 if trans_temp > 185 then warning=true
 end
  if trans_temp > 200 then danger=true
 end
  if oil_temp > 220 then warning=true
  end
 if oil_temp > 250 then danger=true
 end
  if H20_temp > 212 then warning=true
  end
  if H20_temp > 230 then danger=true
 end

-- If one of the warning flags has been set - set the two end LEDS &#40;7 and 8&#41; to yellow.  
  if warning  and &#40;not  danger &#41; then 
     sxSetLed&#40;8,1,255,255,0,0&#41; 
     sxSetLed&#40;7,1,255,255,0,0&#41;
-- If one of the danger flags has been set - set the two end LEDs &#40;7 and 8&#41; to red and flash them.  
   elseif danger and warning then
     sxSetLed&#40;8,1,255,0,0,0&#41; 
     sxSetLed&#40;7,1,255,0,0,0&#41;
-- Otherwise set the two end LEDs to green &#40;no warning and no danger&#41;      
   else
      sxSetLed&#40;8,1,0,255,0,0&#41; 
     sxSetLed&#40;7,1,0,255,0,0&#41;
   end
 
 -- Update the linear graph with the current RPM  
  sxUpdateLinearGraph&#40;getTimerRpm&#40;0&#41;&#41;
end

function sxOnInit&#40;&#41;
  --config shift light
  sxCfgLinearGraph&#40;0,0,0,7000&#41; --left to right graph, linear style, 0 - 7000 RPM range
  sxSetLinearThresh&#40;0,0,3000,0,255,0,0&#41; --green at 3000 RPM
  sxSetLinearThresh&#40;1,0,5800,255,255,0,0&#41; --yellow at 5800 RPM
  sxSetLinearThresh&#40;2,0,6200,255,0,0,10&#41; --red+flash at 6200 RPM
end

---ShiftX2 functions

function sxSetLed&#40;i,l,r,g,b,f&#41;
  sxTx&#40;10,&#123;i,l,r,g,b,f&#125;&#41;
end

function sxSetLinearThresh&#40;id,s,th,r,g,b,f&#41;
  sxTx&#40;41,&#123;id,s,spl&#40;th&#41;,sph&#40;th&#41;,r,g,b,f&#125;&#41;
end

function sxSetAlertThresh&#40;id,tid,th,r,g,b,f&#41;
  sxTx&#40;21,&#123;id,tid,spl&#40;th&#41;,sph&#40;th&#41;,r,g,b,f&#125;&#41;
end

function setBaseConfig&#40;bright&#41;
  sxTx&#40;3,&#123;bright&#125;&#41;
end

function sxSetAlert&#40;id,r,g,b,f&#41;
  sxTx&#40;20,&#123;id,r,g,b,f&#125;&#41;
end

function sxUpdateAlert&#40;id,v&#41;
  if v~=nil then sxTx&#40;22,&#123;id,spl&#40;v&#41;,sph&#40;v&#41;&#125;&#41; end
end

function sxCfgLinearGraph&#40;rs,ls,lr,hr&#41; 
  sxTx&#40;40,&#123;rs,ls,spl&#40;lr&#41;,sph&#40;lr&#41;,spl&#40;hr&#41;,sph&#40;hr&#41;&#125;&#41;
end

function sxUpdateLinearGraph&#40;v&#41;
  if v ~= nil then sxTx&#40;42,&#123;spl&#40;v&#41;,sph&#40;v&#41;&#125;&#41; end
end

function sxInit&#40;&#41;
  setBaseConfig&#40;sxBright&#41;
  if sxOnInit~=nil then sxOnInit&#40;&#41; end
end

function sxChkCan&#40;&#41;
  id,ext,data=rxCAN&#40;sxCan,0&#41;
  if id==sxCanId then sxInit&#40;&#41; end
  if id==sxCanId+60 and sxOnBut~=nil then sxOnBut&#40;data&#91;1&#93;&#41; end
end

function sxProcess&#40;&#41;
  sxChkCan&#40;&#41;
  if sxOnUpdate~=nil then sxOnUpdate&#40;&#41; end
end

function sxTx&#40;offset, data&#41;
  txCAN&#40;sxCan, sxCanId + offset, 1, data&#41;
  sleep&#40;10&#41;
end

function spl&#40;v&#41; return bit.band&#40;v,0xFF&#41; end
function sph&#40;v&#41; return bit.rshift&#40;bit.band&#40;v,0xFF00&#41;,8&#41; end


-- Function onTick is the main loop for the program.  
-- Ontick will call update fuel average to create a smoothed out fuel level 
function onTick&#40;&#41;
  collectgarbage&#40;&#41; -- This deletes objects in LUA that are unsuable  
  updateFuelAvg&#40;getAnalog&#40;4&#41;&#41;-- call the fuel average routine and pass it the current fuel tank reading to smooth out. 
	check_gear&#40;&#41;  -- call the routine that checks to see what gear we are in
  sxProcess&#40;&#41;  --  Process the shift-2X routines to update the LED dashboard display 
  
  -- Turn on logging anytime the speed of the car is >10mph. Otherwise stop logging.  
    if getGpsSpeed&#40;&#41; > 10 then
      startLogging&#40;&#41;
    else
      stopLogging&#40;&#41;
    end
  
  -- Check Input a and see if the brake lights have been pushed. if so, set a virtual channel to 1
  if getGpio&#40;1&#41; == 0 then 
    setChannel&#40;brake_status,0&#41;
  else
    setChannel&#40;brake_status,1&#41;
  end
end

sxCanId = 0xE3600 + &#40;256 * sxId&#41;

setTickRate&#40;tickRate&#41;
sxInit&#40;&#41;

Posted: Tue Aug 21, 2018 3:21 pm
by psfp
Why aren't you using the Alert LEDs to indicate the danger/warning status? Just trying to understand so I can create an alternative script for you.

Posted: Tue Aug 21, 2018 6:05 pm
by psfp
You may try the following script. It should do exactly the same thing as your own script (except for the Alert lights).

Please note you don't need the "brake status" channel, as it was the same thing as the Gpio(1) input, which is already logged anyway. You can just rename the Gpio channel in GUI (RCP APP).

If it works and crashes at some point, it's probably something else than a memory problem. If it doesn't work at all, I will re-check it.

Code: Select all

sleep&#40;5000&#41;
setTickRate&#40;10&#41;

--Variables
local maxAvg, fuelAvg, fuel_damped_Index, RPM = 75, &#123;&#125;, 1, 0


--Channels
local fuel_damped, gearId


fuel_damped = addChannel&#40;"Fuel_Level", 10, 1, 0,12.6,"%"&#41;
gearId = addChannel&#40;"Gear",5&#41;

--ShiftX2 txCAN function

local function sxTx&#40;offset, data&#41;
    txCAN&#40;0, 0xE3600 + offset, 1, data&#41;
    sleep&#40;10&#41;
end


--Fuel average function

local function updateFuelAvg&#40;value&#41;
    local sum, i = 0
    if #fuelAvg == 0 then
        --initialize averaging table
        for i = 1, maxAvg do fuelAvg&#91;i&#93;=0 end
    end
    fuelAvg&#91;fuel_damped_Index&#93; = value
    fuel_damped_Index = fuel_damped_Index + 1
    if fuel_damped_Index > maxAvg then fuel_damped_Index = 1 end
    for i = 1, #fuelAvg do
        sum = sum + fuelAvg&#91;i&#93;
    end
    setChannel&#40;fuel_damped, sum / maxAvg&#41;
end


-- Function check_gear updates the gear position - called every tick

local function check_gear&#40;&#41;

    local TireDia, gearErr, rpmSpeedRatio, gearPos, speed = 23, 0.1, 0, 0, getGpsSpeed&#40;&#41;

    if speed > 10 then
        --makes sure your rolling so as not to divide by 0
        rpmSpeedRatio = &#40;RPM/speed&#41;/&#40;3.94*1056/&#40;TireDia*3.14159&#41;&#41;
        if &#40;&#40;3.54 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 1 end
        if &#40;&#40;2.13 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 2 end
        if &#40;&#40;1.36 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 3 end
        if &#40;&#40;1.03 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 4 end
        if &#40;&#40;0.81 - rpmSpeedRatio&#41;^2&#41; < &#40;gearErr^2&#41; then gearPos = 5 end
    else gearPos = 0 end
    setChannel&#40;gearId, gearPos&#41; --outputs to virtual channel
end




local function ShiftX2&#40;&#41;

    --     Thresholds These are in here for convenience and must be updated in the code below
    --                                       Warning     Danger
    --     AN1 &#40;Channel 0&#41; = OIL PRESSURE     35          20    &#40;PSI&#41;
    --     AN2 &#40;Channel 1&#41; = TRANS TEMP       185         200   &#40;Degrees F&#41;
    --     AN3 &#40;Channel 2&#41; = OIL TEMP         220         250   &#40;Degrees F&#41;
    --     AN4 &#40;Channel 3&#41; = H20 TEMP         212         230   &#40;Degrees F&#41;

    -- Go get the readings from the analog gages for Oil pressure, Trans Temp, Oil Temp and coolant temp

    local Alert, oil_pressure, trans_temp, oil_temp, H20_temp, RPM_H, RPM_L = 1, getAnalog&#40;0&#41;, getAnalog&#40;1&#41;, getAnalog&#40;2&#41;, getAnalog&#40;3&#41;

    -- Alert variable -> 1 = No problem; 2 = Warning; 3 = danger

    if &#40;oil_pressure < 35 or trans_temp > 185 or oil_temp > 220 or H20_temp > 212&#41; then Alert = 2 end
    if &#40;oil_pressure < 20 or trans_temp > 200 or oil_temp > 250 or H20_temp > 230&#41; then Alert = 3 end

    sxTx&#40;22,&#123;0,Alert,0&#125;&#41;
    sxTx&#40;22,&#123;1,Alert,0&#125;&#41;

    -- Update the linear graph with the current RPM

    RPM_L = RPM%256
    RPM_H = math.floor&#40;RPM/256&#41;
    sxTx&#40;42, &#123;RPM_L,RPM_H&#125;&#41;

end

--config shift light
sxTx&#40;40,&#123;0,0,0,0,88,27&#125;&#41; -- RPM range -> 0 to 7000 &#40;27*256 + 88&#41;
sxTx&#40;41,&#123;0,0,184,11,0,255,0,0&#125;&#41; -- green at 3000 &#40;11*256 + 184&#41;
sxTx&#40;41,&#123;0,0,168,22,255,255,0,0&#125;&#41; -- yellow at 5800 &#40;22*256 + 168&#41;
sxTx&#40;41,&#123;0,0,56,24,255,0,0,10&#125;&#41; -- red+flash 6200 &#40;24*256 + 56&#41;

--config Alert Lights
sxTx&#40;21,&#123;0,0,1,0,0,255,0,0&#125;&#41; -- Green
sxTx&#40;21,&#123;0,1,2,0,255,255,0,0&#125;&#41; -- Yellow
sxTx&#40;21,&#123;0,2,3,0,255,0,0,10&#125;&#41; -- Flashing red

sxTx&#40;21,&#123;1,0,1,0,0,255,0,0&#125;&#41; -- Green
sxTx&#40;21,&#123;1,1,2,0,255,255,0,0&#125;&#41; -- Yellow
sxTx&#40;21,&#123;1,2,3,0,255,0,0,10&#125;&#41; -- Flashing red



-- Function onTick is the main loop for the program.
-- Ontick will call update fuel average to create a smoothed out fuel level

function onTick&#40;&#41;

    collectgarbage&#40;&#41; -- This deletes objects in LUA that are unsuable

    updateFuelAvg&#40;getAnalog&#40;4&#41;&#41;-- call the fuel average routine and pass it the current fuel tank reading to smooth out.

    RPM = getTimerRpm&#40;0&#41;

    check_gear&#40;&#41;  -- call the routine that checks to see what gear we are in

    ShiftX2&#40;&#41;  --  Process the shift-2X routines to update the LED dashboard display

    -- Turn on logging anytime the speed of the car is >10mph. Otherwise stop logging.

    if getGpsSpeed&#40;&#41; > 10 then
        startLogging&#40;&#41;
    else
        stopLogging&#40;&#41;
    end

end



Looking for help with out of memory errors

Posted: Mon Sep 03, 2018 12:55 pm
by davef_dci
Paulo,

Thanks for your response. I originally started using the ShifX2 Alert routines but I quickly began to run into memory errors (the program would run for a brief period of time and then go into Disco Light mode).

I tried simply turning on the end LEDS manually in the event of a warning/danger and then used the center LEDs for the RPM indicator. My intent was to eventually eliminate the various Shift2X routines that I wasn't using to try to save memory. Someone else on here was suggesting that.

We LOVE the Shift2X - it's completely changed the way we drive. Basically our implementation of it is drop-dead simple - we only use the center LEDs for the RPM gage and simply light up the LEDs on the end if any of the gages we are tracking go into warning or danger mode. In this way, during a race, the driver only has to look at the Shift2X. If the end LEDs go yellow or begin blinking red he can then turn to the Android tablet and see which gage is of concern.

It's made driving much simpler and the driver can focus on driving without having to worry about constantly checking gages. We had a few instances of drivers missing overheating transmission temps just because they were so focused on driving. With the Shift2X that hasn't been an issue. The problem is that when we added in the Shift2X we almost immediately began to get our of memory errors.

So far we've been able to solve the errors by eliminating the gear and brake checking which is a shame because we'd like to log this for telemetry.

It seems like the canned routines for the Shift2X take tremendous amounts of memory - based on what others have said I don't think we're the only ones with this issue.

I can try your routine - but again I think the problem is an out-of-memory one. The program will run fine for a short period of time and then I get disco lights.

If Brent is monitoring this -

- Is my assumption that our problem is the size of the included Shift2X routines or something else?
- Is there any way to strip down this size of these routines?
- Is there any way to check and see how much memory your program is consuming and what the limit of LUA is so you definitively know if you have a problem before starting a race?

Sorry if my approach and questions are dumb - I'm not very good at LUA or programming.

Again - we think the Shift2X is an awesome product - one of the best investments we've made as it really allows the driver to focus on driving and not on the gages. But right now it comes at the expense of some of the other telemetry we'd live to log which is a shame.

Dave

Posted: Mon Sep 03, 2018 2:05 pm
by psfp
Yes, you can see I reduced the number of ShiftX2 scripts from 15 (or so) to only 1 (kept sxTx). This way you shouldn't have any memory issues. Believe me, my personal script is much bigger and more complex and I don't have issues even when I run RCP continuously for hours. If the script runs (I didn't test it) and you have problems after some time, it must be something else, like a script error when a variable doesn't receive the expected data type (for exemple, it receives "null" and there is another operation that will only work with numbers).