BehaviorTree.CPP icon indicating copy to clipboard operation
BehaviorTree.CPP copied to clipboard

XML content

Open galou opened this issue 2 years ago • 2 comments

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?

galou avatar Nov 01 '23 12:11 galou

I am certainly intrigued and want to know more. It would be great if you can show a motivating example

facontidavide avatar Nov 01 '23 14:11 facontidavide

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))

galou avatar Nov 02 '23 11:11 galou