Page 1 of 1

irb360 and path planning

Posted: 14 May 2024, 07:03
by Galileo
Hello there

i have tried to integrate the simpleManipulatorPathPlanning example scene code into my irb360 code.
unfortunately, the simulation does not pass the simIK.findConfig function (its returns nil value).

i made few changes in both the irb360 original code, and the path planning code. and i'm operating the scene from Matlab.
the robot tries reaching a cuboid model through some collidable planes. for that purpose i have made all linkL objects uncollidable, as well as the centrelized motorAux extention objects (axisL)
before putting the cuboid in place, i have checked that it is reachble by using the workspace example (with few changes)

scene:
https://drive.google.com/file/d/1uP7wU6 ... sp=sharing
(Matlab code presented below)

the major changes i have made are:
1. moved the whole scene configaration into function sysCall_init, and extracting its handles to Matlab.
all variables are local, but the robotCollection of handles. and they had been packed using the custom table data functions (see at the end - structuralParameters, kinematicParameters)

Code: Select all

function sysCall_init()
        
    -- Following are the joints that we control when in FK mode:
    local fkDrivingJoints={-1,-1,-1,-1}
    fkDrivingJoints[1] = sim.getObject('./drivingJoint1')
    fkDrivingJoints[2] = sim.getObject('./drivingJoint2')
    fkDrivingJoints[3] = sim.getObject('./drivingJoint3')
    fkDrivingJoints[4] = sim.getObject('./motor')

    -- Following are the joints that we control when in IK mode:
    local ikDrivingJoints={-1,-1,-1,-1}
    ikDrivingJoints[1] = sim.getObject('./cartesianX')
    ikDrivingJoints[2] = sim.getObject('./cartesianY')
    ikDrivingJoints[3] = sim.getObject('./cartesianZ')
    ikDrivingJoints[4] = sim.getObject('./motor')
    
    -- create an IK enviorment
    ikEnv = simIK.createEnvironment()

    -- The main IK group (main task, the 3 arms and platform):
    
    -- get objects handles
    -- here the author had shooden to use the sim.getObject API function
    -- he could have used the simIK.getObjectHandle instead
    local base = sim.getObject('.')
    local ikTip = sim.getObject('./ikTip')
    local ikTarget = sim.getObject('./ikTarget')
    local loop1Tip = sim.getObject('./loopTip')
    local loop1Target=sim.getObject('./loopTarget')
    local loop2Tip=sim.getObject('./loopTip0')
    local loop2Target=sim.getObject('./loopTarget0')
    local loop3Tip=sim.getObject('./loopTip1')
    local loop3Target=sim.getObject('./loopTarget1')
    local loop4Tip=sim.getObject('./loopTip2')
    local loop4Target=sim.getObject('./loopTarget2')
    local loop5Tip=sim.getObject('./loopTip3')
    local loop5Target=sim.getObject('./loopTarget3')
    
    -- create the IK group
    -- see remarks at the CoppeliSim user manual: Funcionality->Kinematics->Solving IK and FK Tasks
    -- here, at the Delta robot, there are few kinematics chains attached together.
    -- therefore they all should be consists under the same kinematic group. 
    local ikGroup_main = simIK.createGroup(ikEnv)
    
    -- sets the calculation method 
    -- method options: simIK.method_pseudo_inverse (features a tiny bit of hard-coded damping), simIK.method_undamped_pseudo_inverse, 
    -- simIK.method_damped_least_squares and simIK.method_jacobian_transpose
    simIK.setGroupCalculation(ikEnv,ikGroup_main,simIK.method_pseudo_inverse,0,6)
    
    -- generate main IK group related IK elements
    -- simIK.addElementFromScene: is a convenient function to quickly generate an IK element from a kinematic chain in the scene
    -- at this Delta parallel robot model there are 6 kinemtics chain to be configured
    -- 1st chain: base -> tip, through right bar arm #1
    local ikElementTip = simIK.addElementFromScene(ikEnv,ikGroup_main,base,ikTip,ikTarget,simIK.constraint_position)
    -- 2nd chain: closed chain left bar arm #1
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_main,base,loop1Tip,loop1Target,simIK.constraint_pose)
    -- 3rd chain: closed chain left bar arm #2
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_main,base,loop2Tip,loop2Target,simIK.constraint_pose)
    -- 4th chain: closed chain right bar arm #2
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_main,base,loop3Tip,loop3Target,simIK.constraint_pose)
    -- 5th chain: closed chain left bar arm #3
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_main,base,loop4Tip,loop4Target,simIK.constraint_pose)
    -- 6th chain: closed chain left bar arm #3
    local ikElement, mapping = simIK.addElementFromScene(ikEnv,ikGroup_main,base,loop5Tip,loop5Target,simIK.constraint_pose)
    
    -- why/how does the last ikElement contains all DrivingJoints?
    local fkDrivingJoints_inIkEnv = {mapping[fkDrivingJoints[1]],mapping[fkDrivingJoints[2]],mapping[fkDrivingJoints[3]]}
    --local fkDrivingJoints_inIkEnv = {mapping[fkDrivingJoints[1]],mapping[fkDrivingJoints[2]],mapping[fkDrivingJoints[3]],mapping[fkDrivingJoints[4]]}
    local ikDrivingJoints_inIkEnv = {mapping[ikDrivingJoints[1]],mapping[ikDrivingJoints[2]],mapping[ikDrivingJoints[3]]}
    --local ikDrivingJoints_inIkEnv = {mapping[ikDrivingJoints[1]],mapping[ikDrivingJoints[2]],mapping[ikDrivingJoints[3]],mapping[ikDrivingJoints[4]]}
    local ikTarget_inIkEnv = mapping[ikTarget]
    local ikBase_inIkEnv = mapping[base]    
    
    -- The secondary IK group (handling the center axis):
    local axisBase = sim.getObject('./axisL')
    local axisTip = sim.getObject('./axisTip')
    local axisTarget = sim.getObject('./axisTarget')
    
    local ikGroup_axis = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_axis,simIK.method_pseudo_inverse,0,6)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_axis,axisBase,axisTip,axisTarget,simIK.constraint_pose)
    simIK.setElementPrecision(ikEnv,ikGroup_axis,ikElement,{0.0001,0.1})
    
    
    -- The IK groups handling the secondary arm bridges:
    local bridge1Base = sim.getObject('./j2')
    local bridge1Tip = sim.getObject('./bridgeLTip')
    local bridge1Target = sim.getObject('./bridgeLTarget')

    local ikGroup_bridge1 = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_bridge1,simIK.method_damped_least_squares,0.01,3)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_bridge1,bridge1Base,bridge1Tip,bridge1Target,simIK.constraint_position)
    
    -- why have the autor choosen 'j26' as base?
    local bridge2Base = sim.getObject('./j26')
    local bridge2Tip = sim.getObject('./bridgeRTip')
    local bridge2Target = sim.getObject('./bridgeRTarget')
    
    local ikGroup_bridge2 = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_bridge2,simIK.method_damped_least_squares,0.01,3)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_bridge2,bridge2Base,bridge2Tip,bridge2Target,simIK.constraint_position)
    
    -- why have the autor choosen 'j28' as base?
    local bridge3Base = sim.getObject('./j28')
    local bridge3Tip = sim.getObject('./bridgeLTip0')
    local bridge3Target = sim.getObject('./bridgeLTarget0')
    
    local ikGroup_bridge3 = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_bridge3,simIK.method_damped_least_squares,0.01,3)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_bridge3,bridge3Base,bridge3Tip,bridge3Target,simIK.constraint_position)
    
    -- why have the autor choosen 'j29' as base?
    local bridge4Base = sim.getObject('./j29')
    local bridge4Tip = sim.getObject('./bridgeRTip0')
    local bridge4Target = sim.getObject('./bridgeRTarget0')

    local ikGroup_bridge4 = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_bridge4,simIK.method_damped_least_squares,0.01,3)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_bridge4,bridge4Base,bridge4Tip,bridge4Target,simIK.constraint_position)
    
    -- why have the autor choosen 'j31' as base?
    local bridge5Base = sim.getObject('./j31')
    local bridge5Tip = sim.getObject('./bridgeLTip1')
    local bridge5Target = sim.getObject('./bridgeLTarget1')
    
    local ikGroup_bridge5 = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_bridge5,simIK.method_damped_least_squares,0.01,3)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_bridge5,bridge5Base,bridge5Tip,bridge5Target,simIK.constraint_position)

    -- why have the autor choosen 'j34' as base?
    local bridge6Base = sim.getObject('./j34')
    local bridge6Tip = sim.getObject('./bridgeRTip1')
    local bridge6Target = sim.getObject('./bridgeRTarget1')
    
    local ikGroup_bridge6 = simIK.createGroup(ikEnv)
    simIK.setGroupCalculation(ikEnv,ikGroup_bridge6,simIK.method_damped_least_squares,0.01,3)
    local ikElement = simIK.addElementFromScene(ikEnv,ikGroup_bridge6,bridge6Base,bridge6Tip,bridge6Target,simIK.constraint_position)
    

    -- Movement profiles when in FK mode:
    local angVel = 180*math.pi/180
    local angAccel = 360*math.pi/180
    local angJerk = 3600*math.pi/180
    local maxAngVel = {angVel,angVel,angVel,angVel}
    local maxAngAccel = {angAccel,angAccel,angAccel,angAccel}
    local maxAngJerk = {angJerk,angJerk,angJerk,angJerk}

    -- Movement profiles when in IK mode:
    local linVel = 2
    local linAccel = 3
    local linJerk = 30
    local maxLinVel = {linVel,linVel,linVel,angVel}
    local maxLinAccel = {linAccel,linAccel,linAccel,angAccel}
    local maxLinJerk = {linJerk,linJerk,linJerk,angJerk}
    
    local structuralParameters = {}
    structuralParameters.robotHandle = base
    structuralParameters.tipHandle = ikTip
    structuralParameters.ikMode = false
    structuralParameters.ikEnv = ikEnv
    structuralParameters.mainIkGroup = ikGroup_main
    structuralParameters.platformIkElement = ikElementTip
    structuralParameters.axisIkGroup = ikGroup_axis
    structuralParameters.bridgeIkGroups = {ikGroup_bridge1,ikGroup_bridge2,ikGroup_bridge3,ikGroup_bridge4,ikGroup_bridge5,ikGroup_bridge6}
    structuralParameters.fkDrivingJoints = fkDrivingJoints
    structuralParameters.ikDrivingJoints = ikDrivingJoints
    structuralParameters.fkDrivingJoints_inIkEnv = fkDrivingJoints_inIkEnv
    structuralParameters.ikDrivingJoints_inIkEnv = ikDrivingJoints_inIkEnv
    structuralParameters.ikTarget_inIkEnv = ikTarget_inIkEnv
    structuralParameters.ikBase_inIkEnv = ikBase_inIkEnv
    
    sim.writeCustomTableData(base, "irb360StructuralParameters", structuralParameters)
    
    local kinematicParameters = {}
    kinematicParameters.jointMaxAngVel = maxAngVel
    kinematicParameters.jointMaxAngAccel = maxAngAccel
    kinematicParameters.jointMaxAngJerk = maxAngJerk
    kinematicParameters.toolMaxLinVel = maxLinVel
    kinematicParameters.toolMaxLinAccel = maxLinAccel
    kinematicParameters.toolMaxLinJerk = maxLinJerk
    
    sim.writeCustomTableData(base, "irb360KinematicParameters", kinematicParameters)
    
    -- Create robot collection:    
    robotCollection = sim.createCollection()
    sim.addItemToCollection(robotCollection,sim.handle_tree,base,0)
    
