PROBLEM DESCRIPTION
The following code is a minimal example that replicates a problem I am having. The rFSM library is used, which can be found here: https://github.com/kmarkus/rFSM
There are three lua scripts. The "main", called runscript.lua
, which initializes and runs the state machine (SM) that needs to be run, called mainTask.lua
, which in turn, uses an auxiliary state machine subTask.lua
.
The code flow is the following. We start inside the state machine mainTask.lua
and immediately enter the Sim
composite state, and then the state evaluate
. There, we are calling the function evaluateData
which is inside subTask.lua
and set the local variable var
to false
. After this function call, we go to mainTask.lua
again, make a transition and end up inside subTask.lua
again. There we print the value of var
.
Again, schematically: mainTask.lua
-> subTask.lua
-> mainTask.lua
-> subTask.lua
.
We expect the value of var
to be false
. However, as you can see, inside mainTask.lua
, we are loading the subTask.lua
twice via rfsm.load("subTask.lua"),
. This results in having two instances of the auxiliary SM, but I want to have one instead.
The rfsm.load
function is
function load(file)
local fsm = dofile(file)
if not is_state(fsm) then
error("rfsm.load: no valid rfsm in file '" .. tostring(file) .. "' found.")
end
return fsm
end
CODE
runscript.lua
-- Set lua path to location of rFSM library
package.path = "/home/anfr/rFSM-master/?.lua;./?.lua";
require 'rfsm';
print('[runscript.lua] Before rfsm.load("mainTask.lua")')
fsm_ = rfsm.load("mainTask.lua")
print('[runscript.lua] Before rfsm.init(fsm_)')
fsm = rfsm.init(fsm_);
print('[runscript.lua] Before rfsm.run(fsm)')
rfsm.run(fsm);
mainTask.lua
local var = true;
return rfsm.state{
Sim = rfsm.composite_state
{
evaluate = rfsm.state {
entry=function()
var = false;
if (evaluateData(var)) then
rfsm.send_events(fsm, "internal_EvaluateDone")
end
end,
},
sub = rfsm.load("subTask.lua"),
rfsm.trans {
src='initial',
tgt='evaluate',
effect=function()
print('[mainTask.lua] initial -> evaluate')
end,
},
rfsm.trans {
src='evaluate',
tgt='sub',
events={'internal_EvaluateDone'},
effect=function()
print('[mainTask.lua] evaluate -> sub with event "internal_EvaluateDone"')
end,
},
}, -- end of Sim
Seq = rfsm.composite_state
{
entry=function()
print('Entry Seq')
end,
exit=function()
print('Exit Seq')
end,
Running = rfsm.composite_state
{
entry=function()
print('Entry Running')
end,
exit=function()
print('Exit Running')
end,
--sub_2 = sub,
sub_2 = rfsm.load("subTask.lua"),
rfsm.trans {
src='initial',
tgt='sub_2',
effect=function()
print('[Seq composite state] initial -> sub_2')
end,
},
},
rfsm.trans {
src='initial',
tgt='Running',
effect=function()
print('[Seq composite state] initial -> Running')
end,
},
}, -- end of Seq
rfsm.trans {
src='initial',
tgt='Sim',
effect=function()
print('[mainTask.lua] initial -> Sim')
end,
},
};
subTask.lua
print("--- start of subTask.lua ---")
local var = true;
function evaluateData(value)
print("[subTask.lua] var before setting in evaluateData is " .. tostring(var));
var = value;
print("[subTask.lua] var after setting in evaluateData is " .. tostring(var))
return true
end
return rfsm.state {
execute = rfsm.state {
entry=function()
print('[subTask.lua] var inside execute is ' .. tostring(var))
end,
},
rfsm.trans {
src='initial',
tgt='execute',
effect=function()
print('[subTask.lua] initial -> execute')
end,
},
},
print("--- end of subTask.lua ---")
LOGS
The following logs show that the second time we enter the auxiliary SM, we use the second instance where the value of var
is true
(we don't want this).
[runscript.lua] Before rfsm.load("mainTask.lua")
--- start of subTask.lua ---
--- end of subTask.lua ---
--- start of subTask.lua ---
--- end of subTask.lua ---
[runscript.lua] Before rfsm.init(fsm_)
[runscript.lua] Before rfsm.run(fsm)
[mainTask.lua] initial -> Sim
[mainTask.lua] initial -> evaluate
[subTask.lua] var before setting in evaluateData is true
[subTask.lua] var after setting in evaluateData is false
[mainTask.lua] evaluate -> sub with event "internal_EvaluateDone"
[subTask.lua] initial -> execute
[subTask.lua] var inside execute is true
ATTEMPTS FOR A SOLUTION
Attempt 1
This attempt actually works in my local example (not the real system) and uses the commented line
sub_2 = sub
. So the idea was to to load the state machine once, and here simply refer to that. I am wondering if the different versions of LUA have an impact on this. Locally I have Lua 5.2, on system Lua 5.1.
Edit
This attempt stops working if I simply add another dummy state inside the Seq
composite state. Also there is no dependence on Lua versions.
Attempt 2
Implement a second version of load
and use require
instead of dofile
. Then use this function in those two places inside mainTask.lua
.
function load2(file)
local fileWithoutExtension = file:gsub("%.lua", "")
print(fileWithoutExtension)
local fsm = require(fileWithoutExtension)
if not is_state(fsm) then
error("rfsm.load: no valid rfsm in file '" .. tostring(file) .. "' found.")
end
return fsm
end
If I run this I get:
[runscript.lua] Before rfsm.load("mainTask.lua")
subTask
--- start of subTask.lua ---
--- end of subTask.lua ---
subTask
[runscript.lua] Before rfsm.init(fsm_)
lua: /home/anfr/rFSM-master/rfsm.lua:483: bad argument #1 to 'find' (string expected, got table)
stack traceback:
[C]: in function 'find'
/home/anfr/rFSM-master/rfsm.lua:483: in function '__resolve_path'
/home/anfr/rFSM-master/rfsm.lua:511: in function '__resolve_src'
/home/anfr/rFSM-master/rfsm.lua:551: in function 'func'
/home/anfr/rFSM-master/rfsm.lua:272: in function 'f'
/home/anfr/rFSM-master/utils.lua:246: in function 'map'
/home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
/home/anfr/rFSM-master/rfsm.lua:275: in function 'f'
/home/anfr/rFSM-master/utils.lua:246: in function 'map'
/home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
/home/anfr/rFSM-master/rfsm.lua:275: in function 'f'
/home/anfr/rFSM-master/utils.lua:246: in function 'map'
/home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
/home/anfr/rFSM-master/rfsm.lua:283: in function 'mapfsm'
/home/anfr/rFSM-master/rfsm.lua:554: in function 'resolve_trans'
/home/anfr/rFSM-master/rfsm.lua:704: in function 'init'
runscript.lua:9: in main chunk
[C]: in ?
I don't understand why I get a table instead of a string. Unfortunately one needs to navigate in the rFSM lib code to help, but I would appreciate any hints.
Ps: Making the variable var
global inside subTask.lua
will give the correct behaviour. However I am trying to avoid the unnecessary overhead of loading the same script two times.