Need Help - Using Channels from AIM SmartyCam CAN

Discussion on the Lua Scripting capabilities for RaceCapture/Pro. Also see the <a href="http://autosportlabs.net/RaceCapturePro_Lua_Scripting">Lua Scripting Guide</a>

Moderators: JeffC, stieg

Post Reply
TBracing427
Posts: 6
Joined: Sat Jun 08, 2019 9:45 pm

Need Help - Using Channels from AIM SmartyCam CAN

Post by TBracing427 »

Hello everyone,

New guy to RaceCapture and writing in Lua Script. My ChampCar team and I recently bought the Podium Connect with one of our goals to be able to calculate fuel consumption for our next race in July. After many hours I'm slowly figuring out the nuances of how to code in Lua, but I still got a lot to learn.

We have an AIM MXL2 Dash connected to the SmartyCam CAN using the AIM-RCP cable. I have been fairly successful in mapping all the channels using the presets in the CAN Mapping section with all channels I have set up working except acceleration. I'll make a separate thread about that.

The trouble I've been running into of late is actually using the channels from the SmartyCam CAN in any kind of Lua Script. I've tried directly pulling the CAN channels into my script by using the getChannel function but I couldn't get that to work. Eventually, I was able to pull the CAN channels into Lua Script by copying the code from the online example for the "old approach" https://wiki.autosportlabs.com/AIM_SmartyCam_CAN. This appeared to have worked, as an example I would see two channels with the same values for fuel pressure in the dashboard. My problem is I can't get any of my codes to work within the script using these new channels.

This is the strangest thing to me. When I wrote the code to do the fuel calculations, for testing purposes, I would set the channels I wanted to use to a fix value using the setChannel function. From that I was able to get a fully functional code and I could watch it add up the fuel on the dashboard at a rate I would expect for the values I substituted in. Great! All I need to do is use the new channels, turn on the car, and compare expected values from actual values. Except that's not what happened. As soon as I turned the car on it wouldn't work, I got nothing it didn't add anything, I could see the fuel pressure channel that I created was working but none of my other code worked. I had created a virtual channel for fuel remaining in tank which should automatically start at it's starting value and not even that would populate.

A few more hours of troubleshooting and I've stripped the code down to the most simplistic expression I could think of, take my channel and add it to itself. I couldn't get that to work either. What was happening was as soon as I flipped the power switch to the car it would stop adding but when I turned it off it would start adding again, turn the power on and it would stop adding. That blows my mind and I can't wrap my head around what's happening.

This is the stripped down code I've been trouble shooting with. I'm not sure why I can't have my own code in this script? Or if this is not the way to get the channels from the SmartyCam CAN I am all ears because I'm pulling my hair out over this. Hopefully someone can shed some light on this.



tickRate = 10
--the CAN baud rate
CAN_baud = 1000000
--CAN channel to listen on. 0=first CAN channel, 1=second
CAN_chan = 0
--1 for Big Endian (MSB) mode; 0 for Little Endian mode (LSB)
be_mode = 0

--add virtual channels here
fpressID = addChannel ("Fuel_Press", 10, 2, 0, 100, "PSI")
sumpressID = addChannel ("Sum_Press", 10, 0, 0, 1000000, "PSI")

CAN_map = {
[1058] = function(data) map_chan(fpressID, data, 0, 2, 0.14503789, 0) end,
}


function doCalc()
if x == nil then x = 1 end

x = x + getChannel(fpressID)
setChannel(sumpressID, x)

println("Sum_Press " ..x)
end


function onTick()
processCAN(CAN_chan) -- get channels from AIM dash
doCalc()
end


--===========do not edit below===========
function processCAN(chan)
repeat
local id, e, data = rxCAN(chan)
if id ~= nil then
local map = CAN_map[id]
if map ~= nil then
map(data)
end
end
until id == nil
end

--Map CAN channel, little endian format
function map_chan_le(cid, data, offset, len, mult, add)
offset = offset + 1
local value = 0
local shift = 1
while len > 0 do
value = value + (data[offset] * shift)
shift = shift * 256
offset = offset + 1
len = len - 1
end
setChannel(cid, (value * mult) + add)
end

map_chan = (be_mode == 1) and map_chan_be or map_chan_le
initCAN(CAN_chan, CAN_baud)
setTickRate(tickRate)

lightningrod
Posts: 47
Joined: Wed Oct 04, 2017 1:44 am

Post by lightningrod »

I haven't got any experience with the AIM SmartyCam but just looking at this code, I'm guessing that when the car is on you're getting a steady steam of CAN signals, which is causing it to stay in the ProcessCAN function for a long time. That function only appears to return when there is no more data on the CAN bus.

Try adding a few debug print statements to the ProcessCAN function to see if its just flooded with CAN bus data. With the code below, with the car on, I'm guessing you'll see a whole lot of "rx: id" messages and not a lot of "done" messages.

Code: Select all

function processCAN&#40;chan&#41;
    repeat
        local id, e, data = rxCAN&#40;chan&#41;
        if id ~= nil then
            local map = CAN_map&#91;id&#93;
            println&#40; "rx&#58; "..id &#41;
            if map ~= nil then
                map&#40;data&#41;
            end
        end
    until id == nil
    println&#40; "done" &#41;
end

TBracing427
Posts: 6
Joined: Sat Jun 08, 2019 9:45 pm

Post by TBracing427 »