end
2. at the path planning function "moveToConfigOMPL" i have used the irb360 'IK joints' (the X,Y,Z prismatic joints) as the joints configuration to be solved. (collisionValidation is the findConfig callback function)

Code: Select all

function collisionValidation(config,info)
    -- check if a configuration is valid, i.e. doesn't collide  
    -- save current config:
    local tmp = getConfig(info)
    
    -- apply new config:
    setConfig(config,nil,nil,info)
    
    -- does new config collide?
    local res = sim.checkCollision(robotCollection,sim.handle_all)
    
    -- restore original config:
    setConfig(tmp,nil,nil,info)
    
    return res == 0
end

function moveToConfigOMPL(goalPose,structuralParameters,kinematicParameters)
    
    setIkMode(structuralParameters)
    
    local simJointHandles = structuralParameters.ikDrivingJoints
    local useForProjection = {}
    
    for i = 1,#simJointHandles,1 do
        useForProjection[i] = i<=3 and 1 or 0
    end
    
    local ikBase = structuralParameters.ikBase_inIkEnv
    local ikTarget = structuralParameters.ikTarget_inIkEnv
    
    local ikEnv = structuralParameters.ikEnv
    local ikGroup = structuralParameters.mainIkGroup
    local ikJointHandles = structuralParameters.ikDrivingJoints_inIkEnv
    
    --setConfig(goalPose,nil,nil,structuralParameters)
    simIK.setObjectPose(ikEnv,ikTarget,goalPose,ikBase)
    
    local config = simIK.findConfig(ikEnv,ikGroup,ikJointHandles,0.65,0.1,{1,1,1,0.1},collisionValidation,structuralParameters)
    print(config)
    
    if config then
        -- found a collision-free config that matches the desired pose!
        -- Now find a collision-free path (via path planning) that brings us from current config to the found config:
        local task = simOMPL.createTask('task')
        simOMPL.setAlgorithm(task,simOMPL.Algorithm.RRTConnect)
        simOMPL.setStateSpaceForJoints(task,simJointHandles,useForProjection)
        simOMPL.setCollisionPairs(task,{robotCollection,sim.handle_all})
        simOMPL.setStartState(task,getConfig())
        simOMPL.setGoalState(task,config)
            
        -- now we could add more goal states with simOMPL.addGoalState, to increase the chance to find a collision-free path. 
        -- But we won't do it for simplicity's sake
        simOMPL.setup(task)
        local res,path = simOMPL.compute(task,4,-1,300)
        
        print(res)
        print(path)
        
        if res and path then
            -- We found a collision-free path
            -- Now move along the path in a very simple way:
            local sw = sim.setStepping(true)
            for i=1,simOMPL.getPathStateCount(task,path) do
                local conf = simOMPL.getPathState(task,path,i)
                setConfig(conf,nil,nil,structuralParameters)
                
                local msg = string.format(" path state #%.0f",i)
                msg = msg..string.format(" (@tip configurationat: %.2f)",conf)
                sim.addLog(sim.verbosity_scriptinfos,msg)
                
                sim.step()
            end
            sim.setStepping(sw)
        end
        simOMPL.destroyTask(task)
    end
    
