XML content
I implemented Lua Scripting for BehaviorTree.CPP (details on this below) that uses XML content rather than an input port to allow for multi-line scripts in a nicer fashion. I needed to add support for XML content. Feel free to cherry-pick if interested.
The Lua scripting is a really nice thing. I can access fields of a structure for example. Non-existing variables are queried from the blackboard and I can write back any supported type to the blackboard. I wrote the bindings for the few types that I need (ROS messages) and this lack of generality is the reason why I have these nodes in a separate repo. Would you be interested in this work? Before adding this to the upstream repo, we would need a mean to allow the user to define the Lua bindings for his own types and functions. What would be your preferred way to do it?
I am certainly intrigued and want to know more. It would be great if you can show a motivating example
A working example of BT xml:
<root main_tree_to_execute="Test" BTCPP_format="4">
<BehaviorTree ID="Test">
<Sequence>
<Log severity="info" message="Behavior tree test_lua_script" />
<LuaScript>
<![CDATA[
-- multi-line script
info('Lua script on multiple lines')
warn('Testing `warn`')
error('Testing `error`')
info('(2 < 3)?: ' .. tostring(2 < 3))
]]>
</LuaScript>
<LuaFile uri="package://brick_layer/bt_tests/script.lua" />
</Sequence>
</BehaviorTree>
</root>
and the accompanying script.lua:
print("script.lua")
-- Create a PoseStamped message.
p = geometry_msgs.msg.PoseStamped.new()
p.pose.position.x = 123456
print("p.pose.position.x = " .. p.pose.position.x)
-- Get values from the blackboard.
print("const_PALETTE_POSITIVE_PADDING = " .. (const_PALETTE_POSITIVE_PADDING or "nil")) -- x is defined.
print("y = " .. (y or "nil")) -- y is not defined.
print("brick_in_l1_pose.pose.position.x = " .. (brick_in_l1_pose.pose.position.x or "nil"))
-- Save values to the blackboard.
to_blackboard("p", p)
-- Copy a PoseStamped and modify a value to check indepedency.
copy_of_brick_in_l1_pose = brick_in_l1_pose
copy_of_brick_in_l1_pose.pose.position.x = 654321
to_blackboard("copy_of_brick_in_l1_pose", copy_of_brick_in_l1_pose)
-- Test the read- and write accessors to the blackboard through the `B` table.
if (B.brick_in_p1_pose == nil) then
print("B.brick_in_p1_pose is nil")
else
print("B.brick_in_p1_pose.position.x = " .. B.brick_in_p1_pose.pose.position.x)
end
B.copy_of_brick_in_p1_pose = B.brick_in_p1_pose
-- To test translated_pose and rotated_pose.
local function close(a, b)
return math.abs(a - b) < 1e-6
end
-- Test translated_pose (C++ translatedPose).
p0 = geometry_msgs.msg.PoseStamped.new()
p0.pose.position.x = 1
p0.pose.position.y = 2
p0.pose.position.z = 3
p0.pose.orientation.x = 0.1618485433953521
p0.pose.orientation.y = 0.35910145565843743
p0.pose.orientation.z = -0.3186393198095994
p0.pose.orientation.w = 0.862160180834205
offset = geometry_msgs.msg.Point.new()
offset.x = 0.1
offset.y = 0.2
offset.z = 0.3
p1 = translated_pose(p0, offset.x, offset.y, offset.z)
p1_ok = (close(p1.pose.position.x, 1.3418572978311953)
and close(p1.pose.position.y, 1.95321206812806)
and close(p1.pose.position.z, 3.144722069328421)
and close(p1.pose.orientation.x, p0.pose.orientation.x)
and close(p1.pose.orientation.y, p0.pose.orientation.y)
and close(p1.pose.orientation.z, p0.pose.orientation.z)
and close(p1.pose.orientation.w, p0.pose.orientation.w))
print("p1 ok: " .. tostring(p1_ok))
p2 = translated_pose(p0, offset)
p2_ok = (close(p2.pose.position.x, 1.3418572978311953)
and close(p2.pose.position.y, 1.95321206812806)
and close(p2.pose.position.z, 3.144722069328421)
and close(p2.pose.orientation.x, p0.pose.orientation.x)
and close(p2.pose.orientation.y, p0.pose.orientation.y)
and close(p2.pose.orientation.z, p0.pose.orientation.z)
and close(p2.pose.orientation.w, p0.pose.orientation.w))
print("p2 ok: " .. tostring(p2_ok))
-- Test rotated_pose (C++ rotatedPose).
rotation = geometry_msgs.msg.Quaternion.new()
rotation.x = 0.19012781918757307
rotation.y = 0.3726484369487944
rotation.z = 0.3597140900688151
rotation.w = 0.834020580211641
p3 = rotated_pose(p0, rotation.x, rotation.y, rotation.z, rotation.w)
p3_ok = (close(p3.pose.position.x, p0.pose.position.x)
and close(p3.pose.position.y, p0.pose.position.y)
and close(p3.pose.position.z, p0.pose.position.z)
and close(p3.pose.orientation.x, 0.5468199488834077)
and close(p3.pose.orientation.y, 0.5019792476912184)
and close(p3.pose.orientation.z, 0.03641684464379197)
and close(p3.pose.orientation.w, 0.6690878804885766))
print("p3 ok: " .. tostring(p3_ok))
p4 = rotated_pose(p0, rotation)
p4_ok = (close(p4.pose.position.x, p0.pose.position.x)
and close(p4.pose.position.y, p0.pose.position.y)
and close(p4.pose.position.z, p0.pose.position.z)
and close(p4.pose.orientation.x, 0.5468199488834077)
and close(p4.pose.orientation.y, 0.5019792476912184)
and close(p4.pose.orientation.z, 0.03641684464379197)
and close(p4.pose.orientation.w, 0.6690878804885766))
print("p4 ok: " .. tostring(p4_ok))