Hmmm, that is a good point, it might be caught up in a loop driven by the CAN feed. I don't have the car near me right now, so I can't try your suggestion yet but I'll post feedback when I get a chance to try it.

So moving forward, lets say your suggestion is correct, what do I need to do to get it out of this loop?

I'm assuming it needs this loop because it's trying to find all the ID's and map them. I'm not completely sure how the can signal works, but from what I think I know it's sending a constant stream of information and the lower number ID signals pass through first followed by the next ID in queue and this continues indefinitely repeating back to the lower number ID after it has cycled through all the IDs.

As for what I might be able to do about this infinite loop is I should only have to loop it through each ID once in a given tick, no point in remapping an ID once it's been mapped. Therefore if I know how many IDs my signal is putting out I could have it count how many ID's it has mapped and once it reaches X amount it stops the loop.

Does this make any sense? Or have I made some bad assumptions.

lightningrod
Posts: 47
Joined: Wed Oct 04, 2017 1:44 am

Post by lightningrod »

It looks like the recommended way of handling this is to set the CAN channels up through the RCP app and save the configuration there.
That will offload the reading of the CAN bus data stream to the firmware rather than doing it in lua.
Then you won't need the processCAN function in your onTick function.

Code: Select all

function onTick&#40;&#41;
  doCalc&#40;&#41; 
end

TBracing427
Posts: 6
Joined: Sat Jun 08, 2019 9:45 pm

Post by TBracing427 »

I did try that at first, maybe I was doing something wrong, but I couldn't get the getChannel() function to work then. I tried putting in the channel ID like getChannel(1056) but that didn't work, nor did putting a reference value like getChannel(1) work, nor did using the channel name like getChannel("EngineSpd"). The script would load an error every time I tried.

The only time I could get the getChannel() function to work was in testing when I added my own channel to the script, like "Fuel_Press" from my example in my original post.

lightningrod
Posts: 47
Joined: Wed Oct 04, 2017 1:44 am

Post by lightningrod »

There is a step where you supply a (unique) name for your channel. I'd be surprised if you can't access it via that name.

brentp
Site Admin
Posts: 6274
Joined: Wed Jan 24, 2007 6:36 am

Post by brentp »

Hi,

You should not need to be mapping CAN channels using the "old" mapping approach.

Try choosing the PodiumConnect AIM Preset in the CAN mapping tab (make sure it's the one that includes the GPS Latitude / Longitude channels, in addition to speed so you can get correct lap times).

Then, in your lua script, you can call the "getChannel() function by specifying the name:

setTickRate(10)

val = getChannel("EngineTemp"))
if val ~= nil then
print('Got channel ' ..val)
end

Replace EngineTemp with the name of the channel you want. You need to check for nil before using the value.

Please try this out, and let us know how it goes.

Thanks,
Brent Picasso
CEO and Founder, Autosport Labs
Facebook | Twitter

TBracing427
Posts: 6
Joined: Sat Jun 08, 2019 9:45 pm

[Solved] Need Help - Using Channels from AIM SmartyCam CAN

Post by TBracing427 »

Problem solved - lightningrod had it right, the code was stuck in an infinite loop checking/mapping the CAN channels. I still needed to use the "old" mapping approach from Autosports wiki page. It was actually simpler to fix then I would have imagine, I just to change one word on one line, I needed to change out the nil for my highest CAN ID number I was using, in this case it's 1058. Since CAN always priorities lowest CAN numbers before higher ones by putting the largest CAN number I was using ensures all the data gets mapped. BTW, it turns out I can't put println statements in the CAN loop like lightningrod suggested that caused an immediate error and wouldn't load the code.



tickRate = 10
--the CAN baud rate
CAN_baud = 1000000
--CAN channel to listen on. 0=first CAN channel, 1=second
CAN_chan = 0
--1 for Big Endian (MSB) mode; 0 for Little Endian mode (LSB)
be_mode = 0

--add virtual channels here
fpressID = addChannel ("Fuel_Press", 10, 2, 0, 100, "PSI")
sumpressID = addChannel ("Sum_Press", 10, 0, 0, 1000000, "PSI")

CAN_map = {
[1058] = function(data) map_chan(fpressID, data, 0, 2, 0.14503789, 0) end,
}


function doCalc()
if x == nil then x = 1 end

x = x + getChannel(fpressID)
setChannel(sumpressID, x)

println("Sum_Press " ..x)
end


function onTick()
processCAN(CAN_chan) -- get channels from AIM dash
doCalc()
end


--===========do not edit below===========
function processCAN(chan)
repeat
local id, e, data = rxCAN(chan)
if id ~= nil then
local map = CAN_map[id]
if map ~= nil then
map(data)
end
end
until id == 1058
end

--Map CAN channel, little endian format
function map_chan_le(cid, data, offset, len, mult, add)
offset = offset + 1
local value = 0
local shift = 1
while len > 0 do
value = value + (data[offset] * shift)
shift = shift * 256
offset = offset + 1
len = len - 1
end
setChannel(cid, (value * mult) + add)
end

map_chan = (be_mode == 1) and map_chan_be or map_chan_le
initCAN(CAN_chan, CAN_baud)
setTickRate(tickRate)

lightningrod
Posts: 47
Joined: Wed Oct 04, 2017 1:44 am

Post by lightningrod »

I'm glad you got it figured out. I'm curious as what the issue is with printing from within that loop.

Post Reply