end
3. the Matlab script

Code: Select all

%% System Initialization
disp('Program started');
% using zeroMQ remote API package
addpath ('C:\Program Files\CoppeliaRobotics\CoppeliaSimEdu\programming\zmqRemoteApi\clients\matlab')

client = RemoteAPIClient();
sim = client.require('sim');

sim.setStepping(true);

sim.startSimulation();
deltaRobot = sim.getObject("/irb360");
deltaRobotTip = sim.getObject("/ikTip");
irb360StructuralParameters = sim.readCustomTableData(deltaRobot, "irb360StructuralParameters");
irb360KinematicParameters = sim.readCustomTableData(deltaRobot, "irb360KinematicParameters");
sim.step()

while true
    
    cuboid = sim.getObject('/cuboidTarget');
    cuboidPosition = cell2mat( sim.getObjectPose(cuboid, deltaRobot) );
    sim.callScriptFunction("moveToConfigOMPL", deltaRobotScipt,...
        cuboidPosition,irb360StructuralParameters, irb360KinematicParameters)
    sim.step()
    pause(2)
        
    break

end

sim.stopSimulation();
disp('Program ended');
i hope it could be understood
cheers

Re: irb360 and path planning

Posted: 15 May 2024, 10:19
by coppelia
Hello,

that is unfortunately too much code to review for us. However take note of following few points:
  • The IRB360 robot is a PKM. As such, it doesn't work out of the box with simIK.findConfigs
  • The IRB360 robot is not redundant. Thus, for each target position, there is either 1 or 0 solution.
  • You can write a very simple equivalent for simIK.findConfigs by simply a) memorizing the current robot state (i.e. all joint positions), b) driving the robot to the desired position in e.g. n steps (i.e. gradually), c) restoring the memorized robot state.
I'd first leave collisions out of the equation, and see how things go just be taking into account the reachability of the robot. Then in a second step, consider collisions too.

Cheers

Re: irb360 and path planning

Posted: 15 May 2024, 11:21
by Galileo
got you. you are rigt, it is simple to have the requiered configuration.

can you please suggest some remarks regarding working the PKM with OMPL library?
could it be used? is there ant alternative API to work with?

cheers