defmodule Robot.Links do @moduledoc """ Provide functions that import robot links """ import SweetXml import Robot.Utils import Robot.Mesh alias ELA.Matrix, as: Matrix alias ELA.Vector, as: Vector @doc """ Get base frame information in a Map TODO: develop information model for robot. ## Parameters - xmldoc: xml file readed ## Examples result = get_base_frame(xmldoc) """ @spec get_base_frame(binary()) :: Robot.Frame def get_base_frame(xmldoc) do result = xmldoc |> xpath( ~x"//library_visual_scenes/visual_scene", translates: ~x"./node/node/node[@name=\"base\"]/translate/text()"l, rotate_axis_sid: ~x"./node/node/node[@name=\"base\"]/rotate/@sid", rotates: ~x"./node/node/node[@name=\"base\"]/rotate/text()"l, ) frame = convert_to_frame(result, "base") end @doc """ Get base link information in a Map TODO: develop information model for robot. ## Parameters - xmldoc: xml file readed ## Examples result = get_base_link(xmldoc) """ @spec get_base_link(binary()) :: Robot.Link def get_base_link(xmldoc) do #result = xmldoc |> xpath( # ~x"///library_visual_scenes/visual_scene", # link_name: ~x"./node/node/@name", ## instance_geometry: ~x"./node/node/instance_geometry/@url", # translate: ~x"./node/node/translate/text()", # rotate: ~x"./node/node/rotate/text()" link_name = 'base_link' link_base_path = get_link_path(link_name) result = get_link(xmldoc, link_base_path, link_name) frame = get_base_frame(xmldoc) link_base = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ Get link_1 information and put it in a Map TODO: develop information model for robot. ## Parameters - xmldoc: xml file readed ## Examples iex> get_link_1(xmldoc) %{frame: %{frames: [%{rotate: [1.0, 0.0, 0.0, 0.0], translate: [0.0, 0.0, 0.0]}, %{rotate: [1.0, 0.0, 0.0, 0.0], translate: [0.0, 0.0, 0.227]}, %{rotate: [1.0, 0.0, 0.0, 0.0], translate: [0.0, 0.0, 0.0]}], name: 'link_1', rotate_axis: [0.0, 0.0, 1.0, 0.0], rotate_axis_sid: 'node_joint_1_axis0'}, instance_geometry: ['#gkmodel0_link_1_geom0'], link_name: 'link_1', linked_links: ['link_2', 'link_cylinder']} """ @spec get_link_1(binary()) :: Robot.Link def get_link_1(xmldoc) do link_name = 'link_1' link_1_path = get_link_path(link_name) result = get_link(xmldoc, link_1_path, link_name) frame = get_link_frame(xmldoc, link_1_path, link_name) link_1 = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ TODO: merge to get_link_n, after development of information model """ def get_link_2(xmldoc) do link_name = 'link_2' link_2_path=get_link_path(link_name) result = get_link(xmldoc, link_2_path, link_name) frame = get_link_frame(xmldoc, link_2_path, link_name) link_2 = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ TODO: merge to get_link_n, after development of information model """ def get_link_3(xmldoc) do link_name = 'link_3' link_3_path = get_link_path(link_name) result = get_link(xmldoc, link_3_path, link_name) frame = get_link_frame(xmldoc, link_3_path, link_name) link_3 = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ TODO: merge to get_link_n, after development of information model """ def get_link_4(xmldoc) do link_name = 'link_4' link_4_path = get_link_path(link_name) result = get_link(xmldoc, link_4_path, link_name) frame = get_link_frame(xmldoc, link_4_path, link_name) link_4 = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ TODO: merge to get_link_n, after development of information model """ def get_link_5(xmldoc) do link_name = 'link_5' link_5_path = get_link_path(link_name) result = get_link(xmldoc, link_5_path, link_name) frame = get_link_frame(xmldoc, link_5_path, link_name) link_5 = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ TODO: merge to get_link_n, after development of information model """ def get_link_6(xmldoc) do link_name = 'link_6' link_6_path = get_link_path(link_name) result = get_link(xmldoc, link_6_path, link_name) frame = get_link_frame(xmldoc, link_6_path, link_name) link_6 = %Robot.Link{link_name: result[:link_name], instance_geometry: result[:instance_geometry], frame: frame, linked_links: result[:linked_links]} end @doc """ Get link path based on link name TODO: develop information model for robot. ## Parameters - link: name of link ## Examples link_name = 'link_6' link_6_path = get_link_path(link_name) """ @spec get_link_path(Charlist) :: %SweetXpath{} def get_link_path(link) do link_base_name = 'base_link' link_1_name = 'link_1' link_2_name = 'link_2' link_3_name = 'link_3' link_4_name = 'link_4' link_5_name = 'link_5' link_6_name = 'link_6' link_base_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node'} link_1_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node/node'} link_2_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node/node/node[@name=\"'++link_1_name++'\"]'} link_3_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node/node/node[@name=\"'++link_1_name++'\"]/node[@name=\"'++link_2_name++'\"]'} link_4_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node/node/node[@name=\"'++link_1_name++'\"]/node[@name=\"'++link_2_name++'\"]/node[@name=\"'++link_3_name++'\"]'} link_5_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node/node/node[@name=\"'++link_1_name++'\"]/node[@name=\"'++link_2_name++'\"]/node[@name=\"'++link_3_name++'\"]/node[@name=\"'++link_4_name++'\"]'} link_6_path = %SweetXpath{path: '//library_visual_scenes/visual_scene/node/node/node[@name=\"'++link_1_name++'\"]/node[@name=\"'++link_2_name++'\"]/node[@name=\"'++link_3_name++'\"]/node[@name=\"'++link_4_name++'\"]/node[@name=\"'++link_5_name++'\"]'} link_paths = [ %{name: link_base_name, path: link_base_path}, %{name: link_1_name, path: link_1_path}, %{name: link_2_name, path: link_2_path}, %{name: link_3_name, path: link_3_path}, %{name: link_4_name, path: link_4_path}, %{name: link_5_name, path: link_5_path}, %{name: link_6_name, path: link_6_path} ] link_paths |> Enum.find(fn map -> map[:name] == link end) |> Map.fetch!(:path) end @doc """ Get link information and return a Map based on name input TODO: develop information model for robot. ## Parameters - xmldoc: xml file readed - link_path: link node path in xml - link_name: link name ## Examples link_name = 'link_6' link_6_path = get_link_path(link_name) result = get_link(xmldoc, link_6_path, link_name) """ @spec get_link(binary(), %SweetXpath{}, Charlist) :: %{link_name: Charlist, instance_geometry: List, linked_links: List} def get_link(xmldoc, link_path, link_name) do link_name_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/@name'} instance_geometry_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/instance_geometry/@url', is_list: true} linked_links_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/node/@name', is_list: true} result = xmldoc |> xpath( link_path, link_name: link_name_path, instance_geometry: instance_geometry_path, linked_links: linked_links_path ) end @doc """ Get link frames information and return a Map based on name input TODO: develop information model for robot. ## Parameters - xmldoc: xml file readed - link_path: link node path in xml - link_name: link name ## Examples link_name = 'link_6' link_6_path = get_link_path(link_name) result = get_link(xmldoc, link_6_path, link_name) """ @spec get_link_frame(binary(), %SweetXpath{}, Charlist) :: Robot.Frame def get_link_frame(xmldoc, link_path, link_name) do translates_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/translate/text()', is_list: true} rotate_axis_sid_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/rotate/@sid'} rotates_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/rotate/text()', is_list: true} result = xmldoc |> xpath( link_path, translates: instance_geometry_path = translates_path, rotate_axis_sid: rotate_axis_sid_path, rotates: rotates_path ) frame = convert_to_frame(result, link_name) end @doc """ TODO """ def get_tool_frame do end @doc """ Convert string list to float list in frame, and add name to frame ## Parameters - xmlresult: frame - name: link node path in xml ## Examples translates_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/translate/text()', is_list: true} rotate_axis_sid_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/rotate/@sid'} rotates_path = %SweetXpath{path: './node[@name=\"'++link_name++'\"]/rotate/text()', is_list: true} result = xmldoc |> xpath( link_path, translates: instance_geometry_path = translates_path, rotate_axis_sid: rotate_axis_sid_path, rotates: rotates_path ) frame = convert_to_frame(result, link_name) """ @spec convert_to_frame(binary(), Charlist) :: Robot.Frame def convert_to_frame(xmlresult,name) do [t1 | t] = xmlresult[:translates] [t2 | [t3]] = t [r1 | r] = xmlresult[:rotates] [r2 | r_] = r [r3 | [r4]] = r_ frame = %Robot.Frame{name: name, rotate_axis_sid: xmlresult[:rotate_axis_sid], frames: [%{translate: charlist_to_flist(t1), rotate: charlist_to_flist(r1)}, %{translate: charlist_to_flist(t2), rotate: charlist_to_flist(r2)}, %{translate: charlist_to_flist(t3), rotate: charlist_to_flist(r4)}], rotate_axis: charlist_to_flist(r3) } end @doc """ Convert List of Char to a List of FLoat. ## Parameters - charlist: Charlist Example: '1 2 3' ## Examples iex(6)> charlist_to_flist('1 2 3') [1.0, 2.0, 3.0] """ @spec charlist_to_flist(Charlist) :: List def charlist_to_flist(charlist) do pos_list_f = String.split(to_string(charlist)) |> Enum.map(fn s -> Float.parse(s) |> elem(0) end) end @doc """ Add meshes and transform info to robot model by using the name of the link ## Parameters - robot_model: robot model used to store mesh and tranform information - geometries: List of geometries to store geometry data - names: names of the gerometries - link: robto link - name: name of the geometry - joint_value: angle of the joint in rad ## Examples geometries = File.read!("geometries.txt") |> :erlang.binary_to_term link_base = File.read!("link_base.txt") |> :erlang.binary_to_term link_1 = File.read!("link_1.txt") |> :erlang.binary_to_term link_2 = File.read!("link_2.txt") |> :erlang.binary_to_term link_3 = File.read!("link_3.txt") |> :erlang.binary_to_term link_4 = File.read!("link_4.txt") |> :erlang.binary_to_term link_5 = File.read!("link_5.txt") |> :erlang.binary_to_term link_6 = File.read!("link_6.txt") |> :erlang.binary_to_term robot_model = %{points: [], indices: [], translates: [], rotates: []} robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_base, 'gkmodel0_base_link_geom0', 0.0) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_1, 'gkmodel0_link_1_geom0', :math.pi/6) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_2, 'gkmodel0_link_2_geom0', :math.pi/6) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_3, 'gkmodel0_link_3_geom0', :math.pi/6) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_4, 'gkmodel0_link_4_geom0', :math.pi/6) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_5, 'gkmodel0_link_5_geom0', :math.pi/6) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_6, 'gkmodel0_link_6_geom0', :math.pi/6) """ @spec add_link_to_robot_model_by_name(%{points: List, indices: List, translates: List, rotates: List}, List, List, %{link_name: Charlist, instance_geometry: List, frame: %{name: Charlist, rotate_axis_sid: Charlist, frames: List, rotate_axis: List}, linked_links: List}, Charlist, Float) :: Rbot.Mesh def add_link_to_robot_model_by_name(robot_model, geometries, names, link, name, joint_value) do index = Enum.find_index(names,fn x-> x==name end) points = robot_model.points indices = robot_model.indices translates = robot_model.translates rotates = robot_model.rotates new_points = List.insert_at(points, length(points),Enum.at(geometries,index)|>Map.fetch!(:positions)) robot_model = %{robot_model | points: new_points} new_indices = List.insert_at(indices, length(indices),Enum.at(geometries,index)|>Map.fetch!(:triangles)) robot_model = %{robot_model | indices: new_indices} tranf_temp = apply_joint(List.last(robot_model.translates),List.last(robot_model.rotates), get_trans_or_rot_from_link(link, :translate),get_trans_or_rot_from_link(link, :rotate), get_joint_from_link(link, joint_value)) new_translates = List.insert_at(translates, length(translates),tranf_temp[:trans]) robot_model = %{robot_model | translates: new_translates} new_rotates = List.insert_at(rotates, length(rotates),tranf_temp[:rot]) robot_model = %{robot_model | rotates: new_rotates} end defp get_trans_or_rot_from_link(link, key) do link|>Map.fetch!(:frame)|>Map.fetch!(:frames)|>Enum.at(1)|>Map.fetch!(key) end @doc """ Get rotaion vector based on rotation axis and input joint angle. ## Parameters - link: link - joint_value: angle of the joint in rad ## Examples get_joint_from_link(link, joint_value) """ @spec get_joint_from_link(%{link_name: Charlist, instance_geometry: List, frame: %{name: Charlist, rotate_axis_sid: Charlist, frames: List, rotate_axis: List}, linked_links: List}, Float) :: List defp get_joint_from_link(link, joint_value) do rot = link|>Map.fetch!(:frame)|>Map.fetch!(:rotate_axis) rot = List.replace_at(rot, 3,joint_value) rot end #def add_two_list(old_trans, new_trans) do # if old_trans do # trans = new_trans|> Enum.with_index |> Enum.map(fn({x, i}) -> x + Enum.at(old_trans,i) end) # else # trans = new_trans # end #end @doc """ Perform frame transformation. ## Parameters - old_trans: the first translation vector - old_rots: the first rotation axis+angle - new_trans: the secord tranlation vector - new_rots: the secord rotation axis+angle - joint_vector: the joint rotaion axis+angle """ @spec apply_joint(List, List, List, List, List) :: List def apply_joint(old_trans, old_rots, new_trans, new_rots, joint_vector) when old_trans==nil do apply_joint([0.0,0.0,0.0], [1.0,0.0,0.0,0.0], new_trans, new_rots, joint_vector) end def apply_joint(old_trans, old_rots, new_trans, new_rots, joint_vector) do old_mat = matrixFromAxisAngle(old_rots, old_trans) new_mat = matrixFromAxisAngle(new_rots, new_trans) joint_vector = matrixFromAxisAngle(joint_vector, [0.0,0.0,0.0]) mat_temp = Matrix.mult(old_mat, new_mat) axisAngleFromMatrix(Matrix.mult(mat_temp, joint_vector)) end @doc """ Generate Robot mesh based on joints ## Parameters - joints: Joints input ## Examples joints = %Robot.Joints{joint1: :math.pi/6, joint2: :math.pi/6, joint3: :math.pi/6, joint4: :math.pi/6, joint5: :math.pi/6, joint6: :math.pi/6} robot_model = get_robot_model_based_on_joint_value(joints) points = robot_model.points indices = robot_model.indices translates = robot_model.translates rotates = robot_model.rotates draw(points,indices,translates,rotates) """ @spec get_robot_model_based_on_joint_value(Robot.Joints) :: Robot.Mesh def get_robot_model_based_on_joint_value(joints) do geometries = File.read!("geometries.txt") |> :erlang.binary_to_term link_base = File.read!("link_base.txt") |> :erlang.binary_to_term link_1 = File.read!("link_1.txt") |> :erlang.binary_to_term link_2 = File.read!("link_2.txt") |> :erlang.binary_to_term link_3 = File.read!("link_3.txt") |> :erlang.binary_to_term link_4 = File.read!("link_4.txt") |> :erlang.binary_to_term link_5 = File.read!("link_5.txt") |> :erlang.binary_to_term link_6 = File.read!("link_6.txt") |> :erlang.binary_to_term robot_model = %Robot.Mesh{points: [], indices: [], translates: [], rotates: []} #points = geometries |> Enum.map(fn map -> map[:positions] end) #indices = geometries |> Enum.map(fn map -> map[:triangles] end) #translates = geometries |> Enum.map(fn map -> [:rand.uniform() * 5, :rand.uniform() * 5,:rand.uniform() * 5] end) #rotates = geometries |> Enum.map(fn map -> [:rand.uniform() * 5, :rand.uniform() * 5,:rand.uniform() * 5] end) names = geometries |> Enum.map(fn map -> map[:name] end) #draw([Enum.at(points,1)],[Enum.at(indices,1)],[[0.0,0.0,0.0]],[[0.0,0.0,0.0]]) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_base, 'gkmodel0_base_link_geom0', 0.0) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_1, 'gkmodel0_link_1_geom0', joints.joint1) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_2, 'gkmodel0_link_2_geom0', joints.joint2) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_3, 'gkmodel0_link_3_geom0', joints.joint3) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_4, 'gkmodel0_link_4_geom0', joints.joint4) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_5, 'gkmodel0_link_5_geom0', joints.joint5) robot_model = add_link_to_robot_model_by_name(robot_model, geometries, names, link_6, 'gkmodel0_link_6_geom0', joints.joint6) end end