diff --git a/7_Demo_youBotPickAndPlace/.gitignore b/7_Demo_youBotPickAndPlace/.gitignore
new file mode 100644
index 0000000..ed8ebf5
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/.gitignore
@@ -0,0 +1 @@
+__pycache__
\ No newline at end of file
diff --git a/7_Demo_youBotPickAndPlace/README.assets/GripperParams.png b/7_Demo_youBotPickAndPlace/README.assets/GripperParams.png
new file mode 100644
index 0000000..751894b
Binary files /dev/null and b/7_Demo_youBotPickAndPlace/README.assets/GripperParams.png differ
diff --git a/7_Demo_youBotPickAndPlace/README.assets/YoubotTopView.png b/7_Demo_youBotPickAndPlace/README.assets/YoubotTopView.png
new file mode 100644
index 0000000..e969e31
Binary files /dev/null and b/7_Demo_youBotPickAndPlace/README.assets/YoubotTopView.png differ
diff --git a/7_Demo_youBotPickAndPlace/README.assets/youBotParams.png b/7_Demo_youBotPickAndPlace/README.assets/youBotParams.png
new file mode 100644
index 0000000..d2fe29d
Binary files /dev/null and b/7_Demo_youBotPickAndPlace/README.assets/youBotParams.png differ
diff --git a/7_Demo_youBotPickAndPlace/README.md b/7_Demo_youBotPickAndPlace/README.md
new file mode 100644
index 0000000..282f427
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/README.md
@@ -0,0 +1,45 @@
+# 说明
+
+---
+
+在使用此源代码的时候,建议读者配合对应的文章教程进行阅读。文章链接详见知乎专栏“AI与机器人”或者微信公众号“博士的沙漏”中的第八期自学笔记。
+
+本项目参考了美国西北大学的Kevin M. Lynch教授和韩国首尔国立大学的Frank C. Park教授共同编撰的《Modern Robotics: Mechanics, Planning and Control》一书,强烈建议有兴趣的读者阅读此书。
+
+TrajectoryGenerator生成的reference trajectory一共有13个变量,分别表示
+
+| 编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
+| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :-----------: |
+| 数值 | phi | x | y | J1 | J2 | J3 | J4 | J5 | w1 | w2 | w3 | w4 | gripper state |
+
+其中,
+
+- x、 y、phi 分别表示World_X_Joint、World_Y_Joint、World_Th_Joint的坐标和偏转角度;
+- J1, $\dots$, J5 分别表示youBot的机械臂上的5个关节角度;
+- w1,$\dots$, w4分别表示front left, front right, rail right, rail left四个轮子的位置(旋转角度),如下图所示;
+- gripper state即表示gripper的状态,0表示打开,1表示闭合。
+
+注意:x、y 的单位是米,phi、J1~J5, w1~w4等角度的单位是弧度。控制Gripper的打开和闭合过程至少需要0.625秒,所以为了保证Gripper能正常完成Open/Close的动作,在编写程序控制Gripper从打开到闭合(或从闭合到打开),确保要在该位置保持0.625秒以上。
+
+youBot地盘上四个轮子的编号如图所示:
+
+
+
+分别对应w1、w2、w3、w4四个轮子旋转的角度。
+
+在VREP中,youBot模型机械臂的基本尺寸参数如图所示:
+
+
+
+对于抓手(Gripper)来说,其尺寸参数如图所示:
+
+
+
+其中:
+$$
+d_{1, min} = 2 \ cm\\
+d_{1, max} = 7 \ cm\\
+d_2 = 3.5 \ cm\\
+d_3 = 4.3 \ cm
+$$
+对于底盘来说,前后轮之间的距离是0.47m,左右轮之间的距离是0.3m,轮子的半径为0.0475m。
diff --git a/7_Demo_youBotPickAndPlace/code/FeedbackControl.py b/7_Demo_youBotPickAndPlace/code/FeedbackControl.py
new file mode 100644
index 0000000..ee5f701
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/FeedbackControl.py
@@ -0,0 +1,81 @@
+import numpy as np
+import modern_robotics as mr
+from JointLimits import jointLimits
+
+def feedbackControl(config, Xd, Xd_next, Kp, Ki, dt, jointlimit):
+ # here we compute X
+ M = np.array([[1,0,0,0.033],[0,1,0,0],[0,0,1,0.6546],[0,0,0,1]])
+ Blist = np.array([[0,0,1,0,0.033,0],[0,-1,0,-0.5076,0,0],[0,-1,0,-0.3526,0,0],[0,-1,0,-0.2176,0,0],[0,0,1,0,0,0]]).T
+ Tb0 = np.array([[1,0,0,0.1662],[0,1,0,0],[0,0,1,0.0026],[0,0,0,1]])
+ thetalist_initial = np.array([config[0,3],config[0,4],config[0,5],config[0,6],config[0,7]])
+ T_sb_initial = np.array([[np.cos(config[0,0]),-np.sin(config[0,0]),0,config[0,1]],[np.sin(config[0,0]),np.cos(config[0,0]),0,config[0,2]],[0,0,1,0.0963],[0,0,0,1]])
+ X = T_sb_initial.dot(Tb0).dot(mr.FKinBody(M,Blist,thetalist_initial))
+
+ # here we write down Vd
+ Vd = mr.se3ToVec((1/dt)*mr.MatrixLog6(np.linalg.inv(Xd).dot(Xd_next)))
+
+ # here we write down Vb = Ad*Vd
+ Vb = mr.Adjoint(np.linalg.inv(X).dot(Xd)).dot(Vd)
+
+ # here we write down X_err
+ X_err = mr.se3ToVec(mr.MatrixLog6(np.linalg.inv(X).dot(Xd)))
+
+ # here we write down commanded twist
+ V = Vb+Kp*X_err+Ki*(X_err+X_err*dt)
+
+ # here we compute J_e
+ # first we write down J_arm
+ Blist = np.array([[0,0,1,0,0.033,0],[0,-1,0,-0.5076,0,0],[0,-1,0,-0.3526,0,0],[0,-1,0,-0.2176,0,0],[0,0,1,0,0,0]]).T
+ thetalist = np.array([config[0,3],config[0,4],config[0,5],config[0,6],config[0,7]])
+ J_arm = mr.JacobianBody(Blist,thetalist)
+ # second we write down J_base
+ r = 0.0475
+ l = 0.47/2
+ w = 0.3/2
+ gamma1 = -np.pi/4
+ gamma2 = np.pi/4
+ gamma3 = -np.pi/4
+ gamma4 = np.pi/4
+ beta = 0
+ x1 = l
+ y1 = w
+ x2 = l
+ y2 = -w
+ x3 = -l
+ y3 = -w
+ x4 = -l
+ y4 = w
+ # here we write down F6
+ a1 = np.array([1,np.tan(gamma1)])
+ a2 = np.array([1,np.tan(gamma2)])
+ a3 = np.array([1,np.tan(gamma3)])
+ a4 = np.array([1,np.tan(gamma4)])
+ b = np.array([[np.cos(beta),np.sin(beta)],[-np.sin(beta),np.cos(beta)]])
+ c1 = np.array([[-y1,1,0],[x1,0,1]])
+ c2 = np.array([[-y2,1,0],[x2,0,1]])
+ c3 = np.array([[-y3,1,0],[x3,0,1]])
+ c4 = np.array([[-y4,1,0],[x4,0,1]])
+ h1 = (((1/r)*a1).dot(b)).dot(c1)
+ h2 = (((1/r)*a2).dot(b)).dot(c2)
+ h3 = (((1/r)*a3).dot(b)).dot(c3)
+ h4 = (((1/r)*a4).dot(b)).dot(c4)
+ H0 = np.vstack((h1,h2,h3,h4))
+ F = np.linalg.pinv(H0)
+ F6 = np.array([[0,0,0,0],[0,0,0,0],[F[0,0],F[0,1],F[0,2],F[0,3]],[F[1,0],F[1,1],F[1,2],F[1,3]],[F[2,0],F[2,1],F[2,2],F[2,3]],[0,0,0,0]])
+
+ # then write down J_base
+ T_sb = np.array([[np.cos(config[0,0]),-np.sin(config[0,0]),0,config[0,1]],[np.sin(config[0,0]),np.cos(config[0,0]),0,config[0,2]],[0,0,1,0.0963],[0,0,0,1]])
+ T_eb = np.linalg.inv(X).dot(T_sb)
+ J_base = mr.Adjoint(T_eb).dot(F6)
+
+ # here we test joint limits
+ if jointlimit == 1:
+ jointLimits(config,J_arm)
+
+ # finally we write down J_e
+ J_e = np.hstack((J_base,J_arm))
+
+ # here we write down speeds (u,thetadot)
+ speeds = np.linalg.pinv(J_e,rcond=1e-2).dot(V)
+
+ return V, speeds, X_err
\ No newline at end of file
diff --git a/7_Demo_youBotPickAndPlace/code/JointLimits.py b/7_Demo_youBotPickAndPlace/code/JointLimits.py
new file mode 100644
index 0000000..ea3de2a
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/JointLimits.py
@@ -0,0 +1,8 @@
+import numpy as np
+
+def jointLimits(config,J_arm):
+ if config[0,5] > -0.1:
+ J_arm[:,2] = np.array([0,0,0,0,0,0])
+ if config[0,6] > -0.1:
+ J_arm[:,3] = np.array([0,0,0,0,0,0])
+
\ No newline at end of file
diff --git a/7_Demo_youBotPickAndPlace/code/NextState.py b/7_Demo_youBotPickAndPlace/code/NextState.py
new file mode 100644
index 0000000..b3b2b8c
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/NextState.py
@@ -0,0 +1,42 @@
+import numpy as np
+
+def nextState(config,speed,delta_t,speed_max):
+ # here we limit speed
+ for j in np.arange(np.shape(speed)[1]):
+ if speed[0,j]>speed_max:
+ speed[0,j] = speed_max
+ elif speed[0,j]<-speed_max:
+ speed[0,j] = -speed_max
+
+ # here we get the new arm and wheels configurations
+ new_angle_config = config[0,3:12]+speed*delta_t
+
+ # here we start to compute the configuration of chassis using odometry
+ # step1: compute delta theta, which is the change of wheels rotation
+ delta_theta = (speed[0,5:].reshape(1,4)).T*delta_t
+
+ # step2: compute the wheels velocities
+ theta_dot = delta_theta
+
+ # step3: compute chassis planar twist Vb
+ # here we write down some necessary parameters for step3
+ r = 0.0475
+ l = 0.47/2
+ w = 0.3/2
+ Vb = (r/4)*np.array([[-1/(l+w),1/(l+w),1/(l+w),-1/(l+w)],[1,1,1,1],[-1,1,-1,1]]).dot(theta_dot)
+
+ # step4: calculate new chassis config
+ # here we write down dqb
+ if Vb[0,0] == 0:
+ dqb = np.array([[0],[Vb[1,0]],[Vb[2,0]]])
+ elif Vb[0,0] != 0:
+ dqb = np.array([[Vb[0,0]],[(Vb[1,0]*np.sin(Vb[0,0])+Vb[2,0]*(np.cos(Vb[0,0])-1))/Vb[0,0]],[(Vb[2,0]*np.sin(Vb[0,0])+Vb[1,0]*(1-np.cos(Vb[0,0])))/Vb[0,0]]])
+ # here we write down dq
+ dq = np.array([[1,0,0],[0,np.cos(config[0,0]),-np.sin(config[0,0])],[0,np.sin(config[0,0]),np.cos(config[0,0])]]).dot(dqb)
+ # here we write down new chassis config
+ new_chassis_config = config[0,0:3].reshape(1,3)+dq.reshape(1,3)
+
+ # here we put the angle and chassis configuration together
+ new_config = np.hstack((new_chassis_config,new_angle_config))
+
+ return new_config
\ No newline at end of file
diff --git a/7_Demo_youBotPickAndPlace/code/TrajectoryGenerator.py b/7_Demo_youBotPickAndPlace/code/TrajectoryGenerator.py
new file mode 100644
index 0000000..36f2a7c
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/TrajectoryGenerator.py
@@ -0,0 +1,86 @@
+import numpy as np
+import modern_robotics as mr
+
+def trajectoryGenerator(T_se_initial, T_sc_initial, T_sc_final, T_ce_grasp, T_ce_standoff, k):
+ # ---------------------------------
+ # segment 1: A trajectory to move the gripper from its initial configuration to a "standoff" configuration a few cm above the block
+ # represent the frame of end-effector when standoff in space frame
+ T_se_standoff_initial = T_sc_initial.dot(T_ce_standoff)
+ # generate trajectory when approaching the standoff position in segment 1
+ T_se_segment_1 = mr.CartesianTrajectory(T_se_initial,T_se_standoff_initial,5,5/0.01,3)
+
+ # ---------------------------------
+ # segment 2: A trajectory to move the gripper down to the grasp position
+ # represent the frame of end-effecto r in space frame in segment 2
+ T_se_grasp = T_sc_initial.dot(T_ce_grasp)
+ # generate trajectory when approaching the grasping position in segment 2
+ T_se_seg2 = mr.CartesianTrajectory(T_se_segment_1[-1], T_se_grasp, 2, 2/0.01, 3)
+ # append the trajectory of segment 2 after segment 1
+ T_se_before = np.append(T_se_segment_1, T_se_seg2, axis=0)
+
+ # ---------------------------------
+ # segment 3: Closing of the gripper
+ # append the trajectory of segment 3 by 63 times
+ for i in np.arange(64):
+ T_se_before = np.append(T_se_before,np.array([T_se_before[-1]]),axis=0)
+
+ # ---------------------------------
+ # segment 4: A trajectory to move the gripper back up to the "standoff" configuration
+ # generate trajectory when back on the standoff position in segment 4
+ T_se_segment_4 = mr.CartesianTrajectory(T_se_grasp, T_se_standoff_initial, 2, 2/0.01, 3)
+ # append the trajectory of segment 4
+ T_se_before = np.append(T_se_before,T_se_segment_4,axis=0)
+
+ # ---------------------------------
+ # segment 5: A trajectory to move the gripper to a "standoff" configuration above the final configuration
+ # generate trajectory when moving to the final standoff position in segment 5
+ T_se_standoff_final = T_sc_final.dot(T_ce_standoff)
+ T_se_segment_5 = mr.CartesianTrajectory(T_se_standoff_initial, T_se_standoff_final, 8, 8/0.01, 3)
+ # append the trajectory of segment 5
+ T_se_before = np.append(T_se_before, T_se_segment_5, axis=0)
+
+ # ---------------------------------
+ # segment 6: A trajectory to move the gripper to the final configuration of the object
+ # generate the end-effector configuration when losing
+ T_se_lose = T_sc_final.dot(T_ce_grasp)
+ # generate trajectory when moving to the final cube position in segment 6
+ T_se_segment_6 = mr.CartesianTrajectory(T_se_standoff_final, T_se_lose, 2, 2/0.01, 3)
+ # append the trajectory of segment 6
+ T_se_before = np.append(T_se_before, T_se_segment_6, axis=0)
+
+ # ---------------------------------
+ # segment 7: Opening of the gripper
+ # append the trajectory of segment 7 by 63 times
+ for i in np.arange(64):
+ T_se_before = np.append(T_se_before, np.array([T_se_before[-1]]), axis=0)
+
+ # ---------------------------------
+ # segment 8: A trajectory to move the gripper back to the "standoff" configuration
+ # generate trajectory when moving to the final standoff position in segment 8
+ T_se_segment_8 = mr.CartesianTrajectory(T_se_before[-1], T_se_standoff_final, 2, 2/0.01, 3)
+ # append the trajectory of segment 8
+ T_se_before = np.append(T_se_before, T_se_segment_8, axis=0)
+
+ # ---------------------------------
+ # generate a matrix which is n by 13
+ T_se_post = np.zeros([int(k*21/0.01+64*2),13])
+ # put the configuration, position and gripper state in matrix which is n by 13
+ for i in np.arange(int(k*21/0.01+64*2)):
+ T_se_post[i,0] = T_se_before[i,0,0]
+ T_se_post[i,1] = T_se_before[i,0,1]
+ T_se_post[i,2] = T_se_before[i,0,2]
+ T_se_post[i,3] = T_se_before[i,1,0]
+ T_se_post[i,4] = T_se_before[i,1,1]
+ T_se_post[i,5] = T_se_before[i,1,2]
+ T_se_post[i,6] = T_se_before[i,2,0]
+ T_se_post[i,7] = T_se_before[i,2,1]
+ T_se_post[i,8] = T_se_before[i,2,2]
+ T_se_post[i,9] = T_se_before[i,0,3]
+ T_se_post[i,10] = T_se_before[i,1,3]
+ T_se_post[i,11] = T_se_before[i,2,3]
+ T_se_post[i,12] = 0
+ # amend the gripper state in segment 3, 4, 5, 6
+ for i in np.arange(int(k*7/0.01), int(k*19/0.01+64)):
+ T_se_post[i, 12] = 1
+
+ return T_se_post
\ No newline at end of file
diff --git a/7_Demo_youBotPickAndPlace/code/main.py b/7_Demo_youBotPickAndPlace/code/main.py
new file mode 100644
index 0000000..1d5c046
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/main.py
@@ -0,0 +1,248 @@
+import numpy as np
+from TrajectoryGenerator import trajectoryGenerator
+from NextState import nextState
+from FeedbackControl import feedbackControl
+
+import time
+import sys
+sys.path.append('./vrep/VREP_remoteAPIs')
+
+#%% VREP control function definition
+''' Arm control function of youBot '''
+def VREP_armControl(vrep_sim, clientID, arm_joints_handle, desired_arm_joint_angles):
+ for i in range(0,5):
+ vrep_sim.simxSetJointPosition(clientID, arm_joints_handle[i], desired_arm_joint_angles[i], vrep_sim.simx_opmode_oneshot)
+
+''' Wheels control function of youBot '''
+def VREP_wheelsControl(vrep_sim, clientID, wheel_joints_handle, desired_wheel_positions):
+ for i in range(0,4):
+ vrep_sim.simxSetJointPosition(clientID, wheel_joints_handle[i], desired_wheel_positions[i], vrep_sim.simx_opmode_oneshot)
+
+''' World frame control function of youBot '''
+def VREP_WorldFrameControl(vrep_sim, clientID, world_joints_handle, desired_world_positions):
+ for i in range(0,3):
+ vrep_sim.simxSetJointPosition(clientID, world_joints_handle[i], desired_world_positions[i], vrep_sim.simx_opmode_oneshot)
+
+
+#%% VREP initialization
+try:
+ import sim as vrep_sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+print ('Program started')
+vrep_sim.simxFinish(-1) # just in case, close all opened connections
+clientID = vrep_sim.simxStart('127.0.0.1',19999,True,True,5000,5) # Connect to CoppeliaSim
+if clientID != -1:
+ print ('Connected to remote API server')
+
+ return_code, youBot_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBot', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot ok.')
+
+ return_code, youBot_dummy_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBotDummy', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBotDummy ok.')
+
+ # Prepare initial values for four wheels
+ wheel_joints_handle = [-1,-1,-1,-1]; # front left, rear left, rear right, front right
+ return_code, wheel_joints_handle[0] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_fl', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_rl ok.')
+
+ return_code, wheel_joints_handle[1] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_fr', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_fl ok.')
+
+ return_code, wheel_joints_handle[2] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_rr', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_fr ok.')
+
+ return_code, wheel_joints_handle[3] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_rl', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_rr ok.')
+
+ # Prepare initial values for five arm joints
+ arm_joints_handle = [-1,-1,-1,-1,-1]
+ for i in range(0,5):
+ return_code, arm_joints_handle[i] = vrep_sim.simxGetObjectHandle(clientID, 'Joint' + str(i+1), vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object arm joint ' + str(i+1) + ' ok.')
+
+ return_code, gripper_joint_1_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBotGripperJoint1', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object gripper joint 1 ok')
+
+ return_code, gripper_joint_2_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBotGripperJoint2', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object gripper joint 2 ok')
+
+ return_code, gripper_tip_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBot_positionTip', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object gripper position tip ok')
+
+ # Desired joint positions for initialization
+ desired_arm_joint_angles = [0, 0, 0, 0, 0]
+
+ # Initialization all arm joints
+ for i in range(0,5):
+ vrep_sim.simxSetJointPosition(clientID, arm_joints_handle[i], desired_arm_joint_angles[i], vrep_sim.simx_opmode_blocking)
+
+ # Get world joints handles
+ world_joints_handle = [-1, -1, -1]
+ return_code, world_joints_handle[0] = vrep_sim.simxGetObjectHandle(clientID, 'World_X_Joint', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object world joint X ok.')
+
+ return_code, world_joints_handle[1] = vrep_sim.simxGetObjectHandle(clientID, 'World_Y_Joint', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object world joint Y ok.')
+
+ return_code, world_joints_handle[2] = vrep_sim.simxGetObjectHandle(clientID, 'World_Th_Joint', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object world joint Th ok.')
+
+ # Get initial and goal cube handles
+ return_code, cube_1_handle = vrep_sim.simxGetObjectHandle(clientID, 'Cube_1', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object cube_1 ok.')
+
+ return_code, cube_2_handle = vrep_sim.simxGetObjectHandle(clientID, 'Cube_2', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object cube_2 ok.')
+
+ return_code, cube_goal_handle = vrep_sim.simxGetObjectHandle(clientID, 'Cube_goal', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object cube_goal_1 ok.')
+else:
+ print ('Failed connecting to remote API server')
+
+
+#%% ---------------------- generate trajectory and control the robot ---------------------------
+# Get initial and goal cube positions
+_, cube_1_position = vrep_sim.simxGetObjectPosition(clientID, cube_1_handle, -1, vrep_sim.simx_opmode_blocking)
+_, cube_2_position = vrep_sim.simxGetObjectPosition(clientID, cube_2_handle, -1, vrep_sim.simx_opmode_blocking)
+_, cube_goal_position = vrep_sim.simxGetObjectPosition(clientID, cube_goal_handle, -1, vrep_sim.simx_opmode_blocking)
+
+
+for i in range (0,2):
+ # Get youBot position
+ _, youBot_position = vrep_sim.simxGetObjectPosition(clientID, youBot_handle, -1, vrep_sim.simx_opmode_blocking)
+ _, youBot_x = vrep_sim.simxGetJointPosition(clientID, world_joints_handle[0], vrep_sim.simx_opmode_blocking)
+ _, youBot_y = vrep_sim.simxGetJointPosition(clientID, world_joints_handle[1], vrep_sim.simx_opmode_blocking)
+ _, youBot_phi = vrep_sim.simxGetJointPosition(clientID, world_joints_handle[2], vrep_sim.simx_opmode_blocking)
+
+ # Get youBot arm joint angles
+ youBot_arm_q = [0, 0, 0, 0, 0]
+ for j in range(0, 5):
+ _, youBot_arm_q[j] = vrep_sim.simxGetJointPosition(clientID, arm_joints_handle[j], vrep_sim.simx_opmode_blocking)
+
+ # Get youBot wheel angles
+ youBot_wheel_angles = [0, 0, 0, 0]
+ for j in range(0, 4):
+ _, youBot_wheel_angles[j] = vrep_sim.simxGetJointPosition(clientID, wheel_joints_handle[j], vrep_sim.simx_opmode_blocking)
+
+ # Get youBot gripper position
+ _, youBot_gripper_position = vrep_sim.simxGetObjectPosition(clientID, gripper_tip_handle, -1, vrep_sim.simx_opmode_blocking)
+
+ # Initialize the robot's configuration
+ # phi x y J1 J2 J3 J4 J5 w1 w2 w3 w4 gripper
+ config_initial = np.array([youBot_phi, youBot_x, youBot_y, youBot_arm_q[0], youBot_arm_q[1], youBot_arm_q[2], youBot_arm_q[3], youBot_arm_q[4], youBot_wheel_angles[0], youBot_wheel_angles[1], youBot_wheel_angles[2], youBot_wheel_angles[3], 0]).reshape(1,13)
+
+ # Generate trajectory
+ T_se_initial = np.array([[0,0,1,youBot_gripper_position[0]],[0,1,0,youBot_gripper_position[1]],[-1,0,0,youBot_gripper_position[2]],[0,0,0,1]])
+ if i == 0:
+ T_sc_initial = np.array([[1,0,0,cube_1_position[0]],[0,1,0,cube_1_position[1]],[0,0,1,cube_1_position[2]],[0,0,0,1]])
+ T_sc_final = np.array([[0,1,0,cube_goal_position[0]],[-1,0,0,cube_goal_position[1]],[0,0,1, cube_goal_position[2]],[0,0,0,1]])
+ else:
+ T_sc_initial = np.array([[1,0,0,cube_2_position[0]],[0,1,0,cube_2_position[1]],[0,0,1,cube_2_position[2]],[0,0,0,1]])
+ T_sc_final = np.array([[0,1,0,cube_goal_position[0]],[-1,0,0,cube_goal_position[1]],[0,0,1, cube_goal_position[2] + 0.05],[0,0,0,1]])
+ gripper_pose = np.pi/3 # change orientation of the gripper, default value is pi/4
+ T_ce_grasp = np.array([[-np.sin(gripper_pose), 0, np.cos(gripper_pose),0],[0,1,0,0],[-np.cos(gripper_pose), 0, -np.sin(gripper_pose),0],[0,0,0,1]])
+ T_ce_standoff = np.array([[-np.sin(gripper_pose), 0, np.cos(gripper_pose),0],[0,1,0,0],[-np.cos(gripper_pose), 0, -np.sin(gripper_pose),0.1],[0,0,0,1]])
+
+ k = 1
+ T_se_post = trajectoryGenerator(T_se_initial,T_sc_initial,T_sc_final,T_ce_grasp,T_ce_standoff,k)
+
+ # set to use joint limits
+ joint_limit = 0
+
+ # set Kp, Ki and dt
+ Kp = 2.2
+ Ki = 0
+ dt = 0.01
+
+ #%% ------------------------------------- main loop --------------------------------------
+ desired_wheel_positions = [0,0,0,0]
+ desired_world_positions = [0,0,0]
+ reference_trajectory = []
+ reference_trajectory.append(config_initial)
+ new_config = config_initial
+
+ print('begin main control loop ...')
+ for i in np.arange(np.shape(T_se_post)[0]-1):
+ # write down Xd
+ Xd = np.array([[T_se_post[i,0],T_se_post[i,1],T_se_post[i,2],T_se_post[i,9]],[T_se_post[i,3],T_se_post[i,4],T_se_post[i,5],T_se_post[i,10]],[T_se_post[i,6],T_se_post[i,7],T_se_post[i,8],T_se_post[i,11]],[0,0,0,1]])
+
+ # write down Xd_next
+ Xd_next = np.array([[T_se_post[i+1,0],T_se_post[i+1,1],T_se_post[i+1,2],T_se_post[i+1,9]],[T_se_post[i+1,3],T_se_post[i+1,4],T_se_post[i+1,5],T_se_post[i+1,10]],[T_se_post[i+1,6],T_se_post[i+1,7],T_se_post[i+1,8],T_se_post[i+1,11]],[0,0,0,1]])
+
+ # compute speeds and X_err
+ V, speeds, X_err = feedbackControl(new_config, Xd, Xd_next, Kp, Ki, dt, joint_limit)
+
+ # adjust the order of wheels speeds and joints speeds
+ speeds = np.array([speeds[4], speeds[5], speeds[6], speeds[7], speeds[8], speeds[0], speeds[1], speeds[2], speeds[3]]).reshape(1,9)
+ speeds_max = 1000
+
+ # compute new configuration
+ new_config = nextState(new_config,speeds,dt,speeds_max)
+ new_config = np.append(new_config,[[T_se_post[i,12]]],axis=1)
+ reference_trajectory.append(new_config) # record the trajectory
+
+ # set commands for the youBot model in VREP
+ desired_world_positions[0] = new_config[0, 1]
+ desired_world_positions[1] = new_config[0, 2]
+ desired_world_positions[2] = new_config[0, 0]
+
+ desired_arm_joint_angles[0] = new_config[0, 3]
+ desired_arm_joint_angles[1] = new_config[0, 4]
+ desired_arm_joint_angles[2] = new_config[0, 5]
+ desired_arm_joint_angles[3] = new_config[0, 6]
+ desired_arm_joint_angles[4] = new_config[0, 7]
+
+ desired_wheel_positions[0] = new_config[0, 8]
+ desired_wheel_positions[1] = new_config[0, 9]
+ desired_wheel_positions[2] = new_config[0, 10]
+ desired_wheel_positions[3] = new_config[0, 11]
+
+ # send commands to VREP
+ VREP_armControl(vrep_sim, clientID, arm_joints_handle, desired_arm_joint_angles)
+ VREP_wheelsControl(vrep_sim, clientID, wheel_joints_handle, desired_wheel_positions)
+ VREP_WorldFrameControl(vrep_sim, clientID, world_joints_handle, desired_world_positions)
+
+ # set gripper state
+ if new_config[0, 12] == 0:
+ vrep_sim.simxSetJointTargetVelocity(clientID, gripper_joint_2_handle, -0.04, vrep_sim.simx_opmode_oneshot) # open
+ else:
+ vrep_sim.simxSetJointTargetVelocity(clientID, gripper_joint_2_handle, 0.04, vrep_sim.simx_opmode_oneshot) # close
+ return_code, gripper_joint_2_position = vrep_sim.simxGetJointPosition(clientID, gripper_joint_2_handle, vrep_sim.simx_opmode_oneshot)
+ vrep_sim.simxSetJointTargetPosition(clientID, gripper_joint_1_handle, -gripper_joint_2_position, vrep_sim.simx_opmode_oneshot)
+ time.sleep(0.002)
+
+ # Squeeze reference trajectory
+ reference_trajectory = np.squeeze(reference_trajectory)
+
+# Stop VREP simulation
+#print ('Stop VREP simulation')
+#vrep_sim.simxStopSimulation(clientID, vrep_sim.simx_opmode_blocking)
+time.sleep(0.1)
+
+# Now close the connection to VREP
+vrep_sim.simxFinish(clientID)
+print ('Program ended')
diff --git a/7_Demo_youBotPickAndPlace/code/modern_robotics/__init__.py b/7_Demo_youBotPickAndPlace/code/modern_robotics/__init__.py
new file mode 100644
index 0000000..1c4a7c8
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/modern_robotics/__init__.py
@@ -0,0 +1,4 @@
+from .__version__ import __version__
+
+from .core import *
+
diff --git a/7_Demo_youBotPickAndPlace/code/modern_robotics/__version__.py b/7_Demo_youBotPickAndPlace/code/modern_robotics/__version__.py
new file mode 100644
index 0000000..d930acc
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/modern_robotics/__version__.py
@@ -0,0 +1,2 @@
+
+__version__ = '1.1.0'
diff --git a/7_Demo_youBotPickAndPlace/code/modern_robotics/core.py b/7_Demo_youBotPickAndPlace/code/modern_robotics/core.py
new file mode 100644
index 0000000..4b44235
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/modern_robotics/core.py
@@ -0,0 +1,1899 @@
+from __future__ import print_function
+'''
+***************************************************************************
+Modern Robotics: Mechanics, Planning, and Control.
+Code Library
+***************************************************************************
+Author: Huan Weng, Bill Hunt, Jarvis Schultz, Mikhail Todes,
+Email: huanweng@u.northwestern.edu
+Date: January 2018
+***************************************************************************
+Language: Python
+Also available in: MATLAB, Mathematica
+Required library: numpy
+Optional library: matplotlib
+***************************************************************************
+'''
+
+'''
+*** IMPORTS ***
+'''
+
+import numpy as np
+
+'''
+*** BASIC HELPER FUNCTIONS ***
+'''
+
+def NearZero(z):
+ """Determines whether a scalar is small enough to be treated as zero
+
+ :param z: A scalar input to check
+ :return: True if z is close to zero, false otherwise
+
+ Example Input:
+ z = -1e-7
+ Output:
+ True
+ """
+ return abs(z) < 1e-6
+
+def Normalize(V):
+ """Normalizes a vector
+
+ :param V: A vector
+ :return: A unit vector pointing in the same direction as z
+
+ Example Input:
+ V = np.array([1, 2, 3])
+ Output:
+ np.array([0.26726124, 0.53452248, 0.80178373])
+ """
+ return V / np.linalg.norm(V)
+
+'''
+*** CHAPTER 3: RIGID-BODY MOTIONS ***
+'''
+
+def RotInv(R):
+ """Inverts a rotation matrix
+
+ :param R: A rotation matrix
+ :return: The inverse of R
+
+ Example Input:
+ R = np.array([[0, 0, 1],
+ [1, 0, 0],
+ [0, 1, 0]])
+ Output:
+ np.array([[0, 1, 0],
+ [0, 0, 1],
+ [1, 0, 0]])
+ """
+ return np.array(R).T
+
+def VecToso3(omg):
+ """Converts a 3-vector to an so(3) representation
+
+ :param omg: A 3-vector
+ :return: The skew symmetric representation of omg
+
+ Example Input:
+ omg = np.array([1, 2, 3])
+ Output:
+ np.array([[ 0, -3, 2],
+ [ 3, 0, -1],
+ [-2, 1, 0]])
+ """
+ return np.array([[0, -omg[2], omg[1]],
+ [omg[2], 0, -omg[0]],
+ [-omg[1], omg[0], 0]])
+
+def so3ToVec(so3mat):
+ """Converts an so(3) representation to a 3-vector
+
+ :param so3mat: A 3x3 skew-symmetric matrix
+ :return: The 3-vector corresponding to so3mat
+
+ Example Input:
+ so3mat = np.array([[ 0, -3, 2],
+ [ 3, 0, -1],
+ [-2, 1, 0]])
+ Output:
+ np.array([1, 2, 3])
+ """
+ return np.array([so3mat[2][1], so3mat[0][2], so3mat[1][0]])
+
+def AxisAng3(expc3):
+ """Converts a 3-vector of exponential coordinates for rotation into
+ axis-angle form
+
+ :param expc3: A 3-vector of exponential coordinates for rotation
+ :return omghat: A unit rotation axis
+ :return theta: The corresponding rotation angle
+
+ Example Input:
+ expc3 = np.array([1, 2, 3])
+ Output:
+ (np.array([0.26726124, 0.53452248, 0.80178373]), 3.7416573867739413)
+ """
+ return (Normalize(expc3), np.linalg.norm(expc3))
+
+def MatrixExp3(so3mat):
+ """Computes the matrix exponential of a matrix in so(3)
+
+ :param so3mat: A 3x3 skew-symmetric matrix
+ :return: The matrix exponential of so3mat
+
+ Example Input:
+ so3mat = np.array([[ 0, -3, 2],
+ [ 3, 0, -1],
+ [-2, 1, 0]])
+ Output:
+ np.array([[-0.69492056, 0.71352099, 0.08929286],
+ [-0.19200697, -0.30378504, 0.93319235],
+ [ 0.69297817, 0.6313497 , 0.34810748]])
+ """
+ omgtheta = so3ToVec(so3mat)
+ if NearZero(np.linalg.norm(omgtheta)):
+ return np.eye(3)
+ else:
+ theta = AxisAng3(omgtheta)[1]
+ omgmat = so3mat / theta
+ return np.eye(3) + np.sin(theta) * omgmat \
+ + (1 - np.cos(theta)) * np.dot(omgmat, omgmat)
+
+def MatrixLog3(R):
+ """Computes the matrix logarithm of a rotation matrix
+
+ :param R: A 3x3 rotation matrix
+ :return: The matrix logarithm of R
+
+ Example Input:
+ R = np.array([[0, 0, 1],
+ [1, 0, 0],
+ [0, 1, 0]])
+ Output:
+ np.array([[ 0, -1.20919958, 1.20919958],
+ [ 1.20919958, 0, -1.20919958],
+ [-1.20919958, 1.20919958, 0]])
+ """
+ acosinput = (np.trace(R) - 1) / 2.0
+ if acosinput >= 1:
+ return np.zeros((3, 3))
+ elif acosinput <= -1:
+ if not NearZero(1 + R[2][2]):
+ omg = (1.0 / np.sqrt(2 * (1 + R[2][2]))) \
+ * np.array([R[0][2], R[1][2], 1 + R[2][2]])
+ elif not NearZero(1 + R[1][1]):
+ omg = (1.0 / np.sqrt(2 * (1 + R[1][1]))) \
+ * np.array([R[0][1], 1 + R[1][1], R[2][1]])
+ else:
+ omg = (1.0 / np.sqrt(2 * (1 + R[0][0]))) \
+ * np.array([1 + R[0][0], R[1][0], R[2][0]])
+ return VecToso3(np.pi * omg)
+ else:
+ theta = np.arccos(acosinput)
+ return theta / 2.0 / np.sin(theta) * (R - np.array(R).T)
+
+def RpToTrans(R, p):
+ """Converts a rotation matrix and a position vector into homogeneous
+ transformation matrix
+
+ :param R: A 3x3 rotation matrix
+ :param p: A 3-vector
+ :return: A homogeneous transformation matrix corresponding to the inputs
+
+ Example Input:
+ R = np.array([[1, 0, 0],
+ [0, 0, -1],
+ [0, 1, 0]])
+ p = np.array([1, 2, 5])
+ Output:
+ np.array([[1, 0, 0, 1],
+ [0, 0, -1, 2],
+ [0, 1, 0, 5],
+ [0, 0, 0, 1]])
+ """
+ return np.r_[np.c_[R, p], [[0, 0, 0, 1]]]
+
+def TransToRp(T):
+ """Converts a homogeneous transformation matrix into a rotation matrix
+ and position vector
+
+ :param T: A homogeneous transformation matrix
+ :return R: The corresponding rotation matrix,
+ :return p: The corresponding position vector.
+
+ Example Input:
+ T = np.array([[1, 0, 0, 0],
+ [0, 0, -1, 0],
+ [0, 1, 0, 3],
+ [0, 0, 0, 1]])
+ Output:
+ (np.array([[1, 0, 0],
+ [0, 0, -1],
+ [0, 1, 0]]),
+ np.array([0, 0, 3]))
+ """
+ T = np.array(T)
+ return T[0: 3, 0: 3], T[0: 3, 3]
+
+def TransInv(T):
+ """Inverts a homogeneous transformation matrix
+
+ :param T: A homogeneous transformation matrix
+ :return: The inverse of T
+ Uses the structure of transformation matrices to avoid taking a matrix
+ inverse, for efficiency.
+
+ Example input:
+ T = np.array([[1, 0, 0, 0],
+ [0, 0, -1, 0],
+ [0, 1, 0, 3],
+ [0, 0, 0, 1]])
+ Output:
+ np.array([[1, 0, 0, 0],
+ [0, 0, 1, -3],
+ [0, -1, 0, 0],
+ [0, 0, 0, 1]])
+ """
+ R, p = TransToRp(T)
+ Rt = np.array(R).T
+ return np.r_[np.c_[Rt, -np.dot(Rt, p)], [[0, 0, 0, 1]]]
+
+def VecTose3(V):
+ """Converts a spatial velocity vector into a 4x4 matrix in se3
+
+ :param V: A 6-vector representing a spatial velocity
+ :return: The 4x4 se3 representation of V
+
+ Example Input:
+ V = np.array([1, 2, 3, 4, 5, 6])
+ Output:
+ np.array([[ 0, -3, 2, 4],
+ [ 3, 0, -1, 5],
+ [-2, 1, 0, 6],
+ [ 0, 0, 0, 0]])
+ """
+ return np.r_[np.c_[VecToso3([V[0], V[1], V[2]]), [V[3], V[4], V[5]]],
+ np.zeros((1, 4))]
+
+def se3ToVec(se3mat):
+ """ Converts an se3 matrix into a spatial velocity vector
+
+ :param se3mat: A 4x4 matrix in se3
+ :return: The spatial velocity 6-vector corresponding to se3mat
+
+ Example Input:
+ se3mat = np.array([[ 0, -3, 2, 4],
+ [ 3, 0, -1, 5],
+ [-2, 1, 0, 6],
+ [ 0, 0, 0, 0]])
+ Output:
+ np.array([1, 2, 3, 4, 5, 6])
+ """
+ return np.r_[[se3mat[2][1], se3mat[0][2], se3mat[1][0]],
+ [se3mat[0][3], se3mat[1][3], se3mat[2][3]]]
+
+def Adjoint(T):
+ """Computes the adjoint representation of a homogeneous transformation
+ matrix
+
+ :param T: A homogeneous transformation matrix
+ :return: The 6x6 adjoint representation [AdT] of T
+
+ Example Input:
+ T = np.array([[1, 0, 0, 0],
+ [0, 0, -1, 0],
+ [0, 1, 0, 3],
+ [0, 0, 0, 1]])
+ Output:
+ np.array([[1, 0, 0, 0, 0, 0],
+ [0, 0, -1, 0, 0, 0],
+ [0, 1, 0, 0, 0, 0],
+ [0, 0, 3, 1, 0, 0],
+ [3, 0, 0, 0, 0, -1],
+ [0, 0, 0, 0, 1, 0]])
+ """
+ R, p = TransToRp(T)
+ return np.r_[np.c_[R, np.zeros((3, 3))],
+ np.c_[np.dot(VecToso3(p), R), R]]
+
+def ScrewToAxis(q, s, h):
+ """Takes a parametric description of a screw axis and converts it to a
+ normalized screw axis
+
+ :param q: A point lying on the screw axis
+ :param s: A unit vector in the direction of the screw axis
+ :param h: The pitch of the screw axis
+ :return: A normalized screw axis described by the inputs
+
+ Example Input:
+ q = np.array([3, 0, 0])
+ s = np.array([0, 0, 1])
+ h = 2
+ Output:
+ np.array([0, 0, 1, 0, -3, 2])
+ """
+ return np.r_[s, np.cross(q, s) + np.dot(h, s)]
+
+def AxisAng6(expc6):
+ """Converts a 6-vector of exponential coordinates into screw axis-angle
+ form
+
+ :param expc6: A 6-vector of exponential coordinates for rigid-body motion
+ S*theta
+ :return S: The corresponding normalized screw axis
+ :return theta: The distance traveled along/about S
+
+ Example Input:
+ expc6 = np.array([1, 0, 0, 1, 2, 3])
+ Output:
+ (np.array([1.0, 0.0, 0.0, 1.0, 2.0, 3.0]), 1.0)
+ """
+ theta = np.linalg.norm([expc6[0], expc6[1], expc6[2]])
+ if NearZero(theta):
+ theta = np.linalg.norm([expc6[3], expc6[4], expc6[5]])
+ return (np.array(expc6 / theta), theta)
+
+def MatrixExp6(se3mat):
+ """Computes the matrix exponential of an se3 representation of
+ exponential coordinates
+
+ :param se3mat: A matrix in se3
+ :return: The matrix exponential of se3mat
+
+ Example Input:
+ se3mat = np.array([[0, 0, 0, 0],
+ [0, 0, -1.57079632, 2.35619449],
+ [0, 1.57079632, 0, 2.35619449],
+ [0, 0, 0, 0]])
+ Output:
+ np.array([[1.0, 0.0, 0.0, 0.0],
+ [0.0, 0.0, -1.0, 0.0],
+ [0.0, 1.0, 0.0, 3.0],
+ [ 0, 0, 0, 1]])
+ """
+ se3mat = np.array(se3mat)
+ omgtheta = so3ToVec(se3mat[0: 3, 0: 3])
+ if NearZero(np.linalg.norm(omgtheta)):
+ return np.r_[np.c_[np.eye(3), se3mat[0: 3, 3]], [[0, 0, 0, 1]]]
+ else:
+ theta = AxisAng3(omgtheta)[1]
+ omgmat = se3mat[0: 3, 0: 3] / theta
+ return np.r_[np.c_[MatrixExp3(se3mat[0: 3, 0: 3]),
+ np.dot(np.eye(3) * theta \
+ + (1 - np.cos(theta)) * omgmat \
+ + (theta - np.sin(theta)) \
+ * np.dot(omgmat,omgmat),
+ se3mat[0: 3, 3]) / theta],
+ [[0, 0, 0, 1]]]
+
+def MatrixLog6(T):
+ """Computes the matrix logarithm of a homogeneous transformation matrix
+
+ :param R: A matrix in SE3
+ :return: The matrix logarithm of R
+
+ Example Input:
+ T = np.array([[1, 0, 0, 0],
+ [0, 0, -1, 0],
+ [0, 1, 0, 3],
+ [0, 0, 0, 1]])
+ Output:
+ np.array([[0, 0, 0, 0]
+ [0, 0, -1.57079633, 2.35619449]
+ [0, 1.57079633, 0, 2.35619449]
+ [0, 0, 0, 0]])
+ """
+ R, p = TransToRp(T)
+ omgmat = MatrixLog3(R)
+ if np.array_equal(omgmat, np.zeros((3, 3))):
+ return np.r_[np.c_[np.zeros((3, 3)),
+ [T[0][3], T[1][3], T[2][3]]],
+ [[0, 0, 0, 0]]]
+ else:
+ theta = np.arccos((np.trace(R) - 1) / 2.0)
+ return np.r_[np.c_[omgmat,
+ np.dot(np.eye(3) - omgmat / 2.0 \
+ + (1.0 / theta - 1.0 / np.tan(theta / 2.0) / 2) \
+ * np.dot(omgmat,omgmat) / theta,[T[0][3],
+ T[1][3],
+ T[2][3]])],
+ [[0, 0, 0, 0]]]
+
+def ProjectToSO3(mat):
+ """Returns a projection of mat into SO(3)
+
+ :param mat: A matrix near SO(3) to project to SO(3)
+ :return: The closest matrix to R that is in SO(3)
+ Projects a matrix mat to the closest matrix in SO(3) using singular-value
+ decomposition (see
+ http://hades.mech.northwestern.edu/index.php/Modern_Robotics_Linear_Algebra_Review).
+ This function is only appropriate for matrices close to SO(3).
+
+ Example Input:
+ mat = np.array([[ 0.675, 0.150, 0.720],
+ [ 0.370, 0.771, -0.511],
+ [-0.630, 0.619, 0.472]])
+ Output:
+ np.array([[ 0.67901136, 0.14894516, 0.71885945],
+ [ 0.37320708, 0.77319584, -0.51272279],
+ [-0.63218672, 0.61642804, 0.46942137]])
+ """
+ U, s, Vh = np.linalg.svd(mat)
+ R = np.dot(U, Vh)
+ if np.linalg.det(R) < 0:
+ # In this case the result may be far from mat.
+ R[:, s[2, 2]] = -R[:, s[2, 2]]
+ return R
+
+def ProjectToSE3(mat):
+ """Returns a projection of mat into SE(3)
+
+ :param mat: A 4x4 matrix to project to SE(3)
+ :return: The closest matrix to T that is in SE(3)
+ Projects a matrix mat to the closest matrix in SE(3) using singular-value
+ decomposition (see
+ http://hades.mech.northwestern.edu/index.php/Modern_Robotics_Linear_Algebra_Review).
+ This function is only appropriate for matrices close to SE(3).
+
+ Example Input:
+ mat = np.array([[ 0.675, 0.150, 0.720, 1.2],
+ [ 0.370, 0.771, -0.511, 5.4],
+ [-0.630, 0.619, 0.472, 3.6],
+ [ 0.003, 0.002, 0.010, 0.9]])
+ Output:
+ np.array([[ 0.67901136, 0.14894516, 0.71885945, 1.2 ],
+ [ 0.37320708, 0.77319584, -0.51272279, 5.4 ],
+ [-0.63218672, 0.61642804, 0.46942137, 3.6 ],
+ [ 0. , 0. , 0. , 1. ]])
+ """
+ mat = np.array(mat)
+ return RpToTrans(ProjectToSO3(mat[:3, :3]), mat[:3, 3])
+
+def DistanceToSO3(mat):
+ """Returns the Frobenius norm to describe the distance of mat from the
+ SO(3) manifold
+
+ :param mat: A 3x3 matrix
+ :return: A quantity describing the distance of mat from the SO(3)
+ manifold
+ Computes the distance from mat to the SO(3) manifold using the following
+ method:
+ If det(mat) <= 0, return a large number.
+ If det(mat) > 0, return norm(mat^T.mat - I).
+
+ Example Input:
+ mat = np.array([[ 1.0, 0.0, 0.0 ],
+ [ 0.0, 0.1, -0.95],
+ [ 0.0, 1.0, 0.1 ]])
+ Output:
+ 0.08835
+ """
+ if np.linalg.det(mat) > 0:
+ return np.linalg.norm(np.dot(np.array(mat).T, mat) - np.eye(3))
+ else:
+ return 1e+9
+
+def DistanceToSE3(mat):
+ """Returns the Frobenius norm to describe the distance of mat from the
+ SE(3) manifold
+
+ :param mat: A 4x4 matrix
+ :return: A quantity describing the distance of mat from the SE(3)
+ manifold
+ Computes the distance from mat to the SE(3) manifold using the following
+ method:
+ Compute the determinant of matR, the top 3x3 submatrix of mat.
+ If det(matR) <= 0, return a large number.
+ If det(matR) > 0, replace the top 3x3 submatrix of mat with matR^T.matR,
+ and set the first three entries of the fourth column of mat to zero. Then
+ return norm(mat - I).
+
+ Example Input:
+ mat = np.array([[ 1.0, 0.0, 0.0, 1.2 ],
+ [ 0.0, 0.1, -0.95, 1.5 ],
+ [ 0.0, 1.0, 0.1, -0.9 ],
+ [ 0.0, 0.0, 0.1, 0.98 ]])
+ Output:
+ 0.134931
+ """
+ matR = np.array(mat)[0: 3, 0: 3]
+ if np.linalg.det(matR) > 0:
+ return np.linalg.norm(np.r_[np.c_[np.dot(np.transpose(matR), matR),
+ np.zeros((3, 1))],
+ [np.array(mat)[3, :]]] - np.eye(4))
+ else:
+ return 1e+9
+
+def TestIfSO3(mat):
+ """Returns true if mat is close to or on the manifold SO(3)
+
+ :param mat: A 3x3 matrix
+ :return: True if mat is very close to or in SO(3), false otherwise
+ Computes the distance d from mat to the SO(3) manifold using the
+ following method:
+ If det(mat) <= 0, d = a large number.
+ If det(mat) > 0, d = norm(mat^T.mat - I).
+ If d is close to zero, return true. Otherwise, return false.
+
+ Example Input:
+ mat = np.array([[1.0, 0.0, 0.0 ],
+ [0.0, 0.1, -0.95],
+ [0.0, 1.0, 0.1 ]])
+ Output:
+ False
+ """
+ return abs(DistanceToSO3(mat)) < 1e-3
+
+def TestIfSE3(mat):
+ """Returns true if mat is close to or on the manifold SE(3)
+
+ :param mat: A 4x4 matrix
+ :return: True if mat is very close to or in SE(3), false otherwise
+ Computes the distance d from mat to the SE(3) manifold using the
+ following method:
+ Compute the determinant of the top 3x3 submatrix of mat.
+ If det(mat) <= 0, d = a large number.
+ If det(mat) > 0, replace the top 3x3 submatrix of mat with mat^T.mat, and
+ set the first three entries of the fourth column of mat to zero.
+ Then d = norm(T - I).
+ If d is close to zero, return true. Otherwise, return false.
+
+ Example Input:
+ mat = np.array([[1.0, 0.0, 0.0, 1.2],
+ [0.0, 0.1, -0.95, 1.5],
+ [0.0, 1.0, 0.1, -0.9],
+ [0.0, 0.0, 0.1, 0.98]])
+ Output:
+ False
+ """
+ return abs(DistanceToSE3(mat)) < 1e-3
+
+'''
+*** CHAPTER 4: FORWARD KINEMATICS ***
+'''
+
+def FKinBody(M, Blist, thetalist):
+ """Computes forward kinematics in the body frame for an open chain robot
+
+ :param M: The home configuration (position and orientation) of the end-
+ effector
+ :param Blist: The joint screw axes in the end-effector frame when the
+ manipulator is at the home position, in the format of a
+ matrix with axes as the columns
+ :param thetalist: A list of joint coordinates
+ :return: A homogeneous transformation matrix representing the end-
+ effector frame when the joints are at the specified coordinates
+ (i.t.o Body Frame)
+
+ Example Input:
+ M = np.array([[-1, 0, 0, 0],
+ [ 0, 1, 0, 6],
+ [ 0, 0, -1, 2],
+ [ 0, 0, 0, 1]])
+ Blist = np.array([[0, 0, -1, 2, 0, 0],
+ [0, 0, 0, 0, 1, 0],
+ [0, 0, 1, 0, 0, 0.1]]).T
+ thetalist = np.array([np.pi / 2.0, 3, np.pi])
+ Output:
+ np.array([[0, 1, 0, -5],
+ [1, 0, 0, 4],
+ [0, 0, -1, 1.68584073],
+ [0, 0, 0, 1]])
+ """
+ T = np.array(M)
+ for i in range(len(thetalist)):
+ T = np.dot(T, MatrixExp6(VecTose3(np.array(Blist)[:, i] \
+ * thetalist[i])))
+ return T
+
+def FKinSpace(M, Slist, thetalist):
+ """Computes forward kinematics in the space frame for an open chain robot
+
+ :param M: The home configuration (position and orientation) of the end-
+ effector
+ :param Slist: The joint screw axes in the space frame when the
+ manipulator is at the home position, in the format of a
+ matrix with axes as the columns
+ :param thetalist: A list of joint coordinates
+ :return: A homogeneous transformation matrix representing the end-
+ effector frame when the joints are at the specified coordinates
+ (i.t.o Space Frame)
+
+ Example Input:
+ M = np.array([[-1, 0, 0, 0],
+ [ 0, 1, 0, 6],
+ [ 0, 0, -1, 2],
+ [ 0, 0, 0, 1]])
+ Slist = np.array([[0, 0, 1, 4, 0, 0],
+ [0, 0, 0, 0, 1, 0],
+ [0, 0, -1, -6, 0, -0.1]]).T
+ thetalist = np.array([np.pi / 2.0, 3, np.pi])
+ Output:
+ np.array([[0, 1, 0, -5],
+ [1, 0, 0, 4],
+ [0, 0, -1, 1.68584073],
+ [0, 0, 0, 1]])
+ """
+ T = np.array(M)
+ for i in range(len(thetalist) - 1, -1, -1):
+ T = np.dot(MatrixExp6(VecTose3(np.array(Slist)[:, i] \
+ * thetalist[i])), T)
+ return T
+
+'''
+*** CHAPTER 5: VELOCITY KINEMATICS AND STATICS***
+'''
+
+def JacobianBody(Blist, thetalist):
+ """Computes the body Jacobian for an open chain robot
+
+ :param Blist: The joint screw axes in the end-effector frame when the
+ manipulator is at the home position, in the format of a
+ matrix with axes as the columns
+ :param thetalist: A list of joint coordinates
+ :return: The body Jacobian corresponding to the inputs (6xn real
+ numbers)
+
+ Example Input:
+ Blist = np.array([[0, 0, 1, 0, 0.2, 0.2],
+ [1, 0, 0, 2, 0, 3],
+ [0, 1, 0, 0, 2, 1],
+ [1, 0, 0, 0.2, 0.3, 0.4]]).T
+ thetalist = np.array([0.2, 1.1, 0.1, 1.2])
+ Output:
+ np.array([[-0.04528405, 0.99500417, 0, 1]
+ [ 0.74359313, 0.09304865, 0.36235775, 0]
+ [-0.66709716, 0.03617541, -0.93203909, 0]
+ [ 2.32586047, 1.66809, 0.56410831, 0.2]
+ [-1.44321167, 2.94561275, 1.43306521, 0.3]
+ [-2.06639565, 1.82881722, -1.58868628, 0.4]])
+ """
+ Jb = np.array(Blist).copy().astype(np.float)
+ T = np.eye(4)
+ for i in range(len(thetalist) - 2, -1, -1):
+ T = np.dot(T,MatrixExp6(VecTose3(np.array(Blist)[:, i + 1] \
+ * -thetalist[i + 1])))
+ Jb[:, i] = np.dot(Adjoint(T), np.array(Blist)[:, i])
+ return Jb
+
+def JacobianSpace(Slist, thetalist):
+ """Computes the space Jacobian for an open chain robot
+
+ :param Slist: The joint screw axes in the space frame when the
+ manipulator is at the home position, in the format of a
+ matrix with axes as the columns
+ :param thetalist: A list of joint coordinates
+ :return: The space Jacobian corresponding to the inputs (6xn real
+ numbers)
+
+ Example Input:
+ Slist = np.array([[0, 0, 1, 0, 0.2, 0.2],
+ [1, 0, 0, 2, 0, 3],
+ [0, 1, 0, 0, 2, 1],
+ [1, 0, 0, 0.2, 0.3, 0.4]]).T
+ thetalist = np.array([0.2, 1.1, 0.1, 1.2])
+ Output:
+ np.array([[ 0, 0.98006658, -0.09011564, 0.95749426]
+ [ 0, 0.19866933, 0.4445544, 0.28487557]
+ [ 1, 0, 0.89120736, -0.04528405]
+ [ 0, 1.95218638, -2.21635216, -0.51161537]
+ [0.2, 0.43654132, -2.43712573, 2.77535713]
+ [0.2, 2.96026613, 3.23573065, 2.22512443]])
+ """
+ Js = np.array(Slist).copy().astype(np.float)
+ T = np.eye(4)
+ for i in range(1, len(thetalist)):
+ T = np.dot(T, MatrixExp6(VecTose3(np.array(Slist)[:, i - 1] \
+ * thetalist[i - 1])))
+ Js[:, i] = np.dot(Adjoint(T), np.array(Slist)[:, i])
+ return Js
+
+'''
+*** CHAPTER 6: INVERSE KINEMATICS ***
+'''
+
+def IKinBody(Blist, M, T, thetalist0, eomg, ev):
+ """Computes inverse kinematics in the body frame for an open chain robot
+
+ :param Blist: The joint screw axes in the end-effector frame when the
+ manipulator is at the home position, in the format of a
+ matrix with axes as the columns
+ :param M: The home configuration of the end-effector
+ :param T: The desired end-effector configuration Tsd
+ :param thetalist0: An initial guess of joint angles that are close to
+ satisfying Tsd
+ :param eomg: A small positive tolerance on the end-effector orientation
+ error. The returned joint angles must give an end-effector
+ orientation error less than eomg
+ :param ev: A small positive tolerance on the end-effector linear position
+ error. The returned joint angles must give an end-effector
+ position error less than ev
+ :return thetalist: Joint angles that achieve T within the specified
+ tolerances,
+ :return success: A logical value where TRUE means that the function found
+ a solution and FALSE means that it ran through the set
+ number of maximum iterations without finding a solution
+ within the tolerances eomg and ev.
+ Uses an iterative Newton-Raphson root-finding method.
+ The maximum number of iterations before the algorithm is terminated has
+ been hardcoded in as a variable called maxiterations. It is set to 20 at
+ the start of the function, but can be changed if needed.
+
+ Example Input:
+ Blist = np.array([[0, 0, -1, 2, 0, 0],
+ [0, 0, 0, 0, 1, 0],
+ [0, 0, 1, 0, 0, 0.1]]).T
+ M = np.array([[-1, 0, 0, 0],
+ [ 0, 1, 0, 6],
+ [ 0, 0, -1, 2],
+ [ 0, 0, 0, 1]])
+ T = np.array([[0, 1, 0, -5],
+ [1, 0, 0, 4],
+ [0, 0, -1, 1.6858],
+ [0, 0, 0, 1]])
+ thetalist0 = np.array([1.5, 2.5, 3])
+ eomg = 0.01
+ ev = 0.001
+ Output:
+ (np.array([1.57073819, 2.999667, 3.14153913]), True)
+ """
+ thetalist = np.array(thetalist0).copy()
+ i = 0
+ maxiterations = 20
+ Vb = se3ToVec(MatrixLog6(np.dot(TransInv(FKinBody(M, Blist, \
+ thetalist)), T)))
+ err = np.linalg.norm([Vb[0], Vb[1], Vb[2]]) > eomg \
+ or np.linalg.norm([Vb[3], Vb[4], Vb[5]]) > ev
+ while err and i < maxiterations:
+ thetalist = thetalist \
+ + np.dot(np.linalg.pinv(JacobianBody(Blist, \
+ thetalist)), Vb)
+ i = i + 1
+ Vb \
+ = se3ToVec(MatrixLog6(np.dot(TransInv(FKinBody(M, Blist, \
+ thetalist)), T)))
+ err = np.linalg.norm([Vb[0], Vb[1], Vb[2]]) > eomg \
+ or np.linalg.norm([Vb[3], Vb[4], Vb[5]]) > ev
+ return (thetalist, not err)
+
+def IKinSpace(Slist, M, T, thetalist0, eomg, ev):
+ """Computes inverse kinematics in the space frame for an open chain robot
+
+ :param Slist: The joint screw axes in the space frame when the
+ manipulator is at the home position, in the format of a
+ matrix with axes as the columns
+ :param M: The home configuration of the end-effector
+ :param T: The desired end-effector configuration Tsd
+ :param thetalist0: An initial guess of joint angles that are close to
+ satisfying Tsd
+ :param eomg: A small positive tolerance on the end-effector orientation
+ error. The returned joint angles must give an end-effector
+ orientation error less than eomg
+ :param ev: A small positive tolerance on the end-effector linear position
+ error. The returned joint angles must give an end-effector
+ position error less than ev
+ :return thetalist: Joint angles that achieve T within the specified
+ tolerances,
+ :return success: A logical value where TRUE means that the function found
+ a solution and FALSE means that it ran through the set
+ number of maximum iterations without finding a solution
+ within the tolerances eomg and ev.
+ Uses an iterative Newton-Raphson root-finding method.
+ The maximum number of iterations before the algorithm is terminated has
+ been hardcoded in as a variable called maxiterations. It is set to 20 at
+ the start of the function, but can be changed if needed.
+
+ Example Input:
+ Slist = np.array([[0, 0, 1, 4, 0, 0],
+ [0, 0, 0, 0, 1, 0],
+ [0, 0, -1, -6, 0, -0.1]]).T
+ M = np.array([[-1, 0, 0, 0],
+ [ 0, 1, 0, 6],
+ [ 0, 0, -1, 2],
+ [ 0, 0, 0, 1]])
+ T = np.array([[0, 1, 0, -5],
+ [1, 0, 0, 4],
+ [0, 0, -1, 1.6858],
+ [0, 0, 0, 1]])
+ thetalist0 = np.array([1.5, 2.5, 3])
+ eomg = 0.01
+ ev = 0.001
+ Output:
+ (np.array([ 1.57073783, 2.99966384, 3.1415342 ]), True)
+ """
+ thetalist = np.array(thetalist0).copy()
+ i = 0
+ maxiterations = 20
+ Tsb = FKinSpace(M,Slist, thetalist)
+ Vs = np.dot(Adjoint(Tsb), \
+ se3ToVec(MatrixLog6(np.dot(TransInv(Tsb), T))))
+ err = np.linalg.norm([Vs[0], Vs[1], Vs[2]]) > eomg \
+ or np.linalg.norm([Vs[3], Vs[4], Vs[5]]) > ev
+ while err and i < maxiterations:
+ thetalist = thetalist \
+ + np.dot(np.linalg.pinv(JacobianSpace(Slist, \
+ thetalist)), Vs)
+ i = i + 1
+ Tsb = FKinSpace(M, Slist, thetalist)
+ Vs = np.dot(Adjoint(Tsb), \
+ se3ToVec(MatrixLog6(np.dot(TransInv(Tsb), T))))
+ err = np.linalg.norm([Vs[0], Vs[1], Vs[2]]) > eomg \
+ or np.linalg.norm([Vs[3], Vs[4], Vs[5]]) > ev
+ return (thetalist, not err)
+
+'''
+*** CHAPTER 8: DYNAMICS OF OPEN CHAINS ***
+'''
+
+def ad(V):
+ """Calculate the 6x6 matrix [adV] of the given 6-vector
+
+ :param V: A 6-vector spatial velocity
+ :return: The corresponding 6x6 matrix [adV]
+
+ Used to calculate the Lie bracket [V1, V2] = [adV1]V2
+
+ Example Input:
+ V = np.array([1, 2, 3, 4, 5, 6])
+ Output:
+ np.array([[ 0, -3, 2, 0, 0, 0],
+ [ 3, 0, -1, 0, 0, 0],
+ [-2, 1, 0, 0, 0, 0],
+ [ 0, -6, 5, 0, -3, 2],
+ [ 6, 0, -4, 3, 0, -1],
+ [-5, 4, 0, -2, 1, 0]])
+ """
+ omgmat = VecToso3([V[0], V[1], V[2]])
+ return np.r_[np.c_[omgmat, np.zeros((3, 3))],
+ np.c_[VecToso3([V[3], V[4], V[5]]), omgmat]]
+
+def InverseDynamics(thetalist, dthetalist, ddthetalist, g, Ftip, Mlist, \
+ Glist, Slist):
+ """Computes inverse dynamics in the space frame for an open chain robot
+
+ :param thetalist: n-vector of joint variables
+ :param dthetalist: n-vector of joint rates
+ :param ddthetalist: n-vector of joint accelerations
+ :param g: Gravity vector g
+ :param Ftip: Spatial force applied by the end-effector expressed in frame
+ {n+1}
+ :param Mlist: List of link frames {i} relative to {i-1} at the home
+ position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :return: The n-vector of required joint forces/torques
+ This function uses forward-backward Newton-Euler iterations to solve the
+ equation:
+ taulist = Mlist(thetalist)ddthetalist + c(thetalist,dthetalist) \
+ + g(thetalist) + Jtr(thetalist)Ftip
+
+ Example Input (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ ddthetalist = np.array([2, 1.5, 1])
+ g = np.array([0, 0, -9.8])
+ Ftip = np.array([1, 1, 1, 1, 1, 1])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ Output:
+ np.array([74.69616155, -33.06766016, -3.23057314])
+ """
+ n = len(thetalist)
+ Mi = np.eye(4)
+ Ai = np.zeros((6, n))
+ AdTi = [[None]] * (n + 1)
+ Vi = np.zeros((6, n + 1))
+ Vdi = np.zeros((6, n + 1))
+ Vdi[:, 0] = np.r_[[0, 0, 0], -np.array(g)]
+ AdTi[n] = Adjoint(TransInv(Mlist[n]))
+ Fi = np.array(Ftip).copy()
+ taulist = np.zeros(n)
+ for i in range(n):
+ Mi = np.dot(Mi,Mlist[i])
+ Ai[:, i] = np.dot(Adjoint(TransInv(Mi)), np.array(Slist)[:, i])
+ AdTi[i] = Adjoint(np.dot(MatrixExp6(VecTose3(Ai[:, i] * \
+ -thetalist[i])), \
+ TransInv(Mlist[i])))
+ Vi[:, i + 1] = np.dot(AdTi[i], Vi[:,i]) + Ai[:, i] * dthetalist[i]
+ Vdi[:, i + 1] = np.dot(AdTi[i], Vdi[:, i]) \
+ + Ai[:, i] * ddthetalist[i] \
+ + np.dot(ad(Vi[:, i + 1]), Ai[:, i]) * dthetalist[i]
+ for i in range (n - 1, -1, -1):
+ Fi = np.dot(np.array(AdTi[i + 1]).T, Fi) \
+ + np.dot(np.array(Glist[i]), Vdi[:, i + 1]) \
+ - np.dot(np.array(ad(Vi[:, i + 1])).T, \
+ np.dot(np.array(Glist[i]), Vi[:, i + 1]))
+ taulist[i] = np.dot(np.array(Fi).T, Ai[:, i])
+ return taulist
+
+def MassMatrix(thetalist, Mlist, Glist, Slist):
+ """Computes the mass matrix of an open chain robot based on the given
+ configuration
+
+ :param thetalist: A list of joint variables
+ :param Mlist: List of link frames i relative to i-1 at the home position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :return: The numerical inertia matrix M(thetalist) of an n-joint serial
+ chain at the given configuration thetalist
+ This function calls InverseDynamics n times, each time passing a
+ ddthetalist vector with a single element equal to one and all other
+ inputs set to zero.
+ Each call of InverseDynamics generates a single column, and these columns
+ are assembled to create the inertia matrix.
+
+ Example Input (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ Output:
+ np.array([[ 2.25433380e+01, -3.07146754e-01, -7.18426391e-03]
+ [-3.07146754e-01, 1.96850717e+00, 4.32157368e-01]
+ [-7.18426391e-03, 4.32157368e-01, 1.91630858e-01]])
+ """
+ n = len(thetalist)
+ M = np.zeros((n, n))
+ for i in range (n):
+ ddthetalist = [0] * n
+ ddthetalist[i] = 1
+ M[:, i] = InverseDynamics(thetalist, [0] * n, ddthetalist, \
+ [0, 0, 0], [0, 0, 0, 0, 0, 0], Mlist, \
+ Glist, Slist)
+ return M
+
+def VelQuadraticForces(thetalist, dthetalist, Mlist, Glist, Slist):
+ """Computes the Coriolis and centripetal terms in the inverse dynamics of
+ an open chain robot
+
+ :param thetalist: A list of joint variables,
+ :param dthetalist: A list of joint rates,
+ :param Mlist: List of link frames i relative to i-1 at the home position,
+ :param Glist: Spatial inertia matrices Gi of the links,
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns.
+ :return: The vector c(thetalist,dthetalist) of Coriolis and centripetal
+ terms for a given thetalist and dthetalist.
+ This function calls InverseDynamics with g = 0, Ftip = 0, and
+ ddthetalist = 0.
+
+ Example Input (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ Output:
+ np.array([0.26453118, -0.05505157, -0.00689132])
+ """
+ return InverseDynamics(thetalist, dthetalist, [0] * len(thetalist), \
+ [0, 0, 0], [0, 0, 0, 0, 0, 0], Mlist, Glist, \
+ Slist)
+
+def GravityForces(thetalist, g, Mlist, Glist, Slist):
+ """Computes the joint forces/torques an open chain robot requires to
+ overcome gravity at its configuration
+
+ :param thetalist: A list of joint variables
+ :param g: 3-vector for gravitational acceleration
+ :param Mlist: List of link frames i relative to i-1 at the home position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :return grav: The joint forces/torques required to overcome gravity at
+ thetalist
+ This function calls InverseDynamics with Ftip = 0, dthetalist = 0, and
+ ddthetalist = 0.
+
+ Example Inputs (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ g = np.array([0, 0, -9.8])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ Output:
+ np.array([28.40331262, -37.64094817, -5.4415892])
+ """
+ n = len(thetalist)
+ return InverseDynamics(thetalist, [0] * n, [0] * n, g, \
+ [0, 0, 0, 0, 0, 0], Mlist, Glist, Slist)
+
+def EndEffectorForces(thetalist, Ftip, Mlist, Glist, Slist):
+ """Computes the joint forces/torques an open chain robot requires only to
+ create the end-effector force Ftip
+
+ :param thetalist: A list of joint variables
+ :param Ftip: Spatial force applied by the end-effector expressed in frame
+ {n+1}
+ :param Mlist: List of link frames i relative to i-1 at the home position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :return: The joint forces and torques required only to create the
+ end-effector force Ftip
+ This function calls InverseDynamics with g = 0, dthetalist = 0, and
+ ddthetalist = 0.
+
+ Example Input (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ Ftip = np.array([1, 1, 1, 1, 1, 1])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ Output:
+ np.array([1.40954608, 1.85771497, 1.392409])
+ """
+ n = len(thetalist)
+ return InverseDynamics(thetalist, [0] * n, [0] * n, [0, 0, 0], Ftip, \
+ Mlist, Glist, Slist)
+
+def ForwardDynamics(thetalist, dthetalist, taulist, g, Ftip, Mlist, \
+ Glist, Slist):
+ """Computes forward dynamics in the space frame for an open chain robot
+
+ :param thetalist: A list of joint variables
+ :param dthetalist: A list of joint rates
+ :param taulist: An n-vector of joint forces/torques
+ :param g: Gravity vector g
+ :param Ftip: Spatial force applied by the end-effector expressed in frame
+ {n+1}
+ :param Mlist: List of link frames i relative to i-1 at the home position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :return: The resulting joint accelerations
+ This function computes ddthetalist by solving:
+ Mlist(thetalist) * ddthetalist = taulist - c(thetalist,dthetalist) \
+ - g(thetalist) - Jtr(thetalist) * Ftip
+
+ Example Input (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ taulist = np.array([0.5, 0.6, 0.7])
+ g = np.array([0, 0, -9.8])
+ Ftip = np.array([1, 1, 1, 1, 1, 1])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ Output:
+ np.array([-0.97392907, 25.58466784, -32.91499212])
+ """
+ return np.dot(np.linalg.inv(MassMatrix(thetalist, Mlist, Glist, \
+ Slist)), \
+ np.array(taulist) \
+ - VelQuadraticForces(thetalist, dthetalist, Mlist, \
+ Glist, Slist) \
+ - GravityForces(thetalist, g, Mlist, Glist, Slist) \
+ - EndEffectorForces(thetalist, Ftip, Mlist, Glist, \
+ Slist))
+
+def EulerStep(thetalist, dthetalist, ddthetalist, dt):
+ """Compute the joint angles and velocities at the next timestep using from here
+ first order Euler integration
+
+ :param thetalist: n-vector of joint variables
+ :param dthetalist: n-vector of joint rates
+ :param ddthetalist: n-vector of joint accelerations
+ :param dt: The timestep delta t
+ :return thetalistNext: Vector of joint variables after dt from first
+ order Euler integration
+ :return dthetalistNext: Vector of joint rates after dt from first order
+ Euler integration
+
+ Example Inputs (3 Link Robot):
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ ddthetalist = np.array([2, 1.5, 1])
+ dt = 0.1
+ Output:
+ thetalistNext:
+ array([ 0.11, 0.12, 0.13])
+ dthetalistNext:
+ array([ 0.3 , 0.35, 0.4 ])
+ """
+ return thetalist + dt * np.array(dthetalist), \
+ dthetalist + dt * np.array(ddthetalist)
+
+def InverseDynamicsTrajectory(thetamat, dthetamat, ddthetamat, g, \
+ Ftipmat, Mlist, Glist, Slist):
+ """Calculates the joint forces/torques required to move the serial chain
+ along the given trajectory using inverse dynamics
+
+ :param thetamat: An N x n matrix of robot joint variables
+ :param dthetamat: An N x n matrix of robot joint velocities
+ :param ddthetamat: An N x n matrix of robot joint accelerations
+ :param g: Gravity vector g
+ :param Ftipmat: An N x 6 matrix of spatial forces applied by the end-
+ effector (If there are no tip forces the user should
+ input a zero and a zero matrix will be used)
+ :param Mlist: List of link frames i relative to i-1 at the home position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :return: The N x n matrix of joint forces/torques for the specified
+ trajectory, where each of the N rows is the vector of joint
+ forces/torques at each time step
+
+ Example Inputs (3 Link Robot):
+ from __future__ import print_function
+ import numpy as np
+ import modern_robotics as mr
+ # Create a trajectory to follow using functions from Chapter 9
+ thetastart = np.array([0, 0, 0])
+ thetaend = np.array([np.pi / 2, np.pi / 2, np.pi / 2])
+ Tf = 3
+ N= 1000
+ method = 5
+ traj = mr.JointTrajectory(thetastart, thetaend, Tf, N, method)
+ thetamat = np.array(traj).copy()
+ dthetamat = np.zeros((1000,3 ))
+ ddthetamat = np.zeros((1000, 3))
+ dt = Tf / (N - 1.0)
+ for i in range(np.array(traj).shape[0] - 1):
+ dthetamat[i + 1, :] = (thetamat[i + 1, :] - thetamat[i, :]) / dt
+ ddthetamat[i + 1, :] \
+ = (dthetamat[i + 1, :] - dthetamat[i, :]) / dt
+ # Initialize robot description (Example with 3 links)
+ g = np.array([0, 0, -9.8])
+ Ftipmat = np.ones((N, 6))
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ taumat \
+ = mr.InverseDynamicsTrajectory(thetamat, dthetamat, ddthetamat, g, \
+ Ftipmat, Mlist, Glist, Slist)
+ # Output using matplotlib to plot the joint forces/torques
+ Tau1 = taumat[:, 0]
+ Tau2 = taumat[:, 1]
+ Tau3 = taumat[:, 2]
+ timestamp = np.linspace(0, Tf, N)
+ try:
+ import matplotlib.pyplot as plt
+ except:
+ print('The result will not be plotted due to a lack of package matplotlib')
+ else:
+ plt.plot(timestamp, Tau1, label = "Tau1")
+ plt.plot(timestamp, Tau2, label = "Tau2")
+ plt.plot(timestamp, Tau3, label = "Tau3")
+ plt.ylim (-40, 120)
+ plt.legend(loc = 'lower right')
+ plt.xlabel("Time")
+ plt.ylabel("Torque")
+ plt.title("Plot of Torque Trajectories")
+ plt.show()
+ """
+ thetamat = np.array(thetamat).T
+ dthetamat = np.array(dthetamat).T
+ ddthetamat = np.array(ddthetamat).T
+ Ftipmat = np.array(Ftipmat).T
+ taumat = np.array(thetamat).copy()
+ for i in range(np.array(thetamat).shape[1]):
+ taumat[:, i] \
+ = InverseDynamics(thetamat[:, i], dthetamat[:, i], \
+ ddthetamat[:, i], g, Ftipmat[:, i], Mlist, \
+ Glist, Slist)
+ taumat = np.array(taumat).T
+ return taumat
+
+def ForwardDynamicsTrajectory(thetalist, dthetalist, taumat, g, Ftipmat, \
+ Mlist, Glist, Slist, dt, intRes):
+ """Simulates the motion of a serial chain given an open-loop history of
+ joint forces/torques
+
+ :param thetalist: n-vector of initial joint variables
+ :param dthetalist: n-vector of initial joint rates
+ :param taumat: An N x n matrix of joint forces/torques, where each row is
+ the joint effort at any time step
+ :param g: Gravity vector g
+ :param Ftipmat: An N x 6 matrix of spatial forces applied by the end-
+ effector (If there are no tip forces the user should
+ input a zero and a zero matrix will be used)
+ :param Mlist: List of link frames {i} relative to {i-1} at the home
+ position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :param dt: The timestep between consecutive joint forces/torques
+ :param intRes: Integration resolution is the number of times integration
+ (Euler) takes places between each time step. Must be an
+ integer value greater than or equal to 1
+ :return thetamat: The N x n matrix of robot joint angles resulting from
+ the specified joint forces/torques
+ :return dthetamat: The N x n matrix of robot joint velocities
+ This function calls a numerical integration procedure that uses
+ ForwardDynamics.
+
+ Example Inputs (3 Link Robot):
+ from __future__ import print_function
+ import numpy as np
+ import modern_robotics as mr
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ taumat = np.array([[3.63, -6.58, -5.57], [3.74, -5.55, -5.5],
+ [4.31, -0.68, -5.19], [5.18, 5.63, -4.31],
+ [5.85, 8.17, -2.59], [5.78, 2.79, -1.7],
+ [4.99, -5.3, -1.19], [4.08, -9.41, 0.07],
+ [3.56, -10.1, 0.97], [3.49, -9.41, 1.23]])
+ # Initialize robot description (Example with 3 links)
+ g = np.array([0, 0, -9.8])
+ Ftipmat = np.ones((np.array(taumat).shape[0], 6))
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ dt = 0.1
+ intRes = 8
+ thetamat,dthetamat \
+ = mr.ForwardDynamicsTrajectory(thetalist, dthetalist, taumat, g, \
+ Ftipmat, Mlist, Glist, Slist, dt, \
+ intRes)
+ # Output using matplotlib to plot the joint angle/velocities
+ theta1 = thetamat[:, 0]
+ theta2 = thetamat[:, 1]
+ theta3 = thetamat[:, 2]
+ dtheta1 = dthetamat[:, 0]
+ dtheta2 = dthetamat[:, 1]
+ dtheta3 = dthetamat[:, 2]
+ N = np.array(taumat).shape[0]
+ Tf = np.array(taumat).shape[0] * dt
+ timestamp = np.linspace(0, Tf, N)
+ try:
+ import matplotlib.pyplot as plt
+ except:
+ print('The result will not be plotted due to a lack of package matplotlib')
+ else:
+ plt.plot(timestamp, theta1, label = "Theta1")
+ plt.plot(timestamp, theta2, label = "Theta2")
+ plt.plot(timestamp, theta3, label = "Theta3")
+ plt.plot(timestamp, dtheta1, label = "DTheta1")
+ plt.plot(timestamp, dtheta2, label = "DTheta2")
+ plt.plot(timestamp, dtheta3, label = "DTheta3")
+ plt.ylim (-12, 10)
+ plt.legend(loc = 'lower right')
+ plt.xlabel("Time")
+ plt.ylabel("Joint Angles/Velocities")
+ plt.title("Plot of Joint Angles and Joint Velocities")
+ plt.show()
+ """
+ taumat = np.array(taumat).T
+ Ftipmat = np.array(Ftipmat).T
+ thetamat = taumat.copy().astype(np.float)
+ thetamat[:, 0] = thetalist
+ dthetamat = taumat.copy().astype(np.float)
+ dthetamat[:, 0] = dthetalist
+ for i in range(np.array(taumat).shape[1] - 1):
+ for j in range(intRes):
+ ddthetalist \
+ = ForwardDynamics(thetalist, dthetalist, taumat[:, i], g, \
+ Ftipmat[:, i], Mlist, Glist, Slist)
+ thetalist,dthetalist = EulerStep(thetalist, dthetalist, \
+ ddthetalist, 1.0 * dt / intRes)
+ thetamat[:, i + 1] = thetalist
+ dthetamat[:, i + 1] = dthetalist
+ thetamat = np.array(thetamat).T
+ dthetamat = np.array(dthetamat).T
+ return thetamat, dthetamat
+
+'''
+*** CHAPTER 9: TRAJECTORY GENERATION ***
+'''
+
+def CubicTimeScaling(Tf, t):
+ """Computes s(t) for a cubic time scaling
+
+ :param Tf: Total time of the motion in seconds from rest to rest
+ :param t: The current time t satisfying 0 < t < Tf
+ :return: The path parameter s(t) corresponding to a third-order
+ polynomial motion that begins and ends at zero velocity
+
+ Example Input:
+ Tf = 2
+ t = 0.6
+ Output:
+ 0.216
+ """
+ return 3 * (1.0 * t / Tf) ** 2 - 2 * (1.0 * t / Tf) ** 3
+
+def QuinticTimeScaling(Tf, t):
+ """Computes s(t) for a quintic time scaling
+
+ :param Tf: Total time of the motion in seconds from rest to rest
+ :param t: The current time t satisfying 0 < t < Tf
+ :return: The path parameter s(t) corresponding to a fifth-order
+ polynomial motion that begins and ends at zero velocity and zero
+ acceleration
+
+ Example Input:
+ Tf = 2
+ t = 0.6
+ Output:
+ 0.16308
+ """
+ return 10 * (1.0 * t / Tf) ** 3 - 15 * (1.0 * t / Tf) ** 4 \
+ + 6 * (1.0 * t / Tf) ** 5
+
+def JointTrajectory(thetastart, thetaend, Tf, N, method):
+ """Computes a straight-line trajectory in joint space
+
+ :param thetastart: The initial joint variables
+ :param thetaend: The final joint variables
+ :param Tf: Total time of the motion in seconds from rest to rest
+ :param N: The number of points N > 1 (Start and stop) in the discrete
+ representation of the trajectory
+ :param method: The time-scaling method, where 3 indicates cubic (third-
+ order polynomial) time scaling and 5 indicates quintic
+ (fifth-order polynomial) time scaling
+ :return: A trajectory as an N x n matrix, where each row is an n-vector
+ of joint variables at an instant in time. The first row is
+ thetastart and the Nth row is thetaend . The elapsed time
+ between each row is Tf / (N - 1)
+
+ Example Input:
+ thetastart = np.array([1, 0, 0, 1, 1, 0.2, 0,1])
+ thetaend = np.array([1.2, 0.5, 0.6, 1.1, 2, 2, 0.9, 1])
+ Tf = 4
+ N = 6
+ method = 3
+ Output:
+ np.array([[ 1, 0, 0, 1, 1, 0.2, 0, 1]
+ [1.0208, 0.052, 0.0624, 1.0104, 1.104, 0.3872, 0.0936, 1]
+ [1.0704, 0.176, 0.2112, 1.0352, 1.352, 0.8336, 0.3168, 1]
+ [1.1296, 0.324, 0.3888, 1.0648, 1.648, 1.3664, 0.5832, 1]
+ [1.1792, 0.448, 0.5376, 1.0896, 1.896, 1.8128, 0.8064, 1]
+ [ 1.2, 0.5, 0.6, 1.1, 2, 2, 0.9, 1]])
+ """
+ N = int(N)
+ timegap = Tf / (N - 1.0)
+ traj = np.zeros((len(thetastart), N))
+ for i in range(N):
+ if method == 3:
+ s = CubicTimeScaling(Tf, timegap * i)
+ else:
+ s = QuinticTimeScaling(Tf, timegap * i)
+ traj[:, i] = s * np.array(thetaend) + (1 - s) * np.array(thetastart)
+ traj = np.array(traj).T
+ return traj
+
+def ScrewTrajectory(Xstart, Xend, Tf, N, method):
+ """Computes a trajectory as a list of N SE(3) matrices corresponding to
+ the screw motion about a space screw axis
+
+ :param Xstart: The initial end-effector configuration
+ :param Xend: The final end-effector configuration
+ :param Tf: Total time of the motion in seconds from rest to rest
+ :param N: The number of points N > 1 (Start and stop) in the discrete
+ representation of the trajectory
+ :param method: The time-scaling method, where 3 indicates cubic (third-
+ order polynomial) time scaling and 5 indicates quintic
+ (fifth-order polynomial) time scaling
+ :return: The discretized trajectory as a list of N matrices in SE(3)
+ separated in time by Tf/(N-1). The first in the list is Xstart
+ and the Nth is Xend
+
+ Example Input:
+ Xstart = np.array([[1, 0, 0, 1],
+ [0, 1, 0, 0],
+ [0, 0, 1, 1],
+ [0, 0, 0, 1]])
+ Xend = np.array([[0, 0, 1, 0.1],
+ [1, 0, 0, 0],
+ [0, 1, 0, 4.1],
+ [0, 0, 0, 1]])
+ Tf = 5
+ N = 4
+ method = 3
+ Output:
+ [np.array([[1, 0, 0, 1]
+ [0, 1, 0, 0]
+ [0, 0, 1, 1]
+ [0, 0, 0, 1]]),
+ np.array([[0.904, -0.25, 0.346, 0.441]
+ [0.346, 0.904, -0.25, 0.529]
+ [-0.25, 0.346, 0.904, 1.601]
+ [ 0, 0, 0, 1]]),
+ np.array([[0.346, -0.25, 0.904, -0.117]
+ [0.904, 0.346, -0.25, 0.473]
+ [-0.25, 0.904, 0.346, 3.274]
+ [ 0, 0, 0, 1]]),
+ np.array([[0, 0, 1, 0.1]
+ [1, 0, 0, 0]
+ [0, 1, 0, 4.1]
+ [0, 0, 0, 1]])]
+ """
+ N = int(N)
+ timegap = Tf / (N - 1.0)
+ traj = [[None]] * N
+ for i in range(N):
+ if method == 3:
+ s = CubicTimeScaling(Tf, timegap * i)
+ else:
+ s = QuinticTimeScaling(Tf, timegap * i)
+ traj[i] \
+ = np.dot(Xstart, MatrixExp6(MatrixLog6(np.dot(TransInv(Xstart), \
+ Xend)) * s))
+ return traj
+
+def CartesianTrajectory(Xstart, Xend, Tf, N, method):
+ """Computes a trajectory as a list of N SE(3) matrices corresponding to
+ the origin of the end-effector frame following a straight line
+
+ :param Xstart: The initial end-effector configuration
+ :param Xend: The final end-effector configuration
+ :param Tf: Total time of the motion in seconds from rest to rest
+ :param N: The number of points N > 1 (Start and stop) in the discrete
+ representation of the trajectory
+ :param method: The time-scaling method, where 3 indicates cubic (third-
+ order polynomial) time scaling and 5 indicates quintic
+ (fifth-order polynomial) time scaling
+ :return: The discretized trajectory as a list of N matrices in SE(3)
+ separated in time by Tf/(N-1). The first in the list is Xstart
+ and the Nth is Xend
+ This function is similar to ScrewTrajectory, except the origin of the
+ end-effector frame follows a straight line, decoupled from the rotational
+ motion.
+
+ Example Input:
+ Xstart = np.array([[1, 0, 0, 1],
+ [0, 1, 0, 0],
+ [0, 0, 1, 1],
+ [0, 0, 0, 1]])
+ Xend = np.array([[0, 0, 1, 0.1],
+ [1, 0, 0, 0],
+ [0, 1, 0, 4.1],
+ [0, 0, 0, 1]])
+ Tf = 5
+ N = 4
+ method = 5
+ Output:
+ [np.array([[1, 0, 0, 1]
+ [0, 1, 0, 0]
+ [0, 0, 1, 1]
+ [0, 0, 0, 1]]),
+ np.array([[ 0.937, -0.214, 0.277, 0.811]
+ [ 0.277, 0.937, -0.214, 0]
+ [-0.214, 0.277, 0.937, 1.651]
+ [ 0, 0, 0, 1]]),
+ np.array([[ 0.277, -0.214, 0.937, 0.289]
+ [ 0.937, 0.277, -0.214, 0]
+ [-0.214, 0.937, 0.277, 3.449]
+ [ 0, 0, 0, 1]]),
+ np.array([[0, 0, 1, 0.1]
+ [1, 0, 0, 0]
+ [0, 1, 0, 4.1]
+ [0, 0, 0, 1]])]
+ """
+ N = int(N)
+ timegap = Tf / (N - 1.0)
+ traj = [[None]] * N
+ Rstart, pstart = TransToRp(Xstart)
+ Rend, pend = TransToRp(Xend)
+ for i in range(N):
+ if method == 3:
+ s = CubicTimeScaling(Tf, timegap * i)
+ else:
+ s = QuinticTimeScaling(Tf, timegap * i)
+ traj[i] \
+ = np.r_[np.c_[np.dot(Rstart, \
+ MatrixExp3(MatrixLog3(np.dot(np.array(Rstart).T,Rend)) * s)), \
+ s * np.array(pend) + (1 - s) * np.array(pstart)], \
+ [[0, 0, 0, 1]]]
+ return traj
+
+'''
+*** CHAPTER 11: ROBOT CONTROL ***
+'''
+
+def ComputedTorque(thetalist, dthetalist, eint, g, Mlist, Glist, Slist, \
+ thetalistd, dthetalistd, ddthetalistd, Kp, Ki, Kd):
+ """Computes the joint control torques at a particular time instant
+
+ :param thetalist: n-vector of joint variables
+ :param dthetalist: n-vector of joint rates
+ :param eint: n-vector of the time-integral of joint errors
+ :param g: Gravity vector g
+ :param Mlist: List of link frames {i} relative to {i-1} at the home
+ position
+ :param Glist: Spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :param thetalistd: n-vector of reference joint variables
+ :param dthetalistd: n-vector of reference joint velocities
+ :param ddthetalistd: n-vector of reference joint accelerations
+ :param Kp: The feedback proportional gain (identical for each joint)
+ :param Ki: The feedback integral gain (identical for each joint)
+ :param Kd: The feedback derivative gain (identical for each joint)
+ :return: The vector of joint forces/torques computed by the feedback
+ linearizing controller at the current instant
+
+ Example Input:
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ eint = np.array([0.2, 0.2, 0.2])
+ g = np.array([0, 0, -9.8])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ thetalistd = np.array([1.0, 1.0, 1.0])
+ dthetalistd = np.array([2, 1.2, 2])
+ ddthetalistd = np.array([0.1, 0.1, 0.1])
+ Kp = 1.3
+ Ki = 1.2
+ Kd = 1.1
+ Output:
+ np.array([133.00525246, -29.94223324, -3.03276856])
+ """
+ e = np.subtract(thetalistd, thetalist)
+ return np.dot(MassMatrix(thetalist, Mlist, Glist, Slist), \
+ Kp * e + Ki * (np.array(eint) + e) \
+ + Kd * np.subtract(dthetalistd, dthetalist)) \
+ + InverseDynamics(thetalist, dthetalist, ddthetalistd, g, \
+ [0, 0, 0, 0, 0, 0], Mlist, Glist, Slist)
+
+def SimulateControl(thetalist, dthetalist, g, Ftipmat, Mlist, Glist, \
+ Slist, thetamatd, dthetamatd, ddthetamatd, gtilde, \
+ Mtildelist, Gtildelist, Kp, Ki, Kd, dt, intRes):
+ """Simulates the computed torque controller over a given desired
+ trajectory
+
+ :param thetalist: n-vector of initial joint variables
+ :param dthetalist: n-vector of initial joint velocities
+ :param g: Actual gravity vector g
+ :param Ftipmat: An N x 6 matrix of spatial forces applied by the end-
+ effector (If there are no tip forces the user should
+ input a zero and a zero matrix will be used)
+ :param Mlist: Actual list of link frames i relative to i-1 at the home
+ position
+ :param Glist: Actual spatial inertia matrices Gi of the links
+ :param Slist: Screw axes Si of the joints in a space frame, in the format
+ of a matrix with axes as the columns
+ :param thetamatd: An Nxn matrix of desired joint variables from the
+ reference trajectory
+ :param dthetamatd: An Nxn matrix of desired joint velocities
+ :param ddthetamatd: An Nxn matrix of desired joint accelerations
+ :param gtilde: The gravity vector based on the model of the actual robot
+ (actual values given above)
+ :param Mtildelist: The link frame locations based on the model of the
+ actual robot (actual values given above)
+ :param Gtildelist: The link spatial inertias based on the model of the
+ actual robot (actual values given above)
+ :param Kp: The feedback proportional gain (identical for each joint)
+ :param Ki: The feedback integral gain (identical for each joint)
+ :param Kd: The feedback derivative gain (identical for each joint)
+ :param dt: The timestep between points on the reference trajectory
+ :param intRes: Integration resolution is the number of times integration
+ (Euler) takes places between each time step. Must be an
+ integer value greater than or equal to 1
+ :return taumat: An Nxn matrix of the controllers commanded joint forces/
+ torques, where each row of n forces/torques corresponds
+ to a single time instant
+ :return thetamat: An Nxn matrix of actual joint angles
+ The end of this function plots all the actual and desired joint angles
+ using matplotlib and random libraries.
+
+ Example Input:
+ from __future__ import print_function
+ import numpy as np
+ from modern_robotics import JointTrajectory
+ thetalist = np.array([0.1, 0.1, 0.1])
+ dthetalist = np.array([0.1, 0.2, 0.3])
+ # Initialize robot description (Example with 3 links)
+ g = np.array([0, 0, -9.8])
+ M01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.089159],
+ [0, 0, 0, 1]])
+ M12 = np.array([[ 0, 0, 1, 0.28],
+ [ 0, 1, 0, 0.13585],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ M23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.1197],
+ [0, 0, 1, 0.395],
+ [0, 0, 0, 1]])
+ M34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.14225],
+ [0, 0, 0, 1]])
+ G1 = np.diag([0.010267, 0.010267, 0.00666, 3.7, 3.7, 3.7])
+ G2 = np.diag([0.22689, 0.22689, 0.0151074, 8.393, 8.393, 8.393])
+ G3 = np.diag([0.0494433, 0.0494433, 0.004095, 2.275, 2.275, 2.275])
+ Glist = np.array([G1, G2, G3])
+ Mlist = np.array([M01, M12, M23, M34])
+ Slist = np.array([[1, 0, 1, 0, 1, 0],
+ [0, 1, 0, -0.089, 0, 0],
+ [0, 1, 0, -0.089, 0, 0.425]]).T
+ dt = 0.01
+ # Create a trajectory to follow
+ thetaend = np.array([np.pi / 2, np.pi, 1.5 * np.pi])
+ Tf = 1
+ N = int(1.0 * Tf / dt)
+ method = 5
+ traj = mr.JointTrajectory(thetalist, thetaend, Tf, N, method)
+ thetamatd = np.array(traj).copy()
+ dthetamatd = np.zeros((N, 3))
+ ddthetamatd = np.zeros((N, 3))
+ dt = Tf / (N - 1.0)
+ for i in range(np.array(traj).shape[0] - 1):
+ dthetamatd[i + 1, :] \
+ = (thetamatd[i + 1, :] - thetamatd[i, :]) / dt
+ ddthetamatd[i + 1, :] \
+ = (dthetamatd[i + 1, :] - dthetamatd[i, :]) / dt
+ # Possibly wrong robot description (Example with 3 links)
+ gtilde = np.array([0.8, 0.2, -8.8])
+ Mhat01 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.1],
+ [0, 0, 0, 1]])
+ Mhat12 = np.array([[ 0, 0, 1, 0.3],
+ [ 0, 1, 0, 0.2],
+ [-1, 0, 0, 0],
+ [ 0, 0, 0, 1]])
+ Mhat23 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, -0.2],
+ [0, 0, 1, 0.4],
+ [0, 0, 0, 1]])
+ Mhat34 = np.array([[1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, 0.2],
+ [0, 0, 0, 1]])
+ Ghat1 = np.diag([0.1, 0.1, 0.1, 4, 4, 4])
+ Ghat2 = np.diag([0.3, 0.3, 0.1, 9, 9, 9])
+ Ghat3 = np.diag([0.1, 0.1, 0.1, 3, 3, 3])
+ Gtildelist = np.array([Ghat1, Ghat2, Ghat3])
+ Mtildelist = np.array([Mhat01, Mhat12, Mhat23, Mhat34])
+ Ftipmat = np.ones((np.array(traj).shape[0], 6))
+ Kp = 20
+ Ki = 10
+ Kd = 18
+ intRes = 8
+ taumat,thetamat \
+ = mr.SimulateControl(thetalist, dthetalist, g, Ftipmat, Mlist, \
+ Glist, Slist, thetamatd, dthetamatd, \
+ ddthetamatd, gtilde, Mtildelist, Gtildelist, \
+ Kp, Ki, Kd, dt, intRes)
+ """
+ Ftipmat = np.array(Ftipmat).T
+ thetamatd = np.array(thetamatd).T
+ dthetamatd = np.array(dthetamatd).T
+ ddthetamatd = np.array(ddthetamatd).T
+ m,n = np.array(thetamatd).shape
+ thetacurrent = np.array(thetalist).copy()
+ dthetacurrent = np.array(dthetalist).copy()
+ eint = np.zeros((m,1)).reshape(m,)
+ taumat = np.zeros(np.array(thetamatd).shape)
+ thetamat = np.zeros(np.array(thetamatd).shape)
+ for i in range(n):
+ taulist \
+ = ComputedTorque(thetacurrent, dthetacurrent, eint, gtilde, \
+ Mtildelist, Gtildelist, Slist, thetamatd[:, i], \
+ dthetamatd[:, i], ddthetamatd[:, i], Kp, Ki, Kd)
+ for j in range(intRes):
+ ddthetalist \
+ = ForwardDynamics(thetacurrent, dthetacurrent, taulist, g, \
+ Ftipmat[:, i], Mlist, Glist, Slist)
+ thetacurrent, dthetacurrent \
+ = EulerStep(thetacurrent, dthetacurrent, ddthetalist, \
+ 1.0 * dt / intRes)
+ taumat[:, i] = taulist
+ thetamat[:, i] = thetacurrent
+ eint = np.add(eint, dt * np.subtract(thetamatd[:, i], thetacurrent))
+ # Output using matplotlib to plot
+ try:
+ import matplotlib.pyplot as plt
+ except:
+ print('The result will not be plotted due to a lack of package matplotlib')
+ else:
+ links = np.array(thetamat).shape[0]
+ N = np.array(thetamat).shape[1]
+ Tf = N * dt
+ timestamp = np.linspace(0, Tf, N)
+ for i in range(links):
+ col = [np.random.uniform(0, 1), np.random.uniform(0, 1),
+ np.random.uniform(0, 1)]
+ plt.plot(timestamp, thetamat[i, :], "-", color=col, \
+ label = ("ActualTheta" + str(i + 1)))
+ plt.plot(timestamp, thetamatd[i, :], ".", color=col, \
+ label = ("DesiredTheta" + str(i + 1)))
+ plt.legend(loc = 'upper left')
+ plt.xlabel("Time")
+ plt.ylabel("Joint Angles")
+ plt.title("Plot of Actual and Desired Joint Angles")
+ plt.show()
+ taumat = np.array(taumat).T
+ thetamat = np.array(thetamat).T
+ return (taumat, thetamat)
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/complexCommandTest.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/complexCommandTest.py
new file mode 100644
index 0000000..f76fe2f
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/complexCommandTest.py
@@ -0,0 +1,59 @@
+# This example illustrates how to execute complex commands from
+# a remote API client. You can also use a similar construct for
+# commands that are not directly supported by the remote API.
+#
+# Load the demo scene 'remoteApiCommandServerExample.ttt' in CoppeliaSim, then
+# start the simulation and run this program.
+#
+# IMPORTANT: for each successful call to simxStart, there
+# should be a corresponding call to simxFinish at the end!
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import sys
+import ctypes
+print ('Program started')
+sim.simxFinish(-1) # just in case, close all opened connections
+clientID=sim.simxStart('127.0.0.1',19999,True,True,5000,5) # Connect to CoppeliaSim
+if clientID!=-1:
+ print ('Connected to remote API server')
+
+ # 1. First send a command to display a specific message in a dialog box:
+ emptyBuff = bytearray()
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'displayText_function',[],[],['Hello world!'],emptyBuff,sim.simx_opmode_blocking)
+ if res==sim.simx_return_ok:
+ print ('Return string: ',retStrings[0]) # display the reply from CoppeliaSim (in this case, just a string)
+ else:
+ print ('Remote function call failed')
+
+ # 2. Now create a dummy object at coordinate 0.1,0.2,0.3 with name 'MyDummyName':
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'createDummy_function',[],[0.1,0.2,0.3],['MyDummyName'],emptyBuff,sim.simx_opmode_blocking)
+ if res==sim.simx_return_ok:
+ print ('Dummy handle: ',retInts[0]) # display the reply from CoppeliaSim (in this case, the handle of the created dummy)
+ else:
+ print ('Remote function call failed')
+
+ # 3. Now send a code string to execute some random functions:
+ code="local octreeHandle=simCreateOctree(0.5,0,1)\n" \
+ "simInsertVoxelsIntoOctree(octreeHandle,0,{0.1,0.1,0.1},{255,0,255})\n" \
+ "return 'done'"
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,"remoteApiCommandServer",sim.sim_scripttype_childscript,'executeCode_function',[],[],[code],emptyBuff,sim.simx_opmode_blocking)
+ if res==sim.simx_return_ok:
+ print ('Code execution returned: ',retStrings[0])
+ else:
+ print ('Remote function call failed')
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(clientID)
+else:
+ print ('Failed connecting to remote API server')
+print ('Program ended')
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/depth_image_encoding.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/depth_image_encoding.py
new file mode 100644
index 0000000..5671298
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/depth_image_encoding.py
@@ -0,0 +1,229 @@
+"""Creates an image from a numpy array of floating point depth data.
+
+For details about the encoding see:
+https://sites.google.com/site/brainrobotdata/home/depth-image-encoding
+
+Examples:
+
+ depth_array is a 2D numpy array of floating point depth data in meters.
+
+ depth_rgb = FloatArrayToRgbImage(depth_array)
+ depth_rgb is a PIL Image object containing the same data as 24-bit
+ integers encoded in the RGB bytes.
+ depth_rgb.save('image_file.png') - to save to a file.
+
+ depth_array2 = ImageToFloatArray(depth_rgb)
+ depth_array2 is a 2D numpy array containing the same data as
+ depth_array up to the precision of the RGB image (1/256 mm).
+
+ depth_gray = FloatArrayToGrayImage(depth_array)
+ depth_gray is a PIL Image object containing the same data rounded to
+ 8-bit integers.
+ depth_gray.save('image_file.jpg', quality=95) - to save to a file.
+
+ depth_array3 = ImageToFloatArray(depth_gray)
+ depth_array3 is a 2D numpy array containing the same data as
+ depth_array up to the precision of the grayscale image (1 cm).
+
+The image conversions first scale and round the values and then pack
+them into the desired type in a numpy array before converting the
+array to a PIL Image object. The Image can be saved in any format.
+We are using PNG for RGB and high quality JPEG for grayscale images.
+
+You can use different numeric types (e.g. np.uint16, np.int32), but
+not all combinations of numeric type and image format are supported by
+PIL or standard image viewers.
+
+"""
+
+import numpy as np
+from PIL import Image
+from skimage import img_as_ubyte
+from skimage.color import grey2rgb
+
+
+def ClipFloatValues(float_array, min_value, max_value):
+ """Clips values to the range [min_value, max_value].
+
+ First checks if any values are out of range and prints a message.
+ Then clips all values to the given range.
+
+ Args:
+ float_array: 2D array of floating point values to be clipped.
+ min_value: Minimum value of clip range.
+ max_value: Maximum value of clip range.
+
+ Returns:
+ The clipped array.
+
+ """
+ if float_array.min() < min_value or float_array.max() > max_value:
+ print('Image has out-of-range values [%f,%f] not in [%d,%d]',
+ float_array.min(), float_array.max(), min_value, max_value)
+ float_array = np.clip(float_array, min_value, max_value)
+ return float_array
+
+
+DEFAULT_RGB_SCALE_FACTOR = 256000.0
+
+
+def FloatArrayToRgbImage(float_array,
+ scale_factor=DEFAULT_RGB_SCALE_FACTOR,
+ drop_blue=False):
+ """Convert a floating point array of values to an RGB image.
+
+ Convert floating point values to a fixed point representation where
+ the RGB bytes represent a 24-bit integer.
+ R is the high order byte.
+ B is the low order byte.
+ The precision of the depth image is 1/256 mm.
+
+ Floating point values are scaled so that the integer values cover
+ the representable range of depths.
+
+ This image representation should only use lossless compression.
+
+ Args:
+ float_array: Input array of floating point depth values in meters.
+ scale_factor: Scale value applied to all float values.
+ drop_blue: Zero out the blue channel to improve compression, results in 1mm
+ precision depth values.
+
+ Returns:
+ 24-bit RGB PIL Image object representing depth values.
+ """
+ float_array = np.squeeze(float_array)
+ # Scale the floating point array.
+ scaled_array = np.floor(float_array * scale_factor + 0.5)
+ # Convert the array to integer type and clip to representable range.
+ min_inttype = 0
+ max_inttype = 2**24 - 1
+ scaled_array = ClipFloatValues(scaled_array, min_inttype, max_inttype)
+ int_array = scaled_array.astype(np.uint32)
+ # Calculate:
+ # r = (f / 256) / 256 high byte
+ # g = (f / 256) % 256 middle byte
+ # b = f % 256 low byte
+ rg = np.divide(int_array, 256)
+ r = np.divide(rg, 256)
+ g = np.mod(rg, 256)
+ image_shape = int_array.shape
+ rgb_array = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)
+ rgb_array[..., 0] = r
+ rgb_array[..., 1] = g
+ if not drop_blue:
+ # Calculate the blue channel and add it to the array.
+ b = np.mod(int_array, 256)
+ rgb_array[..., 2] = b
+ image_mode = 'RGB'
+ image = Image.fromarray(rgb_array, mode=image_mode)
+ return image
+
+
+DEFAULT_GRAY_SCALE_FACTOR = {np.uint8: 100.0,
+ np.uint16: 1000.0,
+ np.int32: DEFAULT_RGB_SCALE_FACTOR}
+
+
+def FloatArrayToGrayImage(float_array, scale_factor=None, image_dtype=np.uint8):
+ """Convert a floating point array of values to an RGB image.
+
+ Convert floating point values to a fixed point representation with
+ the given bit depth.
+
+ The precision of the depth image with default scale_factor is:
+ uint8: 1cm, with a range of [0, 2.55m]
+ uint16: 1mm, with a range of [0, 65.5m]
+ int32: 1/256mm, with a range of [0, 8388m]
+
+ Right now, PIL turns uint16 images into a very strange format and
+ does not decode int32 images properly. Only uint8 works correctly.
+
+ Args:
+ float_array: Input array of floating point depth values in meters.
+ scale_factor: Scale value applied to all float values.
+ image_dtype: Image datatype, which controls the bit depth of the grayscale
+ image.
+
+ Returns:
+ Grayscale PIL Image object representing depth values.
+
+ """
+ # Ensure that we have a valid numeric type for the image.
+ if image_dtype == np.uint16:
+ image_mode = 'I;16'
+ elif image_dtype == np.int32:
+ image_mode = 'I'
+ else:
+ image_dtype = np.uint8
+ image_mode = 'L'
+ if scale_factor is None:
+ scale_factor = DEFAULT_GRAY_SCALE_FACTOR[image_dtype]
+ # Scale the floating point array.
+ scaled_array = np.floor(float_array * scale_factor + 0.5)
+ # Convert the array to integer type and clip to representable range.
+ min_dtype = np.iinfo(image_dtype).min
+ max_dtype = np.iinfo(image_dtype).max
+ scaled_array = ClipFloatValues(scaled_array, min_dtype, max_dtype)
+
+ image_array = scaled_array.astype(image_dtype)
+ image = Image.fromarray(image_array, mode=image_mode)
+ return image
+
+
+def ImageToFloatArray(image, scale_factor=None):
+ """Recovers the depth values from an image.
+
+ Reverses the depth to image conversion performed by FloatArrayToRgbImage or
+ FloatArrayToGrayImage.
+
+ The image is treated as an array of fixed point depth values. Each
+ value is converted to float and scaled by the inverse of the factor
+ that was used to generate the Image object from depth values. If
+ scale_factor is specified, it should be the same value that was
+ specified in the original conversion.
+
+ The result of this function should be equal to the original input
+ within the precision of the conversion.
+
+ For details see https://sites.google.com/site/brainrobotdata/home/depth-image-encoding.
+
+ Args:
+ image: Depth image output of FloatArrayTo[Format]Image.
+ scale_factor: Fixed point scale factor.
+
+ Returns:
+ A 2D floating point numpy array representing a depth image.
+
+ """
+ image_array = np.array(image)
+ image_dtype = image_array.dtype
+ image_shape = image_array.shape
+
+ channels = image_shape[2] if len(image_shape) > 2 else 1
+ assert 2 <= len(image_shape) <= 3
+ if channels == 3:
+ # RGB image needs to be converted to 24 bit integer.
+ float_array = np.sum(image_array * [65536, 256, 1], axis=2)
+ if scale_factor is None:
+ scale_factor = DEFAULT_RGB_SCALE_FACTOR
+ else:
+ if scale_factor is None:
+ scale_factor = DEFAULT_GRAY_SCALE_FACTOR[image_dtype.type]
+ float_array = image_array.astype(np.float32)
+ scaled_array = float_array / scale_factor
+ return scaled_array
+
+
+def FloatArrayToRawRGB(im, min_value=0.0, max_value=1.0):
+ """Convert a grayscale image to rgb, no encoding.
+
+ For proper display try matplotlib's rendering/conversion instead of this version.
+ Please be aware that this does not incorporate a proper color transform.
+ http://pillow.readthedocs.io/en/3.4.x/reference/Image.html#PIL.Image.Image.convert
+ https://en.wikipedia.org/wiki/Rec._601
+ """
+ im = img_as_ubyte(im)
+ if im.shape[-1] == 1:
+ im = grey2rgb(im)
+ return im
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/pController.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/pController.py
new file mode 100644
index 0000000..bdf55ae
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/pController.py
@@ -0,0 +1,104 @@
+# Make sure to have CoppeliaSim running, with followig scene loaded:
+#
+# scenes/pControllerViaRemoteApi.ttt
+#
+# Do not launch simulation, but run this script
+#
+# The client side (i.e. this script) depends on:
+#
+# sim.py, simConst.py, and the remote API library available
+# in programming/remoteApiBindings/lib/lib
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import math
+
+class Client:
+ def __enter__(self):
+ self.intSignalName='legacyRemoteApiStepCounter'
+ self.stepCounter=0
+ self.maxForce=100
+ sim.simxFinish(-1) # just in case, close all opened connections
+ self.id=sim.simxStart('127.0.0.1',19997,True,True,5000,5) # Connect to CoppeliaSim
+ return self
+
+ def __exit__(self,*err):
+ sim.simxFinish(-1)
+
+with Client() as client:
+ print("running")
+
+ if client.id!=-1:
+ print ('Connected to remote API server')
+
+ def stepSimulation():
+ currentStep=client.stepCounter
+ sim.simxSynchronousTrigger(client.id);
+ while client.stepCounter==currentStep:
+ retCode,s=sim.simxGetIntegerSignal(client.id,client.intSignalName,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ client.stepCounter=s
+
+ def getCurrentJointAngle():
+ retCode=-1
+ jointA=0
+ while retCode!=sim.simx_return_ok:
+ retCode,jointA=sim.simxGetJointPosition(client.id,client.jointHandle,sim.simx_opmode_buffer)
+ return jointA
+
+ def moveToAngle(targetAngle):
+ jointAngle=getCurrentJointAngle()
+ while abs(jointAngle-targetAngle)>0.1*math.pi/180:
+ stepSimulation()
+ jointAngle=getCurrentJointAngle()
+ vel=computeTargetVelocity(jointAngle,targetAngle)
+ sim.simxSetJointTargetVelocity(client.id,client.jointHandle,vel,sim.simx_opmode_oneshot)
+ sim.simxSetJointMaxForce(client.id,client.jointHandle,client.maxForce,sim.simx_opmode_oneshot)
+
+ def computeTargetVelocity(jointAngle,targetAngle):
+ dynStepSize=0.005
+ velUpperLimit=360*math.pi/180
+ PID_P=0.1
+ errorValue=targetAngle-jointAngle
+ sinAngle=math.sin(errorValue)
+ cosAngle=math.cos(errorValue)
+ errorValue=math.atan2(sinAngle,cosAngle)
+ ctrl=errorValue*PID_P
+
+ # Calculate the velocity needed to reach the position in one dynamic time step:
+ velocity=ctrl/dynStepSize
+ if (velocity>velUpperLimit):
+ velocity=velUpperLimit
+
+ if (velocity<-velUpperLimit):
+ velocity=-velUpperLimit
+
+ return velocity
+
+ # Start streaming client.intSignalName integer signal, that signals when a step is finished:
+ sim.simxGetIntegerSignal(client.id,client.intSignalName,sim.simx_opmode_streaming)
+
+ res,client.jointHandle=sim.simxGetObjectHandle(client.id,'joint',sim.simx_opmode_blocking)
+ sim.simxSetJointTargetVelocity(client.id,client.jointHandle,360*math.pi/180,sim.simx_opmode_oneshot)
+ sim.simxGetJointPosition(client.id,client.jointHandle,sim.simx_opmode_streaming)
+
+ # enable the synchronous mode on the client:
+ sim.simxSynchronous(client.id,True)
+
+ sim.simxStartSimulation(client.id,sim.simx_opmode_oneshot)
+
+ moveToAngle(45*math.pi/180)
+ moveToAngle(90*math.pi/180)
+ moveToAngle(-89*math.pi/180) #no -90, to avoid passing below
+ moveToAngle(0*math.pi/180)
+
+ sim.simxStopSimulation(client.id,sim.simx_opmode_blocking)
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/pathPlanningTest.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/pathPlanningTest.py
new file mode 100644
index 0000000..772ab46
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/pathPlanningTest.py
@@ -0,0 +1,160 @@
+# This example illustrates how to use the path/motion
+# planning functionality from a remote API client.
+#
+# Load the demo scene 'motionPlanningServerDemo.ttt' in CoppeliaSim
+# then run this program.
+#
+# IMPORTANT: for each successful call to simxStart, there
+# should be a corresponding call to simxFinish at the end!
+
+import sim
+
+print ('Program started')
+sim.simxFinish(-1) # just in case, close all opened connections
+clientID=sim.simxStart('127.0.0.1',19997,True,True,-500000,5) # Connect to CoppeliaSim, set a very large time-out for blocking commands
+if clientID!=-1:
+ print ('Connected to remote API server')
+
+ emptyBuff = bytearray()
+
+ # Start the simulation:
+ sim.simxStartSimulation(clientID,sim.simx_opmode_oneshot_wait)
+
+ # Load a robot instance: res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'loadRobot',[],[0,0,0,0],['d:/coppeliaRobotics/qrelease/release/test.ttm'],emptyBuff,sim.simx_opmode_oneshot_wait)
+ # robotHandle=retInts[0]
+
+ # Retrieve some handles:
+ res,robotHandle=sim.simxGetObjectHandle(clientID,'IRB4600#',sim.simx_opmode_oneshot_wait)
+ res,target1=sim.simxGetObjectHandle(clientID,'testPose1#',sim.simx_opmode_oneshot_wait)
+ res,target2=sim.simxGetObjectHandle(clientID,'testPose2#',sim.simx_opmode_oneshot_wait)
+ res,target3=sim.simxGetObjectHandle(clientID,'testPose3#',sim.simx_opmode_oneshot_wait)
+ res,target4=sim.simxGetObjectHandle(clientID,'testPose4#',sim.simx_opmode_oneshot_wait)
+
+ # Retrieve the poses (i.e. transformation matrices, 12 values, last row is implicit) of some dummies in the scene
+ res,retInts,target1Pose,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'getObjectPose',[target1],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ res,retInts,target2Pose,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'getObjectPose',[target2],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ res,retInts,target3Pose,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'getObjectPose',[target3],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ res,retInts,target4Pose,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'getObjectPose',[target4],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Get the robot initial state:
+ res,retInts,robotInitialState,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'getRobotState',[robotHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Some parameters:
+ approachVector=[0,0,1] # often a linear approach is required. This should also be part of the calculations when selecting an appropriate state for a given pose
+ maxConfigsForDesiredPose=10 # we will try to find 10 different states corresponding to the goal pose and order them according to distance from initial state
+ maxTrialsForConfigSearch=300 # a parameter needed for finding appropriate goal states
+ searchCount=2 # how many times OMPL will run for a given task
+ minConfigsForPathPlanningPath=400 # interpolation states for the OMPL path
+ minConfigsForIkPath=100 # interpolation states for the linear approach path
+ collisionChecking=1 # whether collision checking is on or off
+
+ # Display a message:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'displayMessage',[],[],['Computing and executing several path planning tasks for a given goal pose.&&nSeveral goal states corresponding to the goal pose are tested.&&nFeasability of a linear approach is also tested. Collision detection is on.'],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Do the path planning here (between a start state and a goal pose, including a linear approach phase):
+ inInts=[robotHandle,collisionChecking,minConfigsForIkPath,minConfigsForPathPlanningPath,maxConfigsForDesiredPose,maxTrialsForConfigSearch,searchCount]
+ inFloats=robotInitialState+target1Pose+approachVector
+ res,retInts,path,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'findPath_goalIsPose',inInts,inFloats,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ if (res==0) and len(path)>0:
+ # The path could be in 2 parts: a path planning path, and a linear approach path:
+ part1StateCnt=retInts[0]
+ part2StateCnt=retInts[1]
+ path1=path[:part1StateCnt*6]
+
+ # Visualize the first path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'visualizePath',[robotHandle,255,0,255],path1,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ line1Handle=retInts[0]
+
+ # Make the robot follow the path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'runThroughPath',[robotHandle],path1,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Wait until the end of the movement:
+ runningPath=True
+ while runningPath:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'isRunningThroughPath',[robotHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ runningPath=retInts[0]==1
+
+ path2=path[part1StateCnt*6:]
+
+ # Visualize the second path (the linear approach):
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'visualizePath',[robotHandle,0,255,0],path2,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ line2Handle=retInts[0]
+
+ # Make the robot follow the path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'runThroughPath',[robotHandle],path2,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Wait until the end of the movement:
+ runningPath=True
+ while runningPath:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'isRunningThroughPath',[robotHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ runningPath=retInts[0]==1
+
+ # Clear the paths visualizations:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'removeLine',[line1Handle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'removeLine',[line2Handle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Get the robot current state:
+ res,retInts,robotCurrentConfig,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'getRobotState',[robotHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Display a message:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'displayMessage',[],[],['Computing and executing several path planning tasks for a given goal state. Collision detection is on.'],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Do the path planning here (between a start state and a goal state):
+ inInts=[robotHandle,collisionChecking,minConfigsForPathPlanningPath,searchCount]
+ inFloats=robotCurrentConfig+robotInitialState
+ res,retInts,path,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'findPath_goalIsState',inInts,inFloats,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ if (res==0) and len(path)>0:
+ # Visualize the path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'visualizePath',[robotHandle,255,0,255],path,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ lineHandle=retInts[0]
+
+ # Make the robot follow the path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'runThroughPath',[robotHandle],path,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Wait until the end of the movement:
+ runningPath=True
+ while runningPath:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'isRunningThroughPath',[robotHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ runningPath=retInts[0]==1
+
+ # Clear the path visualization:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'removeLine',[lineHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Collision checking off:
+ collisionChecking=0
+
+ # Display a message:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'displayMessage',[],[],['Computing and executing several linear paths, going through several waypoints. Collision detection is OFF.'],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Find a linear path that runs through several poses:
+ inInts=[robotHandle,collisionChecking,minConfigsForIkPath]
+ inFloats=robotInitialState+target2Pose+target1Pose+target3Pose+target4Pose
+ res,retInts,path,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'findIkPath',inInts,inFloats,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ if (res==0) and len(path)>0:
+ # Visualize the path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'visualizePath',[robotHandle,0,255,255],path,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ line1Handle=retInts[0]
+
+ # Make the robot follow the path:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'runThroughPath',[robotHandle],path,[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Wait until the end of the movement:
+ runningPath=True
+ while runningPath:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'isRunningThroughPath',[robotHandle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+ runningPath=retInts[0]==1
+
+ # Clear the path visualization:
+ res,retInts,retFloats,retStrings,retBuffer=sim.simxCallScriptFunction(clientID,'remoteApiCommandServer',sim.sim_scripttype_childscript,'removeLine',[line1Handle],[],[],emptyBuff,sim.simx_opmode_oneshot_wait)
+
+ # Stop simulation:
+ sim.simxStopSimulation(clientID,sim.simx_opmode_oneshot_wait)
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(clientID)
+else:
+ print ('Failed connecting to remote API server')
+print ('Program ended')
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/ply.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/ply.py
new file mode 100644
index 0000000..fb2caa2
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/ply.py
@@ -0,0 +1,83 @@
+# MIT LICENSE
+# https://github.com/bponsler/kinectToPly/blob/master/kinectToPly.py
+import numpy as np
+
+
+class Ply(object):
+ '''The Ply class provides the ability to write a point cloud represented
+ by two arrays: an array of points (num points, 3), and an array of colors
+ (num points, 3) to a PLY file.
+ '''
+
+ def __init__(self, points, colors):
+ '''
+ * points -- The matrix of points (num points, 3)
+ * colors -- The matrix of colors (num points, 3)
+ '''
+ self.__points = points
+ self.__colors = colors
+
+ def write(self, filename):
+ '''Write the point cloud data to a PLY file of the given name.
+ * filename -- The PLY file
+ '''
+ # Write the headers
+ lines = self.__getLinesForHeader()
+
+ fd = open(filename, "w")
+ for line in lines:
+ fd.write("%s\n" % line)
+
+ # Write the points
+ self.__writePoints(fd, self.__points, self.__colors)
+
+ fd.close()
+
+ def __getLinesForHeader(self):
+ '''Get the list of lines for the PLY header.'''
+ lines = [
+ "ply",
+ "format ascii 1.0",
+ "comment generated by: kinectToPly",
+ "element vertex %s" % len(self.__points),
+ "property float x",
+ "property float y",
+ "property float z",
+ "property uchar red",
+ "property uchar green",
+ "property uchar blue",
+ "end_header",
+ ]
+
+ return lines
+
+ def __writePoints(self, fd, points, colors):
+ '''Write the point cloud points to a file.
+ * fd -- The file descriptor
+ * points -- The matrix of points (num points, 3)
+ * colors -- The matrix of colors (num points, 3)
+ '''
+ # Stack the two arrays together
+ stacked = np.column_stack((points, colors))
+
+ # Write the array to the file
+ np.savetxt(
+ fd,
+ stacked,
+ delimiter='\n',
+ fmt="%f %f %f %d %d %d")
+
+
+def write_xyz_rgb_as_ply(point_cloud, rgb_image, path):
+ """Write a point cloud with associated rgb image to a ply file
+
+ # Arguments
+
+ point_cloud: xyz point cloud in format [height, width, channels]
+ rgb_image: uint8 image in format [height, width, channels]
+ path: Where to save the file, ex: '/path/to/folder/file.ply'
+ """
+ xyz = point_cloud.reshape([point_cloud.size/3, 3])
+ rgb = np.squeeze(rgb_image).reshape([point_cloud.size/3, 3])
+ ply = Ply(xyz, rgb)
+ ply.write(path)
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/readMe.txt b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/readMe.txt
new file mode 100644
index 0000000..29933ef
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/readMe.txt
@@ -0,0 +1,6 @@
+Make sure you have following files in your directory, in order to run the various examples:
+
+1. sim.py
+2. simConst.py
+3. the appropriate remote API library: "remoteApi.dll" (Windows), "remoteApi.dylib" (Mac) or "remoteApi.so" (Linux)
+4. simpleTest.py (or any other example file)
\ No newline at end of file
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/remoteApi.dll b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/remoteApi.dll
new file mode 100644
index 0000000..d9fb676
Binary files /dev/null and b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/remoteApi.dll differ
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendMovementSequence-mov.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendMovementSequence-mov.py
new file mode 100644
index 0000000..68fe8ed
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendMovementSequence-mov.py
@@ -0,0 +1,103 @@
+# Make sure to have CoppeliaSim running, with followig scene loaded:
+#
+# scenes/movementViaRemoteApi.ttt
+#
+# Do not launch simulation, then run this script
+#
+# The client side (i.e. this script) depends on:
+#
+# sim.py, simConst.py, and the remote API library available
+# in programming/remoteApiBindings/lib/lib
+# Additionally you will need the python math and msgpack modules
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import math
+import msgpack
+
+print ('Program started')
+sim.simxFinish(-1) # just in case, close all opened connections
+clientID=sim.simxStart('127.0.0.1',19997,True,True,5000,5) # Connect to CoppeliaSim
+if clientID!=-1:
+ print ('Connected to remote API server')
+
+ executedMovId='notReady'
+
+ targetArm='threadedBlueArm'
+ #targetArm='nonThreadedRedArm'
+
+ stringSignalName=targetArm+'_executedMovId'
+
+ def waitForMovementExecuted(id):
+ global executedMovId
+ global stringSignalName
+ while executedMovId!=id:
+ retCode,s=sim.simxGetStringSignal(clientID,stringSignalName,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ executedMovId=s
+
+ # Start streaming stringSignalName string signal:
+ sim.simxGetStringSignal(clientID,stringSignalName,sim.simx_opmode_streaming)
+
+ # Set-up some movement variables:
+ mVel=100*math.pi/180
+ mAccel=150*math.pi/180
+ maxVel=[mVel,mVel,mVel,mVel,mVel,mVel]
+ maxAccel=[mAccel,mAccel,mAccel,mAccel,mAccel,mAccel]
+ targetVel=[0,0,0,0,0,0]
+
+ # Start simulation:
+ sim.simxStartSimulation(clientID,sim.simx_opmode_blocking)
+
+ # Wait until ready:
+ waitForMovementExecuted('ready')
+
+ # Send first movement sequence:
+ targetConfig=[90*math.pi/180,90*math.pi/180,-90*math.pi/180,90*math.pi/180,90*math.pi/180,90*math.pi/180]
+ movementData={"id":"movSeq1","type":"mov","targetConfig":targetConfig,"targetVel":targetVel,"maxVel":maxVel,"maxAccel":maxAccel}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+
+ # Execute first movement sequence:
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq1',sim.simx_opmode_oneshot)
+
+ # Wait until above movement sequence finished executing:
+ waitForMovementExecuted('movSeq1')
+
+ # Send second and third movement sequence, where third one should execute immediately after the second one:
+ targetConfig=[-90*math.pi/180,45*math.pi/180,90*math.pi/180,135*math.pi/180,90*math.pi/180,90*math.pi/180]
+ targetVel=[-60*math.pi/180,-20*math.pi/180,0,0,0,0]
+ movementData={"id":"movSeq2","type":"mov","targetConfig":targetConfig,"targetVel":targetVel,"maxVel":maxVel,"maxAccel":maxAccel}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+ targetConfig=[0,0,0,0,0,0]
+ targetVel=[0,0,0,0,0,0]
+ movementData={"id":"movSeq3","type":"mov","targetConfig":targetConfig,"targetVel":targetVel,"maxVel":maxVel,"maxAccel":maxAccel}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+
+ # Execute second and third movement sequence:
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq2',sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq3',sim.simx_opmode_oneshot)
+
+ # Wait until above 2 movement sequences finished executing:
+ waitForMovementExecuted('movSeq3')
+ sim.simxStopSimulation(clientID,sim.simx_opmode_blocking)
+ sim.simxGetStringSignal(clientID,stringSignalName,sim.simx_opmode_discontinue)
+ sim.simxGetPingTime(clientID)
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(clientID)
+else:
+ print ('Failed connecting to remote API server')
+print ('Program ended')
+
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendMovementSequence-pts.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendMovementSequence-pts.py
new file mode 100644
index 0000000..6d1e5ea
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendMovementSequence-pts.py
@@ -0,0 +1,96 @@
+# Make sure to have CoppeliaSim running, with followig scene loaded:
+#
+# scenes/movementViaRemoteApi.ttt
+#
+# Do not launch simulation, then run this script
+#
+# The client side (i.e. this script) depends on:
+#
+# sim.py, simConst.py, and the remote API library available
+# in programming/remoteApiBindings/lib/lib
+# Additionally you will need the python math and msgpack modules
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import time
+import math
+import msgpack
+
+print ('Program started')
+sim.simxFinish(-1) # just in case, close all opened connections
+clientID=sim.simxStart('127.0.0.1',19997,True,True,5000,5) # Connect to CoppeliaSim
+if clientID!=-1:
+ print ('Connected to remote API server')
+
+ executedMovId='notReady'
+
+ targetArm='threadedBlueArm'
+ #targetArm='nonThreadedRedArm'
+
+ stringSignalName=targetArm+'_executedMovId'
+
+ def waitForMovementExecuted(id):
+ global executedMovId
+ global stringSignalName
+ while executedMovId!=id:
+ retCode,s=sim.simxGetStringSignal(clientID,stringSignalName,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ executedMovId=s
+
+ # Start streaming stringSignalName string signal:
+ sim.simxGetStringSignal(clientID,stringSignalName,sim.simx_opmode_streaming)
+
+ # Set-up some movement variables:
+ times=[0.000,0.050,0.100,0.150,0.200,0.250,0.300,0.350,0.400,0.450,0.500,0.550,0.600,0.650,0.700,0.750,0.800,0.850,0.900,0.950,1.000,1.050,1.100,1.150,1.200,1.250,1.300,1.350,1.400,1.450,1.500,1.550,1.600,1.650,1.700,1.750,1.800,1.850]
+ j1=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.360,0.431,0.506,0.587,0.669,0.753,0.838,0.923,1.008,1.091,1.170,1.243,1.308,1.365,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.569,1.570,1.571,1.571,1.571]
+ j2=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.140,0.185,0.237,0.296,0.361,0.431,0.507,0.587,0.670,0.754,0.838,0.924,1.009,1.092,1.171,1.243,1.308,1.365,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.569,1.570,1.571,1.571,1.571]
+ j3=[0.000,0.000,-0.002,-0.009,-0.022,-0.042,-0.068,-0.100,-0.139,-0.185,-0.237,-0.296,-0.361,-0.433,-0.511,-0.595,-0.681,-0.767,-0.854,-0.942,-1.027,-1.107,-1.182,-1.249,-1.311,-1.365,-1.414,-1.455,-1.491,-1.519,-1.541,-1.557,-1.566,-1.569,-1.570,-1.571,-1.571,-1.571]
+ j4=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.361,0.433,0.511,0.595,0.681,0.768,0.855,0.942,1.027,1.107,1.181,1.249,1.310,1.365,1.413,1.455,1.490,1.519,1.541,1.556,1.565,1.569,1.570,1.570,1.570,1.571]
+ j5=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.361,0.433,0.511,0.595,0.681,0.768,0.855,0.942,1.028,1.108,1.182,1.250,1.311,1.366,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.569,1.570,1.571,1.571,1.571]
+ j6=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.361,0.433,0.511,0.595,0.681,0.768,0.855,0.942,1.027,1.108,1.182,1.249,1.311,1.365,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.569,1.570,1.571,1.571,1.571]
+
+ times=[0.000,0.050,0.100,0.150,0.200,0.250,0.300,0.350,0.400,0.450,0.500,0.550,0.600,0.650,0.700,0.750,0.800,0.850,0.900,0.950,1.000,1.050,1.100,1.150,1.200,1.250,1.300,1.350,1.400,1.450,1.500,1.550,1.600,1.650,1.700,1.750,1.800,1.850,1.900,1.950,2.000,2.050,2.100,2.150,2.200,2.250,2.300,2.350,2.400,2.450,2.500,2.550,2.600,2.650,2.700,2.750,2.800,2.850,2.900,2.950,3.000,3.050,3.100,3.150,3.200,3.250,3.300,3.350,3.400,3.450,3.500,3.550,3.600,3.650,3.700,3.750,3.800,3.850,3.900,3.950,4.000,4.050,4.100,4.150,4.200,4.250,4.300,4.350,4.400,4.450,4.500,4.550,4.600,4.650,4.700,4.750,4.800,4.850,4.900,4.950,5.000,5.050,5.100,5.150,5.200,5.250,5.300,5.350,5.400,5.450,5.500,5.550,5.600,5.650,5.700,5.750,5.800,5.850,5.900,5.950,6.000,6.050,6.100,6.150,6.200,6.250,6.300,6.350]
+ j1=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.360,0.431,0.506,0.587,0.669,0.753,0.838,0.923,1.008,1.091,1.170,1.243,1.308,1.365,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.564,1.556,1.543,1.524,1.498,1.465,1.426,1.380,1.328,1.270,1.205,1.136,1.065,0.994,0.922,0.849,0.777,0.705,0.632,0.560,0.487,0.415,0.342,0.270,0.197,0.125,0.053,-0.020,-0.092,-0.165,-0.237,-0.309,-0.382,-0.454,-0.527,-0.599,-0.671,-0.744,-0.816,-0.888,-0.961,-1.033,-1.106,-1.178,-1.250,-1.323,-1.394,-1.462,-1.523,-1.556,-1.595,-1.632,-1.664,-1.690,-1.709,-1.723,-1.729,-1.730,-1.723,-1.710,-1.691,-1.665,-1.632,-1.593,-1.548,-1.495,-1.437,-1.372,-1.302,-1.226,-1.146,-1.064,-0.980,-0.895,-0.810,-0.724,-0.638,-0.552,-0.469,-0.390,-0.318,-0.254,-0.199,-0.151,-0.110,-0.076,-0.048,-0.027,-0.012,-0.004,-0.001,-0.001,-0.000,-0.000,-0.000]
+ j2=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.140,0.185,0.237,0.296,0.361,0.431,0.507,0.587,0.670,0.754,0.838,0.924,1.009,1.092,1.171,1.243,1.308,1.365,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.564,1.557,1.544,1.529,1.513,1.497,1.481,1.465,1.449,1.432,1.416,1.400,1.384,1.367,1.351,1.335,1.319,1.303,1.286,1.270,1.254,1.238,1.221,1.205,1.189,1.173,1.157,1.140,1.124,1.108,1.092,1.075,1.059,1.043,1.027,1.010,0.994,0.978,0.961,0.945,0.929,0.913,0.896,0.880,0.864,0.848,0.831,0.815,0.799,0.786,0.769,0.749,0.730,0.710,0.689,0.669,0.649,0.629,0.609,0.589,0.569,0.548,0.528,0.508,0.488,0.468,0.448,0.427,0.407,0.387,0.367,0.347,0.327,0.306,0.286,0.266,0.246,0.226,0.206,0.186,0.166,0.146,0.125,0.105,0.084,0.064,0.044,0.025,0.012,0.004,0.001,0.000,0.000,0.000,0.000]
+ j3=[0.000,0.000,-0.002,-0.009,-0.022,-0.042,-0.068,-0.100,-0.139,-0.185,-0.237,-0.296,-0.361,-0.433,-0.511,-0.595,-0.681,-0.767,-0.854,-0.942,-1.027,-1.107,-1.182,-1.249,-1.311,-1.365,-1.414,-1.455,-1.491,-1.519,-1.541,-1.557,-1.566,-1.564,-1.556,-1.543,-1.524,-1.498,-1.465,-1.426,-1.381,-1.328,-1.270,-1.205,-1.133,-1.055,-0.971,-0.885,-0.798,-0.711,-0.624,-0.537,-0.450,-0.362,-0.275,-0.188,-0.101,-0.013,0.074,0.161,0.249,0.336,0.423,0.510,0.598,0.685,0.772,0.859,0.947,1.032,1.112,1.186,1.253,1.314,1.369,1.416,1.458,1.492,1.521,1.542,1.557,1.566,1.564,1.557,1.544,1.524,1.498,1.466,1.427,1.383,1.338,1.293,1.247,1.201,1.155,1.110,1.064,1.018,0.972,0.926,0.881,0.835,0.789,0.743,0.697,0.652,0.606,0.560,0.514,0.468,0.423,0.377,0.331,0.285,0.239,0.194,0.149,0.109,0.076,0.048,0.027,0.012,0.004,0.002,0.001,0.000,0.000,0.000]
+ j4=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.361,0.433,0.511,0.595,0.681,0.768,0.855,0.942,1.027,1.107,1.181,1.249,1.310,1.365,1.413,1.455,1.490,1.519,1.541,1.556,1.565,1.567,1.574,1.587,1.603,1.619,1.636,1.653,1.670,1.686,1.703,1.720,1.737,1.754,1.771,1.788,1.805,1.822,1.839,1.856,1.873,1.890,1.907,1.923,1.940,1.957,1.974,1.991,2.008,2.025,2.042,2.059,2.076,2.093,2.110,2.127,2.144,2.161,2.178,2.195,2.212,2.229,2.246,2.263,2.280,2.297,2.314,2.331,2.344,2.352,2.350,2.343,2.330,2.310,2.284,2.252,2.212,2.167,2.115,2.056,1.991,1.919,1.841,1.760,1.679,1.597,1.515,1.433,1.350,1.268,1.186,1.104,1.022,0.940,0.858,0.776,0.694,0.612,0.530,0.452,0.379,0.312,0.252,0.198,0.151,0.110,0.076,0.048,0.027,0.012,0.004,0.002,0.001,0.000,0.000,0.000]
+ j5=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.361,0.433,0.511,0.595,0.681,0.768,0.855,0.942,1.028,1.108,1.182,1.250,1.311,1.366,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.566,1.566,1.566,1.566,1.566,1.566,1.566,1.566,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.570,1.570,1.570,1.570,1.570,1.570,1.570,1.570,1.570,1.571,1.571,1.568,1.561,1.548,1.529,1.503,1.470,1.431,1.388,1.342,1.297,1.251,1.205,1.159,1.113,1.067,1.021,0.975,0.929,0.883,0.837,0.791,0.745,0.699,0.653,0.607,0.561,0.516,0.470,0.424,0.378,0.332,0.286,0.240,0.194,0.149,0.109,0.076,0.048,0.027,0.012,0.004,0.002,0.001,0.000,0.000,0.000]
+ j6=[0.000,0.000,0.002,0.009,0.022,0.042,0.068,0.100,0.139,0.185,0.237,0.296,0.361,0.433,0.511,0.595,0.681,0.768,0.855,0.942,1.027,1.108,1.182,1.249,1.311,1.365,1.414,1.455,1.491,1.519,1.541,1.557,1.566,1.566,1.566,1.566,1.566,1.566,1.566,1.566,1.566,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.567,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.568,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.569,1.570,1.570,1.570,1.570,1.570,1.570,1.570,1.570,1.570,1.571,1.571,1.571,1.569,1.561,1.548,1.529,1.503,1.470,1.431,1.388,1.343,1.297,1.251,1.205,1.159,1.113,1.067,1.021,0.975,0.929,0.883,0.837,0.791,0.745,0.699,0.653,0.607,0.561,0.515,0.470,0.424,0.378,0.332,0.286,0.240,0.194,0.149,0.109,0.076,0.048,0.027,0.012,0.004,0.002,0.001,0.000,0.000,0.000]
+
+ # Start simulation:
+ sim.simxStartSimulation(clientID,sim.simx_opmode_blocking)
+
+ # Wait until ready:
+ waitForMovementExecuted('ready')
+
+ # Send the movement sequence:
+ targetConfig=[90*math.pi/180,90*math.pi/180,-90*math.pi/180,90*math.pi/180,90*math.pi/180,90*math.pi/180]
+ movementData={"id":"movSeq1","type":"pts","times":times,"j1":j1,"j2":j2,"j3":j3,"j4":j4,"j5":j5,"j6":j6}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+
+ # Execute movement sequence:
+ sim.simxCallScriptFunction(clientID,targetArm,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq1',sim.simx_opmode_oneshot)
+
+ # Wait until above movement sequence finished executing:
+ waitForMovementExecuted('movSeq1')
+
+ sim.simxStopSimulation(clientID,sim.simx_opmode_blocking)
+ sim.simxGetIntegerSignal(clientID,integerSignalName,sim.simx_opmode_discontinue)
+ sim.simxGetPingTime(clientID)
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(clientID)
+else:
+ print ('Failed connecting to remote API server')
+print ('Program ended')
+
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendSimultan2MovementSequences-mov.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendSimultan2MovementSequences-mov.py
new file mode 100644
index 0000000..a251261
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sendSimultan2MovementSequences-mov.py
@@ -0,0 +1,129 @@
+# Make sure to have CoppeliaSim running, with followig scene loaded:
+#
+# scenes/movementViaRemoteApi.ttt
+#
+# Do not launch simulation, then run this script
+#
+# The client side (i.e. this script) depends on:
+#
+# sim.py, simConst.py, and the remote API library available
+# in programming/remoteApiBindings/lib/lib
+# Additionally you will need the python math and msgpack modules
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import math
+import msgpack
+
+class Client:
+ def __enter__(self):
+ self.executedMovId1='notReady'
+ self.executedMovId2='notReady'
+ sim.simxFinish(-1) # just in case, close all opened connections
+ self.id=sim.simxStart('127.0.0.1',19997,True,True,5000,5) # Connect to CoppeliaSim
+ return self
+
+ def __exit__(self,*err):
+ sim.simxFinish(-1)
+ print ('Program ended')
+
+with Client() as client:
+ print("running")
+
+ if client.id!=-1:
+ print ('Connected to remote API server')
+
+ targetArm1='threadedBlueArm'
+ targetArm2='nonThreadedRedArm'
+
+ client.stringSignalName1=targetArm1+'_executedMovId'
+ client.stringSignalName2=targetArm2+'_executedMovId'
+
+ def waitForMovementExecuted1(id):
+ while client.executedMovId1!=id:
+ retCode,s=sim.simxGetStringSignal(client.id,client.stringSignalName1,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ client.executedMovId1=s
+
+ def waitForMovementExecuted2(id):
+ while client.executedMovId2!=id:
+ retCode,s=sim.simxGetStringSignal(client.id,client.stringSignalName2,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ client.executedMovId2=s
+
+ # Start streaming client.stringSignalName1 and client.stringSignalName2 string signals:
+ sim.simxGetStringSignal(client.id,client.stringSignalName1,sim.simx_opmode_streaming)
+ sim.simxGetStringSignal(client.id,client.stringSignalName2,sim.simx_opmode_streaming)
+
+ # Set-up some movement variables:
+ mVel=100*math.pi/180
+ mAccel=150*math.pi/180
+ maxVel=[mVel,mVel,mVel,mVel,mVel,mVel]
+ maxAccel=[mAccel,mAccel,mAccel,mAccel,mAccel,mAccel]
+ targetVel=[0,0,0,0,0,0]
+
+ # Start simulation:
+ sim.simxStartSimulation(client.id,sim.simx_opmode_blocking)
+
+ # Wait until ready:
+ waitForMovementExecuted1('ready')
+ waitForMovementExecuted1('ready')
+
+ # Send first movement sequence:
+ targetConfig=[90*math.pi/180,90*math.pi/180,-90*math.pi/180,90*math.pi/180,90*math.pi/180,90*math.pi/180]
+ movementData={"id":"movSeq1","type":"mov","targetConfig":targetConfig,"targetVel":targetVel,"maxVel":maxVel,"maxAccel":maxAccel}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(client.id,targetArm1,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm2,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+
+ # Execute first movement sequence:
+ sim.simxCallScriptFunction(client.id,targetArm1,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq1',sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm2,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq1',sim.simx_opmode_oneshot)
+
+ # Wait until above movement sequence finished executing:
+ waitForMovementExecuted1('movSeq1')
+ waitForMovementExecuted1('movSeq1')
+
+ # Send second and third movement sequence, where third one should execute immediately after the second one:
+ targetConfig=[-90*math.pi/180,45*math.pi/180,90*math.pi/180,135*math.pi/180,90*math.pi/180,90*math.pi/180]
+ targetVel=[-60*math.pi/180,-20*math.pi/180,0,0,0,0]
+ movementData={"id":"movSeq2","type":"mov","targetConfig":targetConfig,"targetVel":targetVel,"maxVel":maxVel,"maxAccel":maxAccel}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(client.id,targetArm1,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm2,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+ targetConfig=[0,0,0,0,0,0]
+ targetVel=[0,0,0,0,0,0]
+ movementData={"id":"movSeq3","type":"mov","targetConfig":targetConfig,"targetVel":targetVel,"maxVel":maxVel,"maxAccel":maxAccel}
+ packedMovementData=msgpack.packb(movementData)
+ sim.simxCallScriptFunction(client.id,targetArm1,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm2,sim.sim_scripttype_childscript,'legacyRapiMovementDataFunction',[],[],[],packedMovementData,sim.simx_opmode_oneshot)
+
+ # Execute second and third movement sequence:
+ sim.simxCallScriptFunction(client.id,targetArm1,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq2',sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm2,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq2',sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm1,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq3',sim.simx_opmode_oneshot)
+ sim.simxCallScriptFunction(client.id,targetArm2,sim.sim_scripttype_childscript,'legacyRapiExecuteMovement',[],[],[],'movSeq3',sim.simx_opmode_oneshot)
+
+ # Wait until above 2 movement sequences finished executing:
+ waitForMovementExecuted1('movSeq3')
+ waitForMovementExecuted1('movSeq3')
+
+ sim.simxStopSimulation(client.id,sim.simx_opmode_blocking)
+ sim.simxGetStringSignal(client.id,client.stringSignalName1,sim.simx_opmode_discontinue)
+ sim.simxGetStringSignal(client.id,client.stringSignalName2,sim.simx_opmode_discontinue)
+ sim.simxGetPingTime(client.id)
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(client.id)
+ else:
+ print ('Failed connecting to remote API server')
+
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sim.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sim.py
new file mode 100644
index 0000000..b77fdf0
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/sim.py
@@ -0,0 +1,1493 @@
+import platform
+import struct
+import sys
+import os
+import ctypes as ct
+from simConst import *
+
+#load library
+libsimx = None
+try:
+ file_extension = '.so'
+ if platform.system() =='cli':
+ file_extension = '.dll'
+ elif platform.system() =='Windows':
+ file_extension = '.dll'
+ elif platform.system() == 'Darwin':
+ file_extension = '.dylib'
+ else:
+ file_extension = '.so'
+ libfullpath = os.path.join(os.path.dirname(__file__), 'remoteApi' + file_extension)
+ libsimx = ct.CDLL(libfullpath)
+except:
+ print ('----------------------------------------------------')
+ print ('The remoteApi library could not be loaded. Make sure')
+ print ('it is located in the same folder as "sim.py", or')
+ print ('appropriately adjust the file "sim.py"')
+ print ('----------------------------------------------------')
+ print ('')
+
+#ctypes wrapper prototypes
+c_GetJointPosition = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetJointPosition", libsimx))
+c_SetJointPosition = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetJointPosition", libsimx))
+c_GetJointMatrix = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetJointMatrix", libsimx))
+c_SetSphericalJointMatrix = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxSetSphericalJointMatrix", libsimx))
+c_SetJointTargetVelocity = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetJointTargetVelocity", libsimx))
+c_SetJointTargetPosition = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetJointTargetPosition", libsimx))
+c_GetJointForce = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetJointForce", libsimx))
+c_GetJointMaxForce = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetJointMaxForce", libsimx))
+c_SetJointForce = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetJointMaxForce", libsimx))
+c_SetJointMaxForce = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetJointMaxForce", libsimx))
+c_ReadForceSensor = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_ubyte), ct.POINTER(ct.c_float), ct.POINTER(ct.c_float), ct.c_int32)(("simxReadForceSensor", libsimx))
+c_BreakForceSensor = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32)(("simxBreakForceSensor", libsimx))
+c_ReadVisionSensor = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_ubyte), ct.POINTER(ct.POINTER(ct.c_float)), ct.POINTER(ct.POINTER(ct.c_int32)), ct.c_int32)(("simxReadVisionSensor", libsimx))
+c_GetObjectHandle = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetObjectHandle", libsimx))
+c_GetVisionSensorImage = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_byte)), ct.c_ubyte, ct.c_int32)(("simxGetVisionSensorImage", libsimx))
+c_SetVisionSensorImage = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_byte), ct.c_int32, ct.c_ubyte, ct.c_int32)(("simxSetVisionSensorImage", libsimx))
+c_GetVisionSensorDepthBuffer= ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_float)), ct.c_int32)(("simxGetVisionSensorDepthBuffer", libsimx))
+c_GetObjectChild = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetObjectChild", libsimx))
+c_GetObjectParent = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetObjectParent", libsimx))
+c_ReadProximitySensor = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_ubyte), ct.POINTER(ct.c_float), ct.POINTER(ct.c_int32), ct.POINTER(ct.c_float), ct.c_int32)(("simxReadProximitySensor", libsimx))
+c_LoadModel = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_ubyte, ct.POINTER(ct.c_int32), ct.c_int32)(("simxLoadModel", libsimx))
+c_LoadUI = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_ubyte, ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_int32)), ct.c_int32)(("simxLoadUI", libsimx))
+c_LoadScene = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_ubyte, ct.c_int32)(("simxLoadScene", libsimx))
+c_StartSimulation = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32)(("simxStartSimulation", libsimx))
+c_PauseSimulation = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32)(("simxPauseSimulation", libsimx))
+c_StopSimulation = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32)(("simxStopSimulation", libsimx))
+c_GetUIHandle = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetUIHandle", libsimx))
+c_GetUISlider = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetUISlider", libsimx))
+c_SetUISlider = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32)(("simxSetUISlider", libsimx))
+c_GetUIEventButton = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetUIEventButton", libsimx))
+c_GetUIButtonProperty = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetUIButtonProperty", libsimx))
+c_SetUIButtonProperty = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32)(("simxSetUIButtonProperty", libsimx))
+c_AddStatusbarMessage = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32)(("simxAddStatusbarMessage", libsimx))
+c_AuxiliaryConsoleOpen = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.c_int32), ct.POINTER(ct.c_float), ct.POINTER(ct.c_float), ct.POINTER(ct.c_int32), ct.c_int32)(("simxAuxiliaryConsoleOpen", libsimx))
+c_AuxiliaryConsoleClose = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32)(("simxAuxiliaryConsoleClose", libsimx))
+c_AuxiliaryConsolePrint = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32)(("simxAuxiliaryConsolePrint", libsimx))
+c_AuxiliaryConsoleShow = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_ubyte, ct.c_int32)(("simxAuxiliaryConsoleShow", libsimx))
+c_GetObjectOrientation = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetObjectOrientation", libsimx))
+c_GetObjectQuaternion = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetObjectQuaternion", libsimx))
+c_GetObjectPosition = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetObjectPosition", libsimx))
+c_SetObjectOrientation = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxSetObjectOrientation", libsimx))
+c_SetObjectQuaternion = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxSetObjectQuaternion", libsimx))
+c_SetObjectPosition = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxSetObjectPosition", libsimx))
+c_SetObjectParent = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_ubyte, ct.c_int32)(("simxSetObjectParent", libsimx))
+c_SetUIButtonLabel = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_char), ct.c_int32)(("simxSetUIButtonLabel", libsimx))
+c_GetLastErrors = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_char)), ct.c_int32)(("simxGetLastErrors", libsimx))
+c_GetArrayParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetArrayParameter", libsimx))
+c_SetArrayParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxSetArrayParameter", libsimx))
+c_GetBooleanParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_ubyte), ct.c_int32)(("simxGetBooleanParameter", libsimx))
+c_SetBooleanParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_ubyte, ct.c_int32)(("simxSetBooleanParameter", libsimx))
+c_GetIntegerParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetIntegerParameter", libsimx))
+c_SetIntegerParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32)(("simxSetIntegerParameter", libsimx))
+c_GetFloatingParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetFloatingParameter", libsimx))
+c_SetFloatingParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetFloatingParameter", libsimx))
+c_GetStringParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.POINTER(ct.c_char)), ct.c_int32)(("simxGetStringParameter", libsimx))
+c_GetCollisionHandle = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetCollisionHandle", libsimx))
+c_GetDistanceHandle = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetDistanceHandle", libsimx))
+c_GetCollectionHandle = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetCollectionHandle", libsimx))
+c_ReadCollision = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_ubyte), ct.c_int32)(("simxReadCollision", libsimx))
+c_ReadDistance = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxReadDistance", libsimx))
+c_RemoveObject = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32)(("simxRemoveObject", libsimx))
+c_RemoveModel = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32)(("simxRemoveModel", libsimx))
+c_RemoveUI = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32)(("simxRemoveUI", libsimx))
+c_CloseScene = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32)(("simxCloseScene", libsimx))
+c_GetObjects = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_int32)), ct.c_int32)(("simxGetObjects", libsimx))
+c_DisplayDialog = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_char), ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_float), ct.POINTER(ct.c_float), ct.POINTER(ct.c_int32), ct.POINTER(ct.c_int32), ct.c_int32)(("simxDisplayDialog", libsimx))
+c_EndDialog = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32)(("simxEndDialog", libsimx))
+c_GetDialogInput = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.POINTER(ct.c_char)), ct.c_int32)(("simxGetDialogInput", libsimx))
+c_GetDialogResult = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetDialogResult", libsimx))
+c_CopyPasteObjects = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32, ct.POINTER(ct.POINTER(ct.c_int32)), ct.POINTER(ct.c_int32), ct.c_int32)(("simxCopyPasteObjects", libsimx))
+c_GetObjectSelection = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.POINTER(ct.c_int32)), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetObjectSelection", libsimx))
+c_SetObjectSelection = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32, ct.c_int32)(("simxSetObjectSelection", libsimx))
+c_ClearFloatSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32)(("simxClearFloatSignal", libsimx))
+c_ClearIntegerSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32)(("simxClearIntegerSignal", libsimx))
+c_ClearStringSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32)(("simxClearStringSignal", libsimx))
+c_GetFloatSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_float), ct.c_int32)(("simxGetFloatSignal", libsimx))
+c_GetIntegerSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetIntegerSignal", libsimx))
+c_GetStringSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.POINTER(ct.c_ubyte)), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetStringSignal", libsimx))
+c_SetFloatSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_float, ct.c_int32)(("simxSetFloatSignal", libsimx))
+c_SetIntegerSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32, ct.c_int32)(("simxSetIntegerSignal", libsimx))
+c_SetStringSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_ubyte), ct.c_int32, ct.c_int32)(("simxSetStringSignal", libsimx))
+c_AppendStringSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_ubyte), ct.c_int32, ct.c_int32)(("simxAppendStringSignal", libsimx))
+c_WriteStringStream = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_ubyte), ct.c_int32, ct.c_int32)(("simxWriteStringStream", libsimx))
+c_GetObjectFloatParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.c_int32)(("simxGetObjectFloatParameter", libsimx))
+c_SetObjectFloatParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_float, ct.c_int32)(("simxSetObjectFloatParameter", libsimx))
+c_GetObjectIntParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetObjectIntParameter", libsimx))
+c_SetObjectIntParameter = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32)(("simxSetObjectIntParameter", libsimx))
+c_GetModelProperty = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetModelProperty", libsimx))
+c_SetModelProperty = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.c_int32)(("simxSetModelProperty", libsimx))
+c_Start = ct.CFUNCTYPE(ct.c_int32,ct.POINTER(ct.c_char), ct.c_int32, ct.c_ubyte, ct.c_ubyte, ct.c_int32, ct.c_int32)(("simxStart", libsimx))
+c_Finish = ct.CFUNCTYPE(None, ct.c_int32)(("simxFinish", libsimx))
+c_GetPingTime = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_int32))(("simxGetPingTime", libsimx))
+c_GetLastCmdTime = ct.CFUNCTYPE(ct.c_int32,ct.c_int32)(("simxGetLastCmdTime", libsimx))
+c_SynchronousTrigger = ct.CFUNCTYPE(ct.c_int32,ct.c_int32)(("simxSynchronousTrigger", libsimx))
+c_Synchronous = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_ubyte)(("simxSynchronous", libsimx))
+c_PauseCommunication = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_ubyte)(("simxPauseCommunication", libsimx))
+c_GetInMessageInfo = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32))(("simxGetInMessageInfo", libsimx))
+c_GetOutMessageInfo = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32))(("simxGetOutMessageInfo", libsimx))
+c_GetConnectionId = ct.CFUNCTYPE(ct.c_int32,ct.c_int32)(("simxGetConnectionId", libsimx))
+c_CreateBuffer = ct.CFUNCTYPE(ct.POINTER(ct.c_ubyte), ct.c_int32)(("simxCreateBuffer", libsimx))
+c_ReleaseBuffer = ct.CFUNCTYPE(None, ct.c_void_p)(("simxReleaseBuffer", libsimx))
+c_TransferFile = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_char), ct.c_int32, ct.c_int32)(("simxTransferFile", libsimx))
+c_EraseFile = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.c_int32)(("simxEraseFile", libsimx))
+c_GetAndClearStringSignal = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.POINTER(ct.c_ubyte)), ct.POINTER(ct.c_int32), ct.c_int32)(("simxGetAndClearStringSignal", libsimx))
+c_ReadStringStream = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.POINTER(ct.c_ubyte)), ct.POINTER(ct.c_int32), ct.c_int32)(("simxReadStringStream", libsimx))
+c_CreateDummy = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_float, ct.POINTER(ct.c_ubyte), ct.POINTER(ct.c_int32), ct.c_int32)(("simxCreateDummy", libsimx))
+c_Query = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.c_ubyte), ct.c_int32, ct.POINTER(ct.c_char), ct.POINTER(ct.POINTER(ct.c_ubyte)), ct.POINTER(ct.c_int32), ct.c_int32)(("simxQuery", libsimx))
+c_GetObjectGroupData = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.c_int32, ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_int32)), ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_int32)), ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_float)), ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_char)), ct.c_int32)(("simxGetObjectGroupData", libsimx))
+c_GetObjectVelocity = ct.CFUNCTYPE(ct.c_int32,ct.c_int32, ct.c_int32, ct.POINTER(ct.c_float), ct.POINTER(ct.c_float), ct.c_int32)(("simxGetObjectVelocity", libsimx))
+c_CallScriptFunction = ct.CFUNCTYPE(ct.c_int32,ct.c_int32,ct.POINTER(ct.c_char),ct.c_int32,ct.POINTER(ct.c_char),ct.c_int32,ct.POINTER(ct.c_int32),ct.c_int32,ct.POINTER(ct.c_float),ct.c_int32,ct.POINTER(ct.c_char),ct.c_int32,ct.POINTER(ct.c_ubyte),ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_int32)),ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_float)),ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_char)),ct.POINTER(ct.c_int32), ct.POINTER(ct.POINTER(ct.c_ubyte)),ct.c_int32)(("simxCallScriptFunction", libsimx))
+
+#API functions
+def simxGetJointPosition(clientID, jointHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ position = ct.c_float()
+ return c_GetJointPosition(clientID, jointHandle, ct.byref(position), operationMode), position.value
+
+def simxSetJointPosition(clientID, jointHandle, position, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetJointPosition(clientID, jointHandle, position, operationMode)
+
+def simxGetJointMatrix(clientID, jointHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ matrix = (ct.c_float*12)()
+ ret = c_GetJointMatrix(clientID, jointHandle, matrix, operationMode)
+ arr = []
+ for i in range(12):
+ arr.append(matrix[i])
+ return ret, arr
+
+def simxSetSphericalJointMatrix(clientID, jointHandle, matrix, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ matrix = (ct.c_float*12)(*matrix)
+ return c_SetSphericalJointMatrix(clientID, jointHandle, matrix, operationMode)
+
+def simxSetJointTargetVelocity(clientID, jointHandle, targetVelocity, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetJointTargetVelocity(clientID, jointHandle, targetVelocity, operationMode)
+
+def simxSetJointTargetPosition(clientID, jointHandle, targetPosition, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetJointTargetPosition(clientID, jointHandle, targetPosition, operationMode)
+
+def simxJointGetForce(clientID, jointHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ force = ct.c_float()
+ return c_GetJointForce(clientID, jointHandle, ct.byref(force), operationMode), force.value
+
+def simxGetJointForce(clientID, jointHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ force = ct.c_float()
+ return c_GetJointForce(clientID, jointHandle, ct.byref(force), operationMode), force.value
+
+def simxGetJointMaxForce(clientID, jointHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ force = ct.c_float()
+ return c_GetJointMaxForce(clientID, jointHandle, ct.byref(force), operationMode), force.value
+
+def simxSetJointForce(clientID, jointHandle, force, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ return c_SetJointMaxForce(clientID, jointHandle, force, operationMode)
+
+def simxSetJointMaxForce(clientID, jointHandle, force, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ return c_SetJointMaxForce(clientID, jointHandle, force, operationMode)
+
+def simxReadForceSensor(clientID, forceSensorHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ state = ct.c_ubyte()
+ forceVector = (ct.c_float*3)()
+ torqueVector = (ct.c_float*3)()
+ ret = c_ReadForceSensor(clientID, forceSensorHandle, ct.byref(state), forceVector, torqueVector, operationMode)
+ arr1 = []
+ for i in range(3):
+ arr1.append(forceVector[i])
+ arr2 = []
+ for i in range(3):
+ arr2.append(torqueVector[i])
+ #if sys.version_info[0] == 3:
+ # state=state.value
+ #else:
+ # state=ord(state.value)
+ return ret, state.value, arr1, arr2
+
+def simxBreakForceSensor(clientID, forceSensorHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ return c_BreakForceSensor(clientID, forceSensorHandle, operationMode)
+
+def simxReadVisionSensor(clientID, sensorHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ detectionState = ct.c_ubyte()
+ auxValues = ct.POINTER(ct.c_float)()
+ auxValuesCount = ct.POINTER(ct.c_int)()
+ ret = c_ReadVisionSensor(clientID, sensorHandle, ct.byref(detectionState), ct.byref(auxValues), ct.byref(auxValuesCount), operationMode)
+
+ auxValues2 = []
+ if ret == 0:
+ s = 0
+ for i in range(auxValuesCount[0]):
+ auxValues2.append(auxValues[s:s+auxValuesCount[i+1]])
+ s += auxValuesCount[i+1]
+
+ #free C buffers
+ c_ReleaseBuffer(auxValues)
+ c_ReleaseBuffer(auxValuesCount)
+
+ return ret, bool(detectionState.value!=0), auxValues2
+
+def simxGetObjectHandle(clientID, objectName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ handle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(objectName) is str):
+ objectName=objectName.encode('utf-8')
+ return c_GetObjectHandle(clientID, objectName, ct.byref(handle), operationMode), handle.value
+
+def simxGetVisionSensorImage(clientID, sensorHandle, options, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ resolution = (ct.c_int*2)()
+ c_image = ct.POINTER(ct.c_byte)()
+ bytesPerPixel = 3
+ if (options and 1) != 0:
+ bytesPerPixel = 1
+ ret = c_GetVisionSensorImage(clientID, sensorHandle, resolution, ct.byref(c_image), options, operationMode)
+
+ reso = []
+ image = []
+ if (ret == 0):
+ image = [None]*resolution[0]*resolution[1]*bytesPerPixel
+ for i in range(resolution[0] * resolution[1] * bytesPerPixel):
+ image[i] = c_image[i]
+ for i in range(2):
+ reso.append(resolution[i])
+ return ret, reso, image
+
+def simxSetVisionSensorImage(clientID, sensorHandle, image, options, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ size = len(image)
+ image_bytes = (ct.c_byte*size)(*image)
+ return c_SetVisionSensorImage(clientID, sensorHandle, image_bytes, size, options, operationMode)
+
+def simxGetVisionSensorDepthBuffer(clientID, sensorHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ c_buffer = ct.POINTER(ct.c_float)()
+ resolution = (ct.c_int*2)()
+ ret = c_GetVisionSensorDepthBuffer(clientID, sensorHandle, resolution, ct.byref(c_buffer), operationMode)
+ reso = []
+ buffer = []
+ if (ret == 0):
+ buffer = [None]*resolution[0]*resolution[1]
+ for i in range(resolution[0] * resolution[1]):
+ buffer[i] = c_buffer[i]
+ for i in range(2):
+ reso.append(resolution[i])
+ return ret, reso, buffer
+
+def simxGetObjectChild(clientID, parentObjectHandle, childIndex, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ childObjectHandle = ct.c_int()
+ return c_GetObjectChild(clientID, parentObjectHandle, childIndex, ct.byref(childObjectHandle), operationMode), childObjectHandle.value
+
+def simxGetObjectParent(clientID, childObjectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ parentObjectHandle = ct.c_int()
+ return c_GetObjectParent(clientID, childObjectHandle, ct.byref(parentObjectHandle), operationMode), parentObjectHandle.value
+
+def simxReadProximitySensor(clientID, sensorHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ detectionState = ct.c_ubyte()
+ detectedObjectHandle = ct.c_int()
+ detectedPoint = (ct.c_float*3)()
+ detectedSurfaceNormalVector = (ct.c_float*3)()
+ ret = c_ReadProximitySensor(clientID, sensorHandle, ct.byref(detectionState), detectedPoint, ct.byref(detectedObjectHandle), detectedSurfaceNormalVector, operationMode)
+ arr1 = []
+ for i in range(3):
+ arr1.append(detectedPoint[i])
+ arr2 = []
+ for i in range(3):
+ arr2.append(detectedSurfaceNormalVector[i])
+ return ret, bool(detectionState.value!=0), arr1, detectedObjectHandle.value, arr2
+
+def simxLoadModel(clientID, modelPathAndName, options, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ baseHandle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(modelPathAndName) is str):
+ modelPathAndName=modelPathAndName.encode('utf-8')
+ return c_LoadModel(clientID, modelPathAndName, options, ct.byref(baseHandle), operationMode), baseHandle.value
+
+def simxLoadUI(clientID, uiPathAndName, options, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ count = ct.c_int()
+ uiHandles = ct.POINTER(ct.c_int)()
+ if (sys.version_info[0] == 3) and (type(uiPathAndName) is str):
+ uiPathAndName=uiPathAndName.encode('utf-8')
+ ret = c_LoadUI(clientID, uiPathAndName, options, ct.byref(count), ct.byref(uiHandles), operationMode)
+
+ handles = []
+ if ret == 0:
+ for i in range(count.value):
+ handles.append(uiHandles[i])
+ #free C buffers
+ c_ReleaseBuffer(uiHandles)
+
+ return ret, handles
+
+def simxLoadScene(clientID, scenePathAndName, options, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(scenePathAndName) is str):
+ scenePathAndName=scenePathAndName.encode('utf-8')
+ return c_LoadScene(clientID, scenePathAndName, options, operationMode)
+
+def simxStartSimulation(clientID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_StartSimulation(clientID, operationMode)
+
+def simxPauseSimulation(clientID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_PauseSimulation(clientID, operationMode)
+
+def simxStopSimulation(clientID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_StopSimulation(clientID, operationMode)
+
+def simxGetUIHandle(clientID, uiName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ handle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(uiName) is str):
+ uiName=uiName.encode('utf-8')
+ return c_GetUIHandle(clientID, uiName, ct.byref(handle), operationMode), handle.value
+
+def simxGetUISlider(clientID, uiHandle, uiButtonID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ position = ct.c_int()
+ return c_GetUISlider(clientID, uiHandle, uiButtonID, ct.byref(position), operationMode), position.value
+
+def simxSetUISlider(clientID, uiHandle, uiButtonID, position, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetUISlider(clientID, uiHandle, uiButtonID, position, operationMode)
+
+def simxGetUIEventButton(clientID, uiHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ uiEventButtonID = ct.c_int()
+ auxValues = (ct.c_int*2)()
+ ret = c_GetUIEventButton(clientID, uiHandle, ct.byref(uiEventButtonID), auxValues, operationMode)
+ arr = []
+ for i in range(2):
+ arr.append(auxValues[i])
+ return ret, uiEventButtonID.value, arr
+
+def simxGetUIButtonProperty(clientID, uiHandle, uiButtonID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ prop = ct.c_int()
+ return c_GetUIButtonProperty(clientID, uiHandle, uiButtonID, ct.byref(prop), operationMode), prop.value
+
+def simxSetUIButtonProperty(clientID, uiHandle, uiButtonID, prop, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetUIButtonProperty(clientID, uiHandle, uiButtonID, prop, operationMode)
+
+def simxAddStatusbarMessage(clientID, message, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(message) is str):
+ message=message.encode('utf-8')
+ return c_AddStatusbarMessage(clientID, message, operationMode)
+
+def simxAuxiliaryConsoleOpen(clientID, title, maxLines, mode, position, size, textColor, backgroundColor, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ consoleHandle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(title) is str):
+ title=title.encode('utf-8')
+ if position != None:
+ c_position = (ct.c_int*2)(*position)
+ else:
+ c_position = None
+ if size != None:
+ c_size = (ct.c_int*2)(*size)
+ else:
+ c_size = None
+ if textColor != None:
+ c_textColor = (ct.c_float*3)(*textColor)
+ else:
+ c_textColor = None
+ if backgroundColor != None:
+ c_backgroundColor = (ct.c_float*3)(*backgroundColor)
+ else:
+ c_backgroundColor = None
+ return c_AuxiliaryConsoleOpen(clientID, title, maxLines, mode, c_position, c_size, c_textColor, c_backgroundColor, ct.byref(consoleHandle), operationMode), consoleHandle.value
+
+def simxAuxiliaryConsoleClose(clientID, consoleHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_AuxiliaryConsoleClose(clientID, consoleHandle, operationMode)
+
+def simxAuxiliaryConsolePrint(clientID, consoleHandle, txt, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(txt) is str):
+ txt=txt.encode('utf-8')
+ return c_AuxiliaryConsolePrint(clientID, consoleHandle, txt, operationMode)
+
+def simxAuxiliaryConsoleShow(clientID, consoleHandle, showState, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_AuxiliaryConsoleShow(clientID, consoleHandle, showState, operationMode)
+
+def simxGetObjectOrientation(clientID, objectHandle, relativeToObjectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ eulerAngles = (ct.c_float*3)()
+ ret = c_GetObjectOrientation(clientID, objectHandle, relativeToObjectHandle, eulerAngles, operationMode)
+ arr = []
+ for i in range(3):
+ arr.append(eulerAngles[i])
+ return ret, arr
+
+def simxGetObjectQuaternion(clientID, objectHandle, relativeToObjectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ quaternion = (ct.c_float*4)()
+ ret = c_GetObjectQuaternion(clientID, objectHandle, relativeToObjectHandle, quaternion, operationMode)
+ arr = []
+ for i in range(4):
+ arr.append(quaternion[i])
+ return ret, arr
+
+def simxGetObjectPosition(clientID, objectHandle, relativeToObjectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ position = (ct.c_float*3)()
+ ret = c_GetObjectPosition(clientID, objectHandle, relativeToObjectHandle, position, operationMode)
+ arr = []
+ for i in range(3):
+ arr.append(position[i])
+ return ret, arr
+
+def simxSetObjectOrientation(clientID, objectHandle, relativeToObjectHandle, eulerAngles, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ angles = (ct.c_float*3)(*eulerAngles)
+ return c_SetObjectOrientation(clientID, objectHandle, relativeToObjectHandle, angles, operationMode)
+
+def simxSetObjectQuaternion(clientID, objectHandle, relativeToObjectHandle, quaternion, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ quat = (ct.c_float*4)(*quaternion)
+ return c_SetObjectQuaternion(clientID, objectHandle, relativeToObjectHandle, quat, operationMode)
+
+def simxSetObjectPosition(clientID, objectHandle, relativeToObjectHandle, position, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ c_position = (ct.c_float*3)(*position)
+ return c_SetObjectPosition(clientID, objectHandle, relativeToObjectHandle, c_position, operationMode)
+
+def simxSetObjectParent(clientID, objectHandle, parentObject, keepInPlace, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetObjectParent(clientID, objectHandle, parentObject, keepInPlace, operationMode)
+
+def simxSetUIButtonLabel(clientID, uiHandle, uiButtonID, upStateLabel, downStateLabel, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if sys.version_info[0] == 3:
+ if type(upStateLabel) is str:
+ upStateLabel=upStateLabel.encode('utf-8')
+ if type(downStateLabel) is str:
+ downStateLabel=downStateLabel.encode('utf-8')
+ return c_SetUIButtonLabel(clientID, uiHandle, uiButtonID, upStateLabel, downStateLabel, operationMode)
+
+def simxGetLastErrors(clientID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ errors =[]
+ errorCnt = ct.c_int()
+ errorStrings = ct.POINTER(ct.c_char)()
+ ret = c_GetLastErrors(clientID, ct.byref(errorCnt), ct.byref(errorStrings), operationMode)
+ if ret == 0:
+ s = 0
+ for i in range(errorCnt.value):
+ a = bytearray()
+ while errorStrings[s] != b'\0':
+ if sys.version_info[0] == 3:
+ a.append(int.from_bytes(errorStrings[s],'big'))
+ else:
+ a.append(errorStrings[s])
+ s += 1
+ s += 1 #skip null
+ if sys.version_info[0] == 3:
+ errors.append(str(a,'utf-8'))
+ else:
+ errors.append(str(a))
+
+ return ret, errors
+
+def simxGetArrayParameter(clientID, paramIdentifier, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ paramValues = (ct.c_float*3)()
+ ret = c_GetArrayParameter(clientID, paramIdentifier, paramValues, operationMode)
+ arr = []
+ for i in range(3):
+ arr.append(paramValues[i])
+ return ret, arr
+
+def simxSetArrayParameter(clientID, paramIdentifier, paramValues, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ c_paramValues = (ct.c_float*3)(*paramValues)
+ return c_SetArrayParameter(clientID, paramIdentifier, c_paramValues, operationMode)
+
+def simxGetBooleanParameter(clientID, paramIdentifier, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ paramValue = ct.c_ubyte()
+ return c_GetBooleanParameter(clientID, paramIdentifier, ct.byref(paramValue), operationMode), bool(paramValue.value!=0)
+
+def simxSetBooleanParameter(clientID, paramIdentifier, paramValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetBooleanParameter(clientID, paramIdentifier, paramValue, operationMode)
+
+def simxGetIntegerParameter(clientID, paramIdentifier, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ paramValue = ct.c_int()
+ return c_GetIntegerParameter(clientID, paramIdentifier, ct.byref(paramValue), operationMode), paramValue.value
+
+def simxSetIntegerParameter(clientID, paramIdentifier, paramValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetIntegerParameter(clientID, paramIdentifier, paramValue, operationMode)
+
+def simxGetFloatingParameter(clientID, paramIdentifier, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ paramValue = ct.c_float()
+ return c_GetFloatingParameter(clientID, paramIdentifier, ct.byref(paramValue), operationMode), paramValue.value
+
+def simxSetFloatingParameter(clientID, paramIdentifier, paramValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetFloatingParameter(clientID, paramIdentifier, paramValue, operationMode)
+
+def simxGetStringParameter(clientID, paramIdentifier, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ paramValue = ct.POINTER(ct.c_char)()
+ ret = c_GetStringParameter(clientID, paramIdentifier, ct.byref(paramValue), operationMode)
+
+ a = bytearray()
+ if ret == 0:
+ i = 0
+ while paramValue[i] != b'\0':
+ if sys.version_info[0] == 3:
+ a.append(int.from_bytes(paramValue[i],'big'))
+ else:
+ a.append(paramValue[i])
+ i=i+1
+ if sys.version_info[0] == 3:
+ a=str(a,'utf-8')
+ else:
+ a=str(a)
+ return ret, a
+
+def simxGetCollisionHandle(clientID, collisionObjectName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ handle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(collisionObjectName) is str):
+ collisionObjectName=collisionObjectName.encode('utf-8')
+ return c_GetCollisionHandle(clientID, collisionObjectName, ct.byref(handle), operationMode), handle.value
+
+def simxGetCollectionHandle(clientID, collectionName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ handle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(collectionName) is str):
+ collectionName=collectionName.encode('utf-8')
+ return c_GetCollectionHandle(clientID, collectionName, ct.byref(handle), operationMode), handle.value
+
+def simxGetDistanceHandle(clientID, distanceObjectName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ handle = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(distanceObjectName) is str):
+ distanceObjectName=distanceObjectName.encode('utf-8')
+ return c_GetDistanceHandle(clientID, distanceObjectName, ct.byref(handle), operationMode), handle.value
+
+def simxReadCollision(clientID, collisionObjectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ collisionState = ct.c_ubyte()
+ return c_ReadCollision(clientID, collisionObjectHandle, ct.byref(collisionState), operationMode), bool(collisionState.value!=0)
+
+def simxReadDistance(clientID, distanceObjectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ minimumDistance = ct.c_float()
+ return c_ReadDistance(clientID, distanceObjectHandle, ct.byref(minimumDistance), operationMode), minimumDistance.value
+
+def simxRemoveObject(clientID, objectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_RemoveObject(clientID, objectHandle, operationMode)
+
+def simxRemoveModel(clientID, objectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_RemoveModel(clientID, objectHandle, operationMode)
+
+def simxRemoveUI(clientID, uiHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_RemoveUI(clientID, uiHandle, operationMode)
+
+def simxCloseScene(clientID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_CloseScene(clientID, operationMode)
+
+def simxGetObjects(clientID, objectType, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ objectCount = ct.c_int()
+ objectHandles = ct.POINTER(ct.c_int)()
+
+ ret = c_GetObjects(clientID, objectType, ct.byref(objectCount), ct.byref(objectHandles), operationMode)
+ handles = []
+ if ret == 0:
+ for i in range(objectCount.value):
+ handles.append(objectHandles[i])
+
+ return ret, handles
+
+
+def simxDisplayDialog(clientID, titleText, mainText, dialogType, initialText, titleColors, dialogColors, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ if titleColors != None:
+ c_titleColors = (ct.c_float*6)(*titleColors)
+ else:
+ c_titleColors = None
+ if dialogColors != None:
+ c_dialogColors = (ct.c_float*6)(*dialogColors)
+ else:
+ c_dialogColors = None
+
+ c_dialogHandle = ct.c_int()
+ c_uiHandle = ct.c_int()
+ if sys.version_info[0] == 3:
+ if type(titleText) is str:
+ titleText=titleText.encode('utf-8')
+ if type(mainText) is str:
+ mainText=mainText.encode('utf-8')
+ if type(initialText) is str:
+ initialText=initialText.encode('utf-8')
+ return c_DisplayDialog(clientID, titleText, mainText, dialogType, initialText, c_titleColors, c_dialogColors, ct.byref(c_dialogHandle), ct.byref(c_uiHandle), operationMode), c_dialogHandle.value, c_uiHandle.value
+
+def simxEndDialog(clientID, dialogHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_EndDialog(clientID, dialogHandle, operationMode)
+
+def simxGetDialogInput(clientID, dialogHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ inputText = ct.POINTER(ct.c_char)()
+ ret = c_GetDialogInput(clientID, dialogHandle, ct.byref(inputText), operationMode)
+
+ a = bytearray()
+ if ret == 0:
+ i = 0
+ while inputText[i] != b'\0':
+ if sys.version_info[0] == 3:
+ a.append(int.from_bytes(inputText[i],'big'))
+ else:
+ a.append(inputText[i])
+ i = i+1
+
+ if sys.version_info[0] == 3:
+ a=str(a,'utf-8')
+ else:
+ a=str(a)
+ return ret, a
+
+
+def simxGetDialogResult(clientID, dialogHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ result = ct.c_int()
+ return c_GetDialogResult(clientID, dialogHandle, ct.byref(result), operationMode), result.value
+
+def simxCopyPasteObjects(clientID, objectHandles, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ c_objectHandles = (ct.c_int*len(objectHandles))(*objectHandles)
+ c_objectHandles = ct.cast(c_objectHandles,ct.POINTER(ct.c_int)) # IronPython needs this
+ newObjectCount = ct.c_int()
+ newObjectHandles = ct.POINTER(ct.c_int)()
+ ret = c_CopyPasteObjects(clientID, c_objectHandles, len(objectHandles), ct.byref(newObjectHandles), ct.byref(newObjectCount), operationMode)
+
+ newobj = []
+ if ret == 0:
+ for i in range(newObjectCount.value):
+ newobj.append(newObjectHandles[i])
+
+ return ret, newobj
+
+
+def simxGetObjectSelection(clientID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ objectCount = ct.c_int()
+ objectHandles = ct.POINTER(ct.c_int)()
+ ret = c_GetObjectSelection(clientID, ct.byref(objectHandles), ct.byref(objectCount), operationMode)
+
+ newobj = []
+ if ret == 0:
+ for i in range(objectCount.value):
+ newobj.append(objectHandles[i])
+
+ return ret, newobj
+
+
+
+def simxSetObjectSelection(clientID, objectHandles, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ c_objectHandles = (ct.c_int*len(objectHandles))(*objectHandles)
+ return c_SetObjectSelection(clientID, c_objectHandles, len(objectHandles), operationMode)
+
+def simxClearFloatSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_ClearFloatSignal(clientID, signalName, operationMode)
+
+def simxClearIntegerSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_ClearIntegerSignal(clientID, signalName, operationMode)
+
+def simxClearStringSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_ClearStringSignal(clientID, signalName, operationMode)
+
+def simxGetFloatSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ signalValue = ct.c_float()
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_GetFloatSignal(clientID, signalName, ct.byref(signalValue), operationMode), signalValue.value
+
+def simxGetIntegerSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ signalValue = ct.c_int()
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_GetIntegerSignal(clientID, signalName, ct.byref(signalValue), operationMode), signalValue.value
+
+def simxGetStringSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ signalLength = ct.c_int();
+ signalValue = ct.POINTER(ct.c_ubyte)()
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ ret = c_GetStringSignal(clientID, signalName, ct.byref(signalValue), ct.byref(signalLength), operationMode)
+
+ a = bytearray()
+ if ret == 0:
+ for i in range(signalLength.value):
+ a.append(signalValue[i])
+ if sys.version_info[0] != 3:
+ a=str(a)
+
+ return ret, a
+
+def simxGetAndClearStringSignal(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ signalLength = ct.c_int();
+ signalValue = ct.POINTER(ct.c_ubyte)()
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ ret = c_GetAndClearStringSignal(clientID, signalName, ct.byref(signalValue), ct.byref(signalLength), operationMode)
+
+ a = bytearray()
+ if ret == 0:
+ for i in range(signalLength.value):
+ a.append(signalValue[i])
+ if sys.version_info[0] != 3:
+ a=str(a)
+
+ return ret, a
+
+def simxReadStringStream(clientID, signalName, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ signalLength = ct.c_int();
+ signalValue = ct.POINTER(ct.c_ubyte)()
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ ret = c_ReadStringStream(clientID, signalName, ct.byref(signalValue), ct.byref(signalLength), operationMode)
+
+ a = bytearray()
+ if ret == 0:
+ for i in range(signalLength.value):
+ a.append(signalValue[i])
+ if sys.version_info[0] != 3:
+ a=str(a)
+
+ return ret, a
+
+def simxSetFloatSignal(clientID, signalName, signalValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_SetFloatSignal(clientID, signalName, signalValue, operationMode)
+
+def simxSetIntegerSignal(clientID, signalName, signalValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(signalName) is str):
+ signalName=signalName.encode('utf-8')
+ return c_SetIntegerSignal(clientID, signalName, signalValue, operationMode)
+
+def simxSetStringSignal(clientID, signalName, signalValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ sigV=signalValue
+ if sys.version_info[0] == 3:
+ if type(signalName) is str:
+ signalName=signalName.encode('utf-8')
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=signalValue.encode('utf-8')
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ else:
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=bytearray(signalValue)
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ sigV=ct.cast(sigV,ct.POINTER(ct.c_ubyte)) # IronPython needs this
+ return c_SetStringSignal(clientID, signalName, sigV, len(signalValue), operationMode)
+
+def simxAppendStringSignal(clientID, signalName, signalValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ sigV=signalValue
+ if sys.version_info[0] == 3:
+ if type(signalName) is str:
+ signalName=signalName.encode('utf-8')
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=signalValue.encode('utf-8')
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ else:
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=bytearray(signalValue)
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ sigV=ct.cast(sigV,ct.POINTER(ct.c_ubyte)) # IronPython needs this
+ return c_AppendStringSignal(clientID, signalName, sigV, len(signalValue), operationMode)
+
+def simxWriteStringStream(clientID, signalName, signalValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ sigV=signalValue
+ if sys.version_info[0] == 3:
+ if type(signalName) is str:
+ signalName=signalName.encode('utf-8')
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=signalValue.encode('utf-8')
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ else:
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=bytearray(signalValue)
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ sigV=ct.cast(sigV,ct.POINTER(ct.c_ubyte)) # IronPython needs this
+ return c_WriteStringStream(clientID, signalName, sigV, len(signalValue), operationMode)
+
+def simxGetObjectFloatParameter(clientID, objectHandle, parameterID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ parameterValue = ct.c_float()
+ return c_GetObjectFloatParameter(clientID, objectHandle, parameterID, ct.byref(parameterValue), operationMode), parameterValue.value
+
+def simxSetObjectFloatParameter(clientID, objectHandle, parameterID, parameterValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetObjectFloatParameter(clientID, objectHandle, parameterID, parameterValue, operationMode)
+
+def simxGetObjectIntParameter(clientID, objectHandle, parameterID, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ parameterValue = ct.c_int()
+ return c_GetObjectIntParameter(clientID, objectHandle, parameterID, ct.byref(parameterValue), operationMode), parameterValue.value
+
+def simxSetObjectIntParameter(clientID, objectHandle, parameterID, parameterValue, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetObjectIntParameter(clientID, objectHandle, parameterID, parameterValue, operationMode)
+
+def simxGetModelProperty(clientID, objectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ prop = ct.c_int()
+ return c_GetModelProperty(clientID, objectHandle, ct.byref(prop), operationMode), prop.value
+
+def simxSetModelProperty(clientID, objectHandle, prop, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SetModelProperty(clientID, objectHandle, prop, operationMode)
+
+def simxStart(connectionAddress, connectionPort, waitUntilConnected, doNotReconnectOnceDisconnected, timeOutInMs, commThreadCycleInMs):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(connectionAddress) is str):
+ connectionAddress=connectionAddress.encode('utf-8')
+ return c_Start(connectionAddress, connectionPort, waitUntilConnected, doNotReconnectOnceDisconnected, timeOutInMs, commThreadCycleInMs)
+
+def simxFinish(clientID):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_Finish(clientID)
+
+def simxGetPingTime(clientID):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ pingTime = ct.c_int()
+ return c_GetPingTime(clientID, ct.byref(pingTime)), pingTime.value
+
+def simxGetLastCmdTime(clientID):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_GetLastCmdTime(clientID)
+
+def simxSynchronousTrigger(clientID):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_SynchronousTrigger(clientID)
+
+def simxSynchronous(clientID, enable):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_Synchronous(clientID, enable)
+
+def simxPauseCommunication(clientID, enable):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_PauseCommunication(clientID, enable)
+
+def simxGetInMessageInfo(clientID, infoType):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ info = ct.c_int()
+ return c_GetInMessageInfo(clientID, infoType, ct.byref(info)), info.value
+
+def simxGetOutMessageInfo(clientID, infoType):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ info = ct.c_int()
+ return c_GetOutMessageInfo(clientID, infoType, ct.byref(info)), info.value
+
+def simxGetConnectionId(clientID):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_GetConnectionId(clientID)
+
+def simxCreateBuffer(bufferSize):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_CreateBuffer(bufferSize)
+
+def simxReleaseBuffer(buffer):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ return c_ReleaseBuffer(buffer)
+
+def simxTransferFile(clientID, filePathAndName, fileName_serverSide, timeOut, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(filePathAndName) is str):
+ filePathAndName=filePathAndName.encode('utf-8')
+ return c_TransferFile(clientID, filePathAndName, fileName_serverSide, timeOut, operationMode)
+
+def simxEraseFile(clientID, fileName_serverSide, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if (sys.version_info[0] == 3) and (type(fileName_serverSide) is str):
+ fileName_serverSide=fileName_serverSide.encode('utf-8')
+ return c_EraseFile(clientID, fileName_serverSide, operationMode)
+
+def simxCreateDummy(clientID, size, color, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ handle = ct.c_int()
+ if color != None:
+ c_color = (ct.c_ubyte*12)(*color)
+ else:
+ c_color = None
+ return c_CreateDummy(clientID, size, c_color, ct.byref(handle), operationMode), handle.value
+
+def simxQuery(clientID, signalName, signalValue, retSignalName, timeOutInMs):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ retSignalLength = ct.c_int();
+ retSignalValue = ct.POINTER(ct.c_ubyte)()
+
+ sigV=signalValue
+ if sys.version_info[0] == 3:
+ if type(signalName) is str:
+ signalName=signalName.encode('utf-8')
+ if type(retSignalName) is str:
+ retSignalName=retSignalName.encode('utf-8')
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=signalValue.encode('utf-8')
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ else:
+ if type(signalValue) is bytearray:
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ if type(signalValue) is str:
+ signalValue=bytearray(signalValue)
+ sigV = (ct.c_ubyte*len(signalValue))(*signalValue)
+ sigV=ct.cast(sigV,ct.POINTER(ct.c_ubyte)) # IronPython needs this
+
+ ret = c_Query(clientID, signalName, sigV, len(signalValue), retSignalName, ct.byref(retSignalValue), ct.byref(retSignalLength), timeOutInMs)
+
+ a = bytearray()
+ if ret == 0:
+ for i in range(retSignalLength.value):
+ a.append(retSignalValue[i])
+ if sys.version_info[0] != 3:
+ a=str(a)
+
+ return ret, a
+
+def simxGetObjectGroupData(clientID, objectType, dataType, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ handles =[]
+ intData =[]
+ floatData =[]
+ stringData =[]
+ handlesC = ct.c_int()
+ handlesP = ct.POINTER(ct.c_int)()
+ intDataC = ct.c_int()
+ intDataP = ct.POINTER(ct.c_int)()
+ floatDataC = ct.c_int()
+ floatDataP = ct.POINTER(ct.c_float)()
+ stringDataC = ct.c_int()
+ stringDataP = ct.POINTER(ct.c_char)()
+ ret = c_GetObjectGroupData(clientID, objectType, dataType, ct.byref(handlesC), ct.byref(handlesP), ct.byref(intDataC), ct.byref(intDataP), ct.byref(floatDataC), ct.byref(floatDataP), ct.byref(stringDataC), ct.byref(stringDataP), operationMode)
+
+ if ret == 0:
+ for i in range(handlesC.value):
+ handles.append(handlesP[i])
+ for i in range(intDataC.value):
+ intData.append(intDataP[i])
+ for i in range(floatDataC.value):
+ floatData.append(floatDataP[i])
+ s = 0
+ for i in range(stringDataC.value):
+ a = bytearray()
+ while stringDataP[s] != b'\0':
+ if sys.version_info[0] == 3:
+ a.append(int.from_bytes(stringDataP[s],'big'))
+ else:
+ a.append(stringDataP[s])
+ s += 1
+ s += 1 #skip null
+ if sys.version_info[0] == 3:
+ a=str(a,'utf-8')
+ else:
+ a=str(a)
+ stringData.append(a)
+
+ return ret, handles, intData, floatData, stringData
+
+def simxCallScriptFunction(clientID, scriptDescription, options, functionName, inputInts, inputFloats, inputStrings, inputBuffer, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ inputBufferV=inputBuffer
+ if sys.version_info[0] == 3:
+ if type(scriptDescription) is str:
+ scriptDescription=scriptDescription.encode('utf-8')
+ if type(functionName) is str:
+ functionName=functionName.encode('utf-8')
+ if type(inputBuffer) is bytearray:
+ inputBufferV = (ct.c_ubyte*len(inputBuffer))(*inputBuffer)
+ if type(inputBuffer) is str:
+ inputBuffer=inputBuffer.encode('utf-8')
+ inputBufferV = (ct.c_ubyte*len(inputBuffer))(*inputBuffer)
+ else:
+ if type(inputBuffer) is bytearray:
+ inputBufferV = (ct.c_ubyte*len(inputBuffer))(*inputBuffer)
+ if type(inputBuffer) is str:
+ inputBuffer=bytearray(inputBuffer)
+ inputBufferV = (ct.c_ubyte*len(inputBuffer))(*inputBuffer)
+ inputBufferV=ct.cast(inputBufferV,ct.POINTER(ct.c_ubyte)) # IronPython needs this
+
+ c_inInts = (ct.c_int*len(inputInts))(*inputInts)
+ c_inInts = ct.cast(c_inInts,ct.POINTER(ct.c_int)) # IronPython needs this
+ c_inFloats = (ct.c_float*len(inputFloats))(*inputFloats)
+ c_inFloats = ct.cast(c_inFloats,ct.POINTER(ct.c_float)) # IronPython needs this
+
+ concatStr=''.encode('utf-8')
+ for i in range(len(inputStrings)):
+ a=inputStrings[i]
+ a=a+'\0'
+ if type(a) is str:
+ a=a.encode('utf-8')
+ concatStr=concatStr+a
+ c_inStrings = (ct.c_char*len(concatStr))(*concatStr)
+
+ intDataOut =[]
+ floatDataOut =[]
+ stringDataOut =[]
+ bufferOut =bytearray()
+
+ intDataC = ct.c_int()
+ intDataP = ct.POINTER(ct.c_int)()
+ floatDataC = ct.c_int()
+ floatDataP = ct.POINTER(ct.c_float)()
+ stringDataC = ct.c_int()
+ stringDataP = ct.POINTER(ct.c_char)()
+ bufferS = ct.c_int()
+ bufferP = ct.POINTER(ct.c_ubyte)()
+
+ ret = c_CallScriptFunction(clientID,scriptDescription,options,functionName,len(inputInts),c_inInts,len(inputFloats),c_inFloats,len(inputStrings),c_inStrings,len(inputBuffer),inputBufferV,ct.byref(intDataC),ct.byref(intDataP),ct.byref(floatDataC),ct.byref(floatDataP),ct.byref(stringDataC),ct.byref(stringDataP),ct.byref(bufferS),ct.byref(bufferP),operationMode)
+
+ if ret == 0:
+ for i in range(intDataC.value):
+ intDataOut.append(intDataP[i])
+ for i in range(floatDataC.value):
+ floatDataOut.append(floatDataP[i])
+ s = 0
+ for i in range(stringDataC.value):
+ a = bytearray()
+ while stringDataP[s] != b'\0':
+ if sys.version_info[0] == 3:
+ a.append(int.from_bytes(stringDataP[s],'big'))
+ else:
+ a.append(stringDataP[s])
+ s += 1
+ s += 1 #skip null
+ if sys.version_info[0] == 3:
+ a=str(a,'utf-8')
+ else:
+ a=str(a)
+ stringDataOut.append(a)
+ for i in range(bufferS.value):
+ bufferOut.append(bufferP[i])
+ if sys.version_info[0] != 3:
+ bufferOut=str(bufferOut)
+
+ return ret, intDataOut, floatDataOut, stringDataOut, bufferOut
+
+def simxGetObjectVelocity(clientID, objectHandle, operationMode):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+ linearVel = (ct.c_float*3)()
+ angularVel = (ct.c_float*3)()
+ ret = c_GetObjectVelocity(clientID, objectHandle, linearVel, angularVel, operationMode)
+ arr1 = []
+ for i in range(3):
+ arr1.append(linearVel[i])
+ arr2 = []
+ for i in range(3):
+ arr2.append(angularVel[i])
+ return ret, arr1, arr2
+
+def simxPackInts(intList):
+ '''
+ Please have a look at the function description/documentation in the CoppeliaSim user manual
+ '''
+
+ if sys.version_info[0] == 3:
+ s=bytes()
+ for i in range(len(intList)):
+ s=s+struct.pack('=1x)
+# reserved =sim_simulation_advancing|0x02
+sim_simulation_advancing_lastbeforepause =sim_simulation_advancing|0x03 # Last simulation pass before pause (1x)
+sim_simulation_advancing_firstafterpause =sim_simulation_advancing|0x04 # First simulation pass after pause (1x)
+sim_simulation_advancing_abouttostop =sim_simulation_advancing|0x05 # "Trying to stop" simulation pass (>=1x)
+sim_simulation_advancing_lastbeforestop =sim_simulation_advancing|0x06 # Last simulation pass (1x)
+
+
+# Script execution result (first return value)
+sim_script_no_error =0
+sim_script_main_script_nonexistent =1
+sim_script_main_script_not_called =2
+sim_script_reentrance_error =4
+sim_script_lua_error =8
+sim_script_call_error =16
+
+
+ # Script types (serialized!)
+sim_scripttype_mainscript =0
+sim_scripttype_childscript =1
+sim_scripttype_jointctrlcallback =4
+sim_scripttype_contactcallback =5
+sim_scripttype_customizationscript =6
+sim_scripttype_generalcallback =7
+
+# API call error messages
+sim_api_errormessage_ignore =0 # does not memorize nor output errors
+sim_api_errormessage_report =1 # memorizes errors (default for C-API calls)
+sim_api_errormessage_output =2 # memorizes and outputs errors (default for Lua-API calls)
+
+
+# special argument of some functions
+sim_handle_all =-2
+sim_handle_all_except_explicit =-3
+sim_handle_self =-4
+sim_handle_main_script =-5
+sim_handle_tree =-6
+sim_handle_chain =-7
+sim_handle_single =-8
+sim_handle_default =-9
+sim_handle_all_except_self =-10
+sim_handle_parent =-11
+
+
+# special handle flags
+sim_handleflag_assembly =0x400000
+sim_handleflag_model =0x800000
+
+
+# distance calculation methods (serialized)
+sim_distcalcmethod_dl =0
+sim_distcalcmethod_dac =1
+sim_distcalcmethod_max_dl_dac =2
+sim_distcalcmethod_dl_and_dac =3
+sim_distcalcmethod_sqrt_dl2_and_dac2=4
+sim_distcalcmethod_dl_if_nonzero =5
+sim_distcalcmethod_dac_if_nonzero =6
+
+
+ # Generic dialog styles
+sim_dlgstyle_message =0
+sim_dlgstyle_input =1
+sim_dlgstyle_ok =2
+sim_dlgstyle_ok_cancel =3
+sim_dlgstyle_yes_no =4
+sim_dlgstyle_dont_center =32# can be combined with one of above values. Only with this flag can the position of the related UI be set just after dialog creation
+
+ # Generic dialog return values
+sim_dlgret_still_open =0
+sim_dlgret_ok =1
+sim_dlgret_cancel =2
+sim_dlgret_yes =3
+sim_dlgret_no =4
+
+
+# Path properties
+sim_pathproperty_show_line =0x0001
+sim_pathproperty_show_orientation =0x0002
+sim_pathproperty_closed_path =0x0004
+sim_pathproperty_automatic_orientation =0x0008
+sim_pathproperty_invert_velocity =0x0010
+sim_pathproperty_infinite_acceleration =0x0020
+sim_pathproperty_flat_path =0x0040
+sim_pathproperty_show_position =0x0080
+sim_pathproperty_auto_velocity_profile_translation =0x0100
+sim_pathproperty_auto_velocity_profile_rotation =0x0200
+sim_pathproperty_endpoints_at_zero =0x0400
+sim_pathproperty_keep_x_up =0x0800
+
+
+ # drawing objects
+# following are mutually exclusive
+sim_drawing_points =0 # 3 values per point (point size in pixels)
+sim_drawing_lines =1 # 6 values per line (line size in pixels)
+sim_drawing_triangles =2 # 9 values per triangle
+sim_drawing_trianglepoints =3 # 6 values per point (3 for triangle position 3 for triangle normal vector) (triangle size in meters)
+sim_drawing_quadpoints =4 # 6 values per point (3 for quad position 3 for quad normal vector) (quad size in meters)
+sim_drawing_discpoints =5 # 6 values per point (3 for disc position 3 for disc normal vector) (disc size in meters)
+sim_drawing_cubepoints =6 # 6 values per point (3 for cube position 3 for cube normal vector) (cube size in meters)
+sim_drawing_spherepoints =7 # 3 values per point (sphere size in meters)
+
+# following can be or-combined
+sim_drawing_itemcolors =0x00020 # +3 values per item (each item has its own ambient color (rgb values)).
+ # Mutually exclusive with sim_drawing_vertexcolors
+sim_drawing_vertexcolors =0x00040 # +3 values per vertex (each vertex has its own ambient color (rgb values). Only for sim_drawing_lines (+6) and for sim_drawing_triangles(+9)). Mutually exclusive with sim_drawing_itemcolors
+sim_drawing_itemsizes =0x00080 # +1 value per item (each item has its own size). Not for sim_drawing_triangles
+sim_drawing_backfaceculling =0x00100 # back faces are not displayed for all items
+sim_drawing_wireframe =0x00200 # all items displayed in wireframe
+sim_drawing_painttag =0x00400 # all items are tagged as paint (for additinal processing at a later stage)
+sim_drawing_followparentvisibility =0x00800 # if the object is associated with a scene object then it follows that visibility otherwise it is always visible
+sim_drawing_cyclic =0x01000 # if the max item count was reached then the first items are overwritten.
+sim_drawing_50percenttransparency =0x02000 # the drawing object will be 50% transparent
+sim_drawing_25percenttransparency =0x04000 # the drawing object will be 25% transparent
+sim_drawing_12percenttransparency =0x08000 # the drawing object will be 12.5% transparent
+sim_drawing_emissioncolor =0x10000 # When used in combination with sim_drawing_itemcolors or sim_drawing_vertexcolors then the specified colors will be for the emissive component
+sim_drawing_facingcamera =0x20000 # Only for trianglepoints quadpoints discpoints and cubepoints. If specified the normal verctor is calculated to face the camera (each item data requires 3 values less)
+sim_drawing_overlay =0x40000 # When specified objects are always drawn on top of "regular objects"
+sim_drawing_itemtransparency =0x80000 # +1 value per item (each item has its own transparency value (0-1)). Not compatible with sim_drawing_vertexcolors
+
+# banner values
+# following can be or-combined
+sim_banner_left =0x00001 # Banners display on the left of the specified point
+sim_banner_right =0x00002 # Banners display on the right of the specified point
+sim_banner_nobackground =0x00004 # Banners have no background rectangle
+sim_banner_overlay =0x00008 # When specified banners are always drawn on top of "regular objects"
+sim_banner_followparentvisibility =0x00010 # if the object is associated with a scene object then it follows that visibility otherwise it is always visible
+sim_banner_clickselectsparent =0x00020 # if the object is associated with a scene object then clicking the banner will select the scene object
+sim_banner_clicktriggersevent =0x00040 # if the banner is clicked an event is triggered (sim_message_eventcallback_bannerclicked and sim_message_bannerclicked are generated)
+sim_banner_facingcamera =0x00080 # If specified the banner will always face the camera by rotating around the banner's vertical axis (y-axis)
+sim_banner_fullyfacingcamera =0x00100 # If specified the banner will always fully face the camera (the banner's orientation is same as the camera looking at it)
+sim_banner_backfaceculling =0x00200 # If specified the banner will only be visible from one side
+sim_banner_keepsamesize =0x00400 # If specified the banner will always appear in the same size. In that case size represents the character height in pixels
+sim_banner_bitmapfont =0x00800 # If specified a fixed-size bitmap font is used. The text will also always fully face the camera and be right
+ # to the specified position. Bitmap fonts are not clickable
+
+
+# particle objects following are mutually exclusive
+sim_particle_points1 =0 # 6 values per point (pt1 and pt2. Pt1 is start position pt2-pt1 is the initial velocity vector). i
+ #Point is 1 pixel big. Only appearance is a point internally handled as a perfect sphere
+sim_particle_points2 =1 # 6 values per point. Point is 2 pixel big. Only appearance is a point internally handled as a perfect sphere
+sim_particle_points4 =2 # 6 values per point. Point is 4 pixel big. Only appearance is a point internally handled as a perfect sphere
+sim_particle_roughspheres =3 # 6 values per sphere. Only appearance is rough. Internally a perfect sphere
+sim_particle_spheres =4 # 6 values per sphere. Internally a perfect sphere
+
+
+
+
+# following can be or-combined
+sim_particle_respondable1to4 =0x0020 # the particles are respondable against shapes (against all objects that have at least one bit 1-4 activated in the global respondable mask)
+sim_particle_respondable5to8 =0x0040 # the particles are respondable against shapes (against all objects that have at least one bit 5-8 activated in the global respondable mask)
+sim_particle_particlerespondable =0x0080 # the particles are respondable against each other
+sim_particle_ignoresgravity =0x0100 # the particles ignore the effect of gravity. Not compatible with sim_particle_water
+sim_particle_invisible =0x0200 # the particles are invisible
+sim_particle_itemsizes =0x0400 # +1 value per particle (each particle can have a different size)
+sim_particle_itemdensities =0x0800 # +1 value per particle (each particle can have a different density)
+sim_particle_itemcolors =0x1000 # +3 values per particle (each particle can have a different color)
+sim_particle_cyclic =0x2000 # if the max item count was reached then the first items are overwritten.
+sim_particle_emissioncolor =0x4000 # When used in combination with sim_particle_itemcolors then the specified colors will be for the emissive component
+sim_particle_water =0x8000 # the particles are water particles (no weight in the water (i.e. when z<0)). Not compatible with sim_particle_ignoresgravity
+sim_particle_painttag =0x10000 # The particles can be seen by vision sensors (sim_particle_invisible must not be set)
+
+
+
+
+# custom user interface menu attributes
+sim_ui_menu_title =1
+sim_ui_menu_minimize =2
+sim_ui_menu_close =4
+sim_ui_menu_systemblock =8
+
+
+
+# Boolean parameters
+sim_boolparam_hierarchy_visible =0
+sim_boolparam_console_visible =1
+sim_boolparam_collision_handling_enabled =2
+sim_boolparam_distance_handling_enabled =3
+sim_boolparam_ik_handling_enabled =4
+sim_boolparam_gcs_handling_enabled =5
+sim_boolparam_dynamics_handling_enabled =6
+sim_boolparam_joint_motion_handling_enabled =7
+sim_boolparam_path_motion_handling_enabled =8
+sim_boolparam_proximity_sensor_handling_enabled =9
+sim_boolparam_vision_sensor_handling_enabled =10
+sim_boolparam_mill_handling_enabled =11
+sim_boolparam_browser_visible =12
+sim_boolparam_scene_and_model_load_messages =13
+sim_reserved0 =14
+sim_boolparam_shape_textures_are_visible =15
+sim_boolparam_display_enabled =16
+sim_boolparam_infotext_visible =17
+sim_boolparam_statustext_open =18
+sim_boolparam_fog_enabled =19
+sim_boolparam_rml2_available =20
+sim_boolparam_rml4_available =21
+sim_boolparam_mirrors_enabled =22
+sim_boolparam_aux_clip_planes_enabled =23
+sim_boolparam_full_model_copy_from_api =24
+sim_boolparam_realtime_simulation =25
+sim_boolparam_force_show_wireless_emission =27
+sim_boolparam_force_show_wireless_reception =28
+sim_boolparam_video_recording_triggered =29
+sim_boolparam_threaded_rendering_enabled =32
+sim_boolparam_fullscreen =33
+sim_boolparam_headless =34
+sim_boolparam_hierarchy_toolbarbutton_enabled =35
+sim_boolparam_browser_toolbarbutton_enabled =36
+sim_boolparam_objectshift_toolbarbutton_enabled =37
+sim_boolparam_objectrotate_toolbarbutton_enabled=38
+sim_boolparam_force_calcstruct_all_visible =39
+sim_boolparam_force_calcstruct_all =40
+sim_boolparam_exit_request =41
+sim_boolparam_play_toolbarbutton_enabled =42
+sim_boolparam_pause_toolbarbutton_enabled =43
+sim_boolparam_stop_toolbarbutton_enabled =44
+sim_boolparam_waiting_for_trigger =45
+
+
+# Integer parameters
+sim_intparam_error_report_mode =0 # Check sim_api_errormessage_... constants above for valid values
+sim_intparam_program_version =1 # e.g Version 2.1.4 --> 20104. Can only be read
+sim_intparam_instance_count =2 # do not use anymore (always returns 1 since CoppeliaSim 2.5.11)
+sim_intparam_custom_cmd_start_id =3 # can only be read
+sim_intparam_compilation_version =4 # 0=evaluation version 1=full version 2=player version. Can only be read
+sim_intparam_current_page =5
+sim_intparam_flymode_camera_handle =6 # can only be read
+sim_intparam_dynamic_step_divider =7 # can only be read
+sim_intparam_dynamic_engine =8 # 0=Bullet 1=ODE. 2=Vortex.
+sim_intparam_server_port_start =9 # can only be read
+sim_intparam_server_port_range =10 # can only be read
+sim_intparam_visible_layers =11
+sim_intparam_infotext_style =12
+sim_intparam_settings =13
+sim_intparam_edit_mode_type =14 # can only be read
+sim_intparam_server_port_next =15 # is initialized at sim_intparam_server_port_start
+sim_intparam_qt_version =16 # version of the used Qt framework
+sim_intparam_event_flags_read =17 # can only be read
+sim_intparam_event_flags_read_clear =18 # can only be read
+sim_intparam_platform =19 # can only be read
+sim_intparam_scene_unique_id =20 # can only be read
+sim_intparam_work_thread_count =21
+sim_intparam_mouse_x =22
+sim_intparam_mouse_y =23
+sim_intparam_core_count =24
+sim_intparam_work_thread_calc_time_ms =25
+sim_intparam_idle_fps =26
+sim_intparam_prox_sensor_select_down =27
+sim_intparam_prox_sensor_select_up =28
+sim_intparam_stop_request_counter =29
+sim_intparam_program_revision =30
+sim_intparam_mouse_buttons =31
+sim_intparam_dynamic_warning_disabled_mask =32
+sim_intparam_simulation_warning_disabled_mask =33
+sim_intparam_scene_index =34
+sim_intparam_motionplanning_seed =35
+sim_intparam_speedmodifier =36
+
+# Float parameters
+sim_floatparam_rand=0 # random value (0.0-1.0)
+sim_floatparam_simulation_time_step =1
+sim_floatparam_stereo_distance =2
+
+# String parameters
+sim_stringparam_application_path=0 # path of CoppeliaSim's executable
+sim_stringparam_video_filename=1
+sim_stringparam_app_arg1 =2
+sim_stringparam_app_arg2 =3
+sim_stringparam_app_arg3 =4
+sim_stringparam_app_arg4 =5
+sim_stringparam_app_arg5 =6
+sim_stringparam_app_arg6 =7
+sim_stringparam_app_arg7 =8
+sim_stringparam_app_arg8 =9
+sim_stringparam_app_arg9 =10
+sim_stringparam_scene_path_and_name =13
+
+# Array parameters
+sim_arrayparam_gravity =0
+sim_arrayparam_fog =1
+sim_arrayparam_fog_color =2
+sim_arrayparam_background_color1=3
+sim_arrayparam_background_color2=4
+sim_arrayparam_ambient_light =5
+sim_arrayparam_random_euler =6
+
+sim_objintparam_visibility_layer= 10
+sim_objfloatparam_abs_x_velocity= 11
+sim_objfloatparam_abs_y_velocity= 12
+sim_objfloatparam_abs_z_velocity= 13
+sim_objfloatparam_abs_rot_velocity= 14
+sim_objfloatparam_objbbox_min_x= 15
+sim_objfloatparam_objbbox_min_y= 16
+sim_objfloatparam_objbbox_min_z= 17
+sim_objfloatparam_objbbox_max_x= 18
+sim_objfloatparam_objbbox_max_y= 19
+sim_objfloatparam_objbbox_max_z= 20
+sim_objfloatparam_modelbbox_min_x= 21
+sim_objfloatparam_modelbbox_min_y= 22
+sim_objfloatparam_modelbbox_min_z= 23
+sim_objfloatparam_modelbbox_max_x= 24
+sim_objfloatparam_modelbbox_max_y= 25
+sim_objfloatparam_modelbbox_max_z= 26
+sim_objintparam_collection_self_collision_indicator= 27
+sim_objfloatparam_transparency_offset= 28
+sim_objintparam_child_role= 29
+sim_objintparam_parent_role= 30
+sim_objintparam_manipulation_permissions= 31
+sim_objintparam_illumination_handle= 32
+
+sim_visionfloatparam_near_clipping= 1000
+sim_visionfloatparam_far_clipping= 1001
+sim_visionintparam_resolution_x= 1002
+sim_visionintparam_resolution_y= 1003
+sim_visionfloatparam_perspective_angle= 1004
+sim_visionfloatparam_ortho_size= 1005
+sim_visionintparam_disabled_light_components= 1006
+sim_visionintparam_rendering_attributes= 1007
+sim_visionintparam_entity_to_render= 1008
+sim_visionintparam_windowed_size_x= 1009
+sim_visionintparam_windowed_size_y= 1010
+sim_visionintparam_windowed_pos_x= 1011
+sim_visionintparam_windowed_pos_y= 1012
+sim_visionintparam_pov_focal_blur= 1013
+sim_visionfloatparam_pov_blur_distance= 1014
+sim_visionfloatparam_pov_aperture= 1015
+sim_visionintparam_pov_blur_sampled= 1016
+sim_visionintparam_render_mode= 1017
+
+sim_jointintparam_motor_enabled= 2000
+sim_jointintparam_ctrl_enabled= 2001
+sim_jointfloatparam_pid_p= 2002
+sim_jointfloatparam_pid_i= 2003
+sim_jointfloatparam_pid_d= 2004
+sim_jointfloatparam_intrinsic_x= 2005
+sim_jointfloatparam_intrinsic_y= 2006
+sim_jointfloatparam_intrinsic_z= 2007
+sim_jointfloatparam_intrinsic_qx= 2008
+sim_jointfloatparam_intrinsic_qy= 2009
+sim_jointfloatparam_intrinsic_qz= 2010
+sim_jointfloatparam_intrinsic_qw= 2011
+sim_jointfloatparam_velocity= 2012
+sim_jointfloatparam_spherical_qx= 2013
+sim_jointfloatparam_spherical_qy= 2014
+sim_jointfloatparam_spherical_qz= 2015
+sim_jointfloatparam_spherical_qw= 2016
+sim_jointfloatparam_upper_limit= 2017
+sim_jointfloatparam_kc_k= 2018
+sim_jointfloatparam_kc_c= 2019
+sim_jointfloatparam_ik_weight= 2021
+sim_jointfloatparam_error_x= 2022
+sim_jointfloatparam_error_y= 2023
+sim_jointfloatparam_error_z= 2024
+sim_jointfloatparam_error_a= 2025
+sim_jointfloatparam_error_b= 2026
+sim_jointfloatparam_error_g= 2027
+sim_jointfloatparam_error_pos= 2028
+sim_jointfloatparam_error_angle= 2029
+sim_jointintparam_velocity_lock= 2030
+sim_jointintparam_vortex_dep_handle= 2031
+sim_jointfloatparam_vortex_dep_multiplication= 2032
+sim_jointfloatparam_vortex_dep_offset= 2033
+
+sim_shapefloatparam_init_velocity_x= 3000
+sim_shapefloatparam_init_velocity_y= 3001
+sim_shapefloatparam_init_velocity_z= 3002
+sim_shapeintparam_static= 3003
+sim_shapeintparam_respondable= 3004
+sim_shapefloatparam_mass= 3005
+sim_shapefloatparam_texture_x= 3006
+sim_shapefloatparam_texture_y= 3007
+sim_shapefloatparam_texture_z= 3008
+sim_shapefloatparam_texture_a= 3009
+sim_shapefloatparam_texture_b= 3010
+sim_shapefloatparam_texture_g= 3011
+sim_shapefloatparam_texture_scaling_x= 3012
+sim_shapefloatparam_texture_scaling_y= 3013
+sim_shapeintparam_culling= 3014
+sim_shapeintparam_wireframe= 3015
+sim_shapeintparam_compound= 3016
+sim_shapeintparam_convex= 3017
+sim_shapeintparam_convex_check= 3018
+sim_shapeintparam_respondable_mask= 3019
+sim_shapefloatparam_init_velocity_a= 3020
+sim_shapefloatparam_init_velocity_b= 3021
+sim_shapefloatparam_init_velocity_g= 3022
+sim_shapestringparam_color_name= 3023
+sim_shapeintparam_edge_visibility= 3024
+sim_shapefloatparam_shading_angle= 3025
+sim_shapefloatparam_edge_angle= 3026
+sim_shapeintparam_edge_borders_hidden= 3027
+
+sim_proxintparam_ray_invisibility= 4000
+
+sim_forcefloatparam_error_x= 5000
+sim_forcefloatparam_error_y= 5001
+sim_forcefloatparam_error_z= 5002
+sim_forcefloatparam_error_a= 5003
+sim_forcefloatparam_error_b= 5004
+sim_forcefloatparam_error_g= 5005
+sim_forcefloatparam_error_pos= 5006
+sim_forcefloatparam_error_angle= 5007
+
+sim_lightintparam_pov_casts_shadows= 8000
+
+sim_cameraintparam_disabled_light_components= 9000
+sim_camerafloatparam_perspective_angle= 9001
+sim_camerafloatparam_ortho_size= 9002
+sim_cameraintparam_rendering_attributes= 9003
+sim_cameraintparam_pov_focal_blur= 9004
+sim_camerafloatparam_pov_blur_distance= 9005
+sim_camerafloatparam_pov_aperture= 9006
+sim_cameraintparam_pov_blur_samples= 9007
+
+sim_dummyintparam_link_type= 10000
+
+sim_mirrorfloatparam_width= 12000
+sim_mirrorfloatparam_height= 12001
+sim_mirrorfloatparam_reflectance= 12002
+sim_mirrorintparam_enable= 12003
+
+sim_pplanfloatparam_x_min= 20000
+sim_pplanfloatparam_x_range= 20001
+sim_pplanfloatparam_y_min= 20002
+sim_pplanfloatparam_y_range= 20003
+sim_pplanfloatparam_z_min= 20004
+sim_pplanfloatparam_z_range= 20005
+sim_pplanfloatparam_delta_min= 20006
+sim_pplanfloatparam_delta_range= 20007
+
+sim_mplanintparam_nodes_computed= 25000
+sim_mplanintparam_prepare_nodes= 25001
+sim_mplanintparam_clear_nodes= 25002
+
+# User interface elements
+sim_gui_menubar =0x0001
+sim_gui_popups =0x0002
+sim_gui_toolbar1 =0x0004
+sim_gui_toolbar2 =0x0008
+sim_gui_hierarchy =0x0010
+sim_gui_infobar =0x0020
+sim_gui_statusbar =0x0040
+sim_gui_scripteditor =0x0080
+sim_gui_scriptsimulationparameters =0x0100
+sim_gui_dialogs =0x0200
+sim_gui_browser =0x0400
+sim_gui_all =0xffff
+
+
+# Joint modes
+sim_jointmode_passive =0
+sim_jointmode_motion =1
+sim_jointmode_ik =2
+sim_jointmode_ikdependent =3
+sim_jointmode_dependent =4
+sim_jointmode_force =5
+
+
+# Navigation and selection modes with the mouse. Lower byte values are mutually exclusive upper byte bits can be combined
+sim_navigation_passive =0x0000
+sim_navigation_camerashift =0x0001
+sim_navigation_camerarotate =0x0002
+sim_navigation_camerazoom =0x0003
+sim_navigation_cameratilt =0x0004
+sim_navigation_cameraangle =0x0005
+sim_navigation_camerafly =0x0006
+sim_navigation_objectshift =0x0007
+sim_navigation_objectrotate =0x0008
+sim_navigation_reserved2 =0x0009
+sim_navigation_reserved3 =0x000A
+sim_navigation_jointpathtest =0x000B
+sim_navigation_ikmanip =0x000C
+sim_navigation_objectmultipleselection =0x000D
+# Bit-combine following values and add them to one of above's values for a valid navigation mode
+sim_navigation_reserved4 =0x0100
+sim_navigation_clickselection =0x0200
+sim_navigation_ctrlselection =0x0400
+sim_navigation_shiftselection =0x0800
+sim_navigation_camerazoomwheel =0x1000
+sim_navigation_camerarotaterightbutton =0x2000
+
+
+
+#Remote API constants
+SIMX_VERSION =0
+# Remote API message header structure
+SIMX_HEADER_SIZE =18
+simx_headeroffset_crc =0 # 1 simxUShort. Generated by the client or server. The CRC for the message
+simx_headeroffset_version =2 # 1 byte. Generated by the client or server. The version of the remote API software
+simx_headeroffset_message_id =3 # 1 simxInt. Generated by the client (and used in a reply by the server)
+simx_headeroffset_client_time =7 # 1 simxInt. Client time stamp generated by the client (and sent back by the server)
+simx_headeroffset_server_time =11 # 1 simxInt. Generated by the server when a reply is generated. The server timestamp
+simx_headeroffset_scene_id =15 # 1 simxUShort. Generated by the server. A unique ID identifying the scene currently displayed
+simx_headeroffset_server_state =17 # 1 byte. Generated by the server. Bit coded 0 set --> simulation not stopped 1 set --> simulation paused 2 set --> real-time switch on 3-5 edit mode type (0=no edit mode 1=triangle 2=vertex 3=edge 4=path 5=UI)
+
+# Remote API command header
+SIMX_SUBHEADER_SIZE =26
+simx_cmdheaderoffset_mem_size =0 # 1 simxInt. Generated by the client or server. The buffer size of the command.
+simx_cmdheaderoffset_full_mem_size =4 # 1 simxInt. Generated by the client or server. The full buffer size of the command (applies to split chunks).
+simx_cmdheaderoffset_pdata_offset0 =8 # 1 simxUShort. Generated by the client or server. The amount of data that is part of the command identification.
+simx_cmdheaderoffset_pdata_offset1 =10 # 1 simxInt. Generated by the client or server. The amount of shift of the pure data buffer (applies to split chunks).
+simx_cmdheaderoffset_cmd=14 # 1 simxInt. Generated by the client (and used in a reply by the server). The command combined with the operation mode of the command.
+simx_cmdheaderoffset_delay_or_split =18 # 1 simxUShort. Generated by the client or server. The amount of delay in ms of a continuous command or the max. pure data size to send at once (applies to split commands).
+simx_cmdheaderoffset_sim_time =20 # 1 simxInt. Generated by the server. The simulation time (in ms) when the command was executed (or 0 if simulation is not running)
+simx_cmdheaderoffset_status =24 # 1 byte. Generated by the server. (1 bit 0 is set --> error in function execution on server side). The client writes bit 1 if command cannot be overwritten
+simx_cmdheaderoffset_reserved =25 # 1 byte. Not yet used
+
+
+
+
+
+# Regular operation modes
+simx_opmode_oneshot =0x000000 # sends command as one chunk. Reply will also come as one chunk. Doesn't wait for the reply.
+simx_opmode_blocking =0x010000 # sends command as one chunk. Reply will also come as one chunk. Waits for the reply (_REPLY_WAIT_TIMEOUT_IN_MS is the timeout).
+simx_opmode_oneshot_wait =0x010000 # sends command as one chunk. Reply will also come as one chunk. Waits for the reply (_REPLY_WAIT_TIMEOUT_IN_MS is the timeout).
+simx_opmode_continuous =0x020000
+simx_opmode_streaming =0x020000 # sends command as one chunk. Command will be stored on the server and always executed
+ #(every x ms (as far as possible) where x can be 0-65535. just add x to opmode_continuous).
+ # A reply will be sent continuously each time as one chunk. Doesn't wait for the reply.
+
+# Operation modes for heavy data
+simx_opmode_oneshot_split =0x030000 # sends command as several chunks (max chunk size is x bytes where x can be _MIN_SPLIT_AMOUNT_IN_BYTES-65535. Just add x to opmode_oneshot_split). Reply will also come as several chunks. Doesn't wait for the reply.
+simx_opmode_continuous_split =0x040000
+simx_opmode_streaming_split =0x040000 # sends command as several chunks (max chunk size is x bytes where x can be _MIN_SPLIT_AMOUNT_IN_BYTES-65535. Just add x to opmode_continuous_split). Command will be stored on the server and always executed. A reply will be sent continuously each time as several chunks. Doesn't wait for the reply.
+
+# Special operation modes
+simx_opmode_discontinue =0x050000 # removes and cancels all commands stored on the client or server side (also continuous commands)
+simx_opmode_buffer =0x060000 # doesn't send anything but checks if a reply for the given command is available in the input buffer (i.e. previously received from the server)
+simx_opmode_remove =0x070000 # doesn't send anything and doesn't return any specific value. It just erases a similar command reply in the inbox (to free some memory)
+
+
+# Command return codes
+simx_return_ok =0x000000
+simx_return_novalue_flag =0x000001 # input buffer doesn't contain the specified command
+simx_return_timeout_flag =0x000002 # command reply not received in time for opmode_oneshot_wait operation mode
+simx_return_illegal_opmode_flag =0x000004 # command doesn't support the specified operation mode
+simx_return_remote_error_flag =0x000008 # command caused an error on the server side
+simx_return_split_progress_flag =0x000010 # previous similar command not yet fully processed (applies to opmode_oneshot_split operation modes)
+simx_return_local_error_flag =0x000020 # command caused an error on the client side
+simx_return_initialize_error_flag =0x000040 # simxStart was not yet called
+
+# Following for backward compatibility (same as above)
+simx_error_noerror =0x000000
+simx_error_novalue_flag =0x000001 # input buffer doesn't contain the specified command
+simx_error_timeout_flag =0x000002 # command reply not received in time for opmode_oneshot_wait operation mode
+simx_error_illegal_opmode_flag =0x000004 # command doesn't support the specified operation mode
+simx_error_remote_error_flag =0x000008 # command caused an error on the server side
+simx_error_split_progress_flag =0x000010 # previous similar command not yet fully processed (applies to opmode_oneshot_split operation modes)
+simx_error_local_error_flag =0x000020 # command caused an error on the client side
+simx_error_initialize_error_flag =0x000040 # simxStart was not yet called
+
+
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/simpleSynchronousTest.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/simpleSynchronousTest.py
new file mode 100644
index 0000000..a1669ee
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/simpleSynchronousTest.py
@@ -0,0 +1,58 @@
+# This small example illustrates how to use the remote API
+# synchronous mode. The synchronous mode needs to be
+# pre-enabled on the server side. You would do this by
+# starting the server (e.g. in a child script) with:
+#
+# simRemoteApi.start(19999,1300,false,true)
+#
+# But in this example we try to connect on port
+# 19997 where there should be a continuous remote API
+# server service already running and pre-enabled for
+# synchronous mode.
+#
+#
+# IMPORTANT: for each successful call to simxStart, there
+# should be a corresponding call to simxFinish at the end!
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import time
+import sys
+
+print ('Program started')
+sim.simxFinish(-1) # just in case, close all opened connections
+clientID=sim.simxStart('127.0.0.1',19997,True,True,5000,5) # Connect to CoppeliaSim
+if clientID!=-1:
+ print ('Connected to remote API server')
+
+ # enable the synchronous mode on the client:
+ sim.simxSynchronous(clientID,True)
+
+ # start the simulation:
+ sim.simxStartSimulation(clientID,sim.simx_opmode_blocking)
+
+ # Now step a few times:
+ for i in range(1,10):
+ if sys.version_info[0] == 3:
+ input('Press key to step the simulation!')
+ else:
+ raw_input('Press key to step the simulation!')
+ sim.simxSynchronousTrigger(clientID);
+
+ # stop the simulation:
+ sim.simxStopSimulation(clientID,sim.simx_opmode_blocking)
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(clientID)
+else:
+ print ('Failed connecting to remote API server')
+print ('Program ended')
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/simpleTest.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/simpleTest.py
new file mode 100644
index 0000000..b58bddc
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/simpleTest.py
@@ -0,0 +1,59 @@
+# Make sure to have the server side running in CoppeliaSim:
+# in a child script of a CoppeliaSim scene, add following command
+# to be executed just once, at simulation start:
+#
+# simRemoteApi.start(19999)
+#
+# then start simulation, and run this program.
+#
+# IMPORTANT: for each successful call to simxStart, there
+# should be a corresponding call to simxFinish at the end!
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import time
+
+print ('Program started')
+sim.simxFinish(-1) # just in case, close all opened connections
+clientID=sim.simxStart('127.0.0.1',19999,True,True,5000,5) # Connect to CoppeliaSim
+if clientID!=-1:
+ print ('Connected to remote API server')
+
+ # Now try to retrieve data in a blocking fashion (i.e. a service call):
+ res,objs=sim.simxGetObjects(clientID,sim.sim_handle_all,sim.simx_opmode_blocking)
+ if res==sim.simx_return_ok:
+ print ('Number of objects in the scene: ',len(objs))
+ else:
+ print ('Remote API function call returned with error code: ',res)
+
+ time.sleep(2)
+
+ # Now retrieve streaming data (i.e. in a non-blocking fashion):
+ startTime=time.time()
+ sim.simxGetIntegerParameter(clientID,sim.sim_intparam_mouse_x,sim.simx_opmode_streaming) # Initialize streaming
+ while time.time()-startTime < 5:
+ returnCode,data=sim.simxGetIntegerParameter(clientID,sim.sim_intparam_mouse_x,sim.simx_opmode_buffer) # Try to retrieve the streamed data
+ if returnCode==sim.simx_return_ok: # After initialization of streaming, it will take a few ms before the first value arrives, so check the return code
+ print ('Mouse position x: ',data) # Mouse position x is actualized when the cursor is over CoppeliaSim's window
+ time.sleep(0.005)
+
+ # Now send some data to CoppeliaSim in a non-blocking fashion:
+ sim.simxAddStatusbarMessage(clientID,'Hello CoppeliaSim!',sim.simx_opmode_oneshot)
+
+ # Before closing the connection to CoppeliaSim, make sure that the last command sent out had time to arrive. You can guarantee this with (for example):
+ sim.simxGetPingTime(clientID)
+
+ # Now close the connection to CoppeliaSim:
+ sim.simxFinish(clientID)
+else:
+ print ('Failed connecting to remote API server')
+print ('Program ended')
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/synchronousImageTransmission.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/synchronousImageTransmission.py
new file mode 100644
index 0000000..dd21748
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/synchronousImageTransmission.py
@@ -0,0 +1,89 @@
+# Make sure to have CoppeliaSim running, with followig scene loaded:
+#
+# scenes/synchronousImageTransmissionViaRemoteApi.ttt
+#
+# Do not launch simulation, but run this script
+#
+# The client side (i.e. this script) depends on:
+#
+# sim.py, simConst.py, and the remote API library available
+# in programming/remoteApiBindings/lib/lib
+
+try:
+ import sim
+except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+import math
+import time
+
+class Client:
+ def __enter__(self):
+ self.intSignalName='legacyRemoteApiStepCounter'
+ self.stepCounter=0
+ self.lastImageAcquisitionTime=-1
+ sim.simxFinish(-1) # just in case, close all opened connections
+ self.id=sim.simxStart('127.0.0.1',19997,True,True,5000,5) # Connect to CoppeliaSim
+ return self
+
+ def __exit__(self,*err):
+ sim.simxFinish(-1)
+
+with Client() as client:
+ client.runInSynchronousMode=True
+
+ print("running")
+
+ if client.id!=-1:
+ print ('Connected to remote API server')
+
+ def stepSimulation():
+ if client.runInSynchronousMode:
+ currentStep=client.stepCounter
+ sim.simxSynchronousTrigger(client.id);
+ while client.stepCounter==currentStep:
+ retCode,s=sim.simxGetIntegerSignal(client.id,client.intSignalName,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ client.stepCounter=s
+ retCode,res,img=sim.simxGetVisionSensorImage(client.id,client.visionSensorHandle,0,sim.simx_opmode_buffer)
+ client.lastImageAcquisitionTime=sim.simxGetLastCmdTime(client.id)
+ if retCode==sim.simx_return_ok:
+ sim.simxSetVisionSensorImage(client.id,client.passiveVisionSensorHandle,img,0,sim.simx_opmode_oneshot)
+ else:
+ retCode,res,img=sim.simxGetVisionSensorImage(client.id,client.visionSensorHandle,0,sim.simx_opmode_buffer)
+ if retCode==sim.simx_return_ok:
+ imageSimTime=sim.simxGetLastCmdTime(client.id)
+ if client.lastImageAcquisitionTime!=imageSimTime:
+ client.lastImageAcquisitionTime=imageSimTime
+ sim.simxSetVisionSensorImage(client.id,client.passiveVisionSensorHandle,img,0,sim.simx_opmode_oneshot)
+
+ # Start streaming client.intSignalName integer signal, that signals when a step is finished:
+ sim.simxGetIntegerSignal(client.id,client.intSignalName,sim.simx_opmode_streaming)
+
+ res,client.visionSensorHandle=sim.simxGetObjectHandle(client.id,'VisionSensor',sim.simx_opmode_blocking)
+ res,client.passiveVisionSensorHandle=sim.simxGetObjectHandle(client.id,'PassiveVisionSensor',sim.simx_opmode_blocking)
+
+ # Start streaming the vision sensor image:
+ sim.simxGetVisionSensorImage(client.id,client.visionSensorHandle,0,sim.simx_opmode_streaming)
+
+ # enable the synchronous mode on the client:
+ if client.runInSynchronousMode:
+ sim.simxSynchronous(client.id,True)
+
+ sim.simxStartSimulation(client.id,sim.simx_opmode_oneshot)
+
+ startTime=time.time()
+ while time.time()-startTime < 5:
+ stepSimulation()
+
+ # stop data streaming
+ sim.simxGetIntegerSignal(client.id,client.intSignalName,sim.simx_opmode_discontinue)
+ sim.simxGetVisionSensorImage(client.id,client.visionSensorHandle,0,sim.simx_opmode_discontinue)
+
+ sim.simxStopSimulation(client.id,sim.simx_opmode_blocking)
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/visualization.py b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/visualization.py
new file mode 100644
index 0000000..ff3dbc8
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/VREP_RemoteAPIs/visualization.py
@@ -0,0 +1,517 @@
+# -*- coding: utf-8 -*-
+"""Code for visualizing data in sim via python.
+
+Author: Andrew Hundt
+
+License: Apache v2 https://www.apache.org/licenses/LICENSE-2.0
+"""
+import os
+import errno
+import traceback
+
+import numpy as np
+import six # compatibility between python 2 + 3 = six
+import matplotlib.pyplot as plt
+
+try:
+ import sim as sim
+except Exception as e:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in PYTHONPATH folder relative to this file,')
+ print ('or appropriately adjust the file "sim.py. Also follow the"')
+ print ('ReadMe.txt in the sim remote API folder')
+ print ('--------------------------------------------------------------')
+ print ('')
+ raise e
+
+import tensorflow as tf
+
+from tensorflow.python.platform import flags
+from tensorflow.python.platform import gfile
+from tensorflow.python.ops import data_flow_ops
+from ply import write_xyz_rgb_as_ply
+from PIL import Image
+
+# progress bars https://github.com/tqdm/tqdm
+# import tqdm without enforcing it as a dependency
+try:
+ from tqdm import tqdm
+except ImportError:
+
+ def tqdm(*args, **kwargs):
+ if args:
+ return args[0]
+ return kwargs.get('iterable', None)
+
+from depth_image_encoding import ClipFloatValues
+from depth_image_encoding import FloatArrayToRgbImage
+from depth_image_encoding import FloatArrayToRawRGB
+from skimage.transform import resize
+from skimage import img_as_ubyte
+from skimage import img_as_uint
+from skimage.color import grey2rgb
+
+try:
+ import eigen # https://github.com/jrl-umi3218/Eigen3ToPython
+ import sva # https://github.com/jrl-umi3218/SpaceVecAlg
+except ImportError:
+ print('eigen and sva python modules are not available. To install run the script at:'
+ 'https://github.com/ahundt/robotics_setup/blob/master/robotics_tasks.sh'
+ 'or follow the instructions at https://github.com/jrl-umi3218/Eigen3ToPython'
+ 'and https://github.com/jrl-umi3218/SpaceVecAlg. '
+ 'When you build the modules make sure python bindings are enabled.')
+
+tf.flags.DEFINE_string('csimVisualizeDepthFormat', 'csim_depth_encoded_rgb',
+ """ Controls how Depth images are displayed. Options are:
+ None: Do not modify the data and display it as-is for rgb input data (not working properly for float depth).
+ 'depth_rgb': convert a floating point depth image to a straight 0-255 encoding of depths less than 3m
+ 'depth_encoded_rgb': convert a floating point depth image to the rgb encoding used by
+ the google brain robot data grasp dataset's raw png depth image encoding,
+ see https://sites.google.com/site/brainrobotdata/home/depth-image-encoding.
+ 'sim': add a sim prefix to any of the above commands to
+ rotate image by 180 degrees, flip left over right, then invert the color channels
+ after the initial conversion step.
+ This is due to a problem where CoppeliaSim seems to display images differently.
+ Examples include 'csim_depth_rgb' and 'csim_depth_encoded_rgb',
+ see http://forum.coppeliarobotics.com/viewtopic.php?f=9&t=737&p=27805#p27805.
+ """)
+tf.flags.DEFINE_string('csimVisualizeRGBFormat', 'csim_rgb',
+ """ Controls how images are displayed. Options are:
+ None: Do not modify the data and display it as-is for rgb input data (not working properly for float depth).
+ 'depth_rgb': convert a floating point depth image to a straight 0-255 encoding of depths less than 3m
+ 'depth_encoded_rgb': convert a floating point depth image to the rgb encoding used by
+ the google brain robot data grasp dataset's raw png depth image encoding,
+ see https://sites.google.com/site/brainrobotdata/home/depth-image-encoding.
+ 'sim': add a sim prefix to any of the above commands to
+ rotate image by 180 degrees, flip left over right, then invert the color channels
+ after the initial conversion step.
+ This is due to a problem where CoppeliaSim seems to display images differently.
+ Examples include 'csim_depth_rgb' and 'csim_depth_encoded_rgb',
+ see http://forum.coppeliarobotics.com/viewtopic.php?f=9&t=737&p=27805#p27805.
+ """)
+
+# the following line is needed for tf versions before 1.5
+# flags.FLAGS._parse_flags()
+FLAGS = flags.FLAGS
+
+
+def depth_image_to_point_cloud(depth, intrinsics_matrix, dtype=np.float32, verbose=0):
+ """Depth images become an XYZ point cloud in the camera frame with shape (depth.shape[0], depth.shape[1], 3).
+
+ Transform a depth image into a point cloud in the camera frame with one point for each
+ pixel in the image, using the camera transform for a camera
+ centred at cx, cy with field of view fx, fy.
+
+ Based on:
+ https://github.com/tensorflow/models/blob/master/research/cognitive_mapping_and_planning/src/depth_utils.py
+ https://codereview.stackexchange.com/a/84990/10101
+
+ also see grasp_geometry_tf.depth_image_to_point_cloud().
+
+ # Arguments
+
+ depth: is a 2-D ndarray with shape (rows, cols) containing
+ 32bit floating point depths in meters. The result is a 3-D array with
+ shape (rows, cols, 3). Pixels with invalid depth in the input have
+ NaN or 0 for the z-coordinate in the result.
+
+ intrinsics_matrix: 3x3 matrix for projecting depth values to z values
+ in the point cloud frame. http://ksimek.github.io/2013/08/13/intrinsic/
+ In this case x0, y0 are at index [2, 0] and [2, 1], respectively.
+
+ transform: 4x4 Rt matrix for rotating and translating the point cloud
+ """
+ fy = intrinsics_matrix[1, 1]
+ fx = intrinsics_matrix[0, 0]
+ # center of image y coordinate
+ center_y = intrinsics_matrix[2, 1]
+ # center of image x coordinate
+ center_x = intrinsics_matrix[2, 0]
+ depth = np.squeeze(depth)
+ y_range, x_range = depth.shape
+
+ y, x = np.meshgrid(np.arange(y_range),
+ np.arange(x_range),
+ indexing='ij')
+ assert y.size == x.size and y.size == depth.size
+ x = x.flatten()
+ y = y.flatten()
+ depth = depth.flatten()
+
+ X = (x - center_x) * depth / fx
+ Y = (y - center_y) * depth / fy
+
+ assert X.size == Y.size and X.size == depth.size
+ assert X.shape == Y.shape and X.shape == depth.shape
+
+ if verbose > 0:
+ print('X np: ', X.shape)
+ print('Y np: ', Y.shape)
+ print('depth np: ', depth.shape)
+ XYZ = np.column_stack([X, Y, depth])
+ assert XYZ.shape == (y_range * x_range, 3)
+ if verbose > 0:
+ print('XYZ pre reshape np: ', XYZ.shape)
+ XYZ = XYZ.reshape((y_range, x_range, 3))
+
+ return XYZ.astype(dtype)
+
+
+def csimPrint(client_id, message):
+ """Print a message in both the python command line and on the CoppeliaSim Statusbar.
+
+ The Statusbar is the white command line output on the bottom of the CoppeliaSim GUI window.
+ """
+ sim.simxAddStatusbarMessage(client_id, message, sim.simx_opmode_oneshot)
+ print(message)
+
+
+def create_dummy(client_id, display_name, transform=None, parent_handle=-1, debug=FLAGS.csimDebugMode, operation_mode=sim.simx_opmode_blocking):
+ """Create a dummy object in the simulation
+
+ # Arguments
+
+ transform_display_name: name string to use for the object in the sim scene
+ transform: 3 cartesian (x, y, z) and 4 quaternion (x, y, z, w) elements, same as sim
+ parent_handle: -1 is the world frame, any other int should be a sim object handle
+ """
+ if transform is None:
+ transform = np.array([0., 0., 0., 0., 0., 0., 1.])
+ # 2. Now create a dummy object at coordinate 0.1,0.2,0.3 with name 'MyDummyName':
+ empty_buffer = bytearray()
+ res, ret_ints, ret_floats, ret_strings, ret_buffer = sim.simxCallScriptFunction(
+ client_id,
+ 'remoteApiCommandServer',
+ sim.sim_scripttype_childscript,
+ 'createDummy_function',
+ [parent_handle],
+ transform,
+ [display_name],
+ empty_buffer,
+ operation_mode)
+ if res == sim.simx_return_ok:
+ # display the reply from CoppeliaSim (in this case, the handle of the created dummy)
+ if debug is not None and 'print_transform' in debug:
+ print ('Dummy name:', display_name, ' handle: ', ret_ints[0], ' transform: ', transform)
+ else:
+ print('create_dummy remote function call failed.')
+ print(''.join(traceback.format_stack()))
+ return -1
+ return ret_ints[0]
+
+
+def setPose(client_id, display_name, transform=None, parent_handle=-1):
+ """Set the pose of an object in the simulation
+
+ # Arguments
+
+ transform_display_name: name string to use for the object in the sim scene
+ transform: 3 cartesian (x, y, z) and 4 quaternion (x, y, z, w) elements, same as sim
+ parent_handle: -1 is the world frame, any other int should be a sim object handle
+ """
+ if transform is None:
+ transform = np.array([0., 0., 0., 0., 0., 0., 1.])
+ # 2. Now create a dummy object at coordinate 0.1,0.2,0.3 with name 'MyDummyName':
+ empty_buffer = bytearray()
+ res, ret_ints, ret_floats, ret_strings, ret_buffer = sim.simxCallScriptFunction(
+ client_id,
+ 'remoteApiCommandServer',
+ sim.sim_scripttype_childscript,
+ 'createDummy_function',
+ [parent_handle],
+ transform,
+ [display_name],
+ empty_buffer,
+ sim.simx_opmode_blocking)
+ if res == sim.simx_return_ok:
+ # display the reply from CoppeliaSim (in this case, the handle of the created dummy)
+ print ('SetPose object name:', display_name, ' handle: ', ret_ints[0], ' transform: ', transform)
+ else:
+ print('setPose remote function call failed.')
+ print(''.join(traceback.format_stack()))
+ return -1
+ return ret_ints[0]
+
+
+def set_vision_sensor_image(client_id, display_name, image, convert=None, scale_factor=256000.0, operation_mode=sim.simx_opmode_oneshot_wait):
+ """Display vision sensor image data in a CoppeliaSim simulation.
+
+ [CoppeliaSim Vision Sensors](http://www.coppeliarobotics.com/helpFiles/en/visionSensors.htm)
+ [simSetVisionSensorImage](http://www.coppeliarobotics.com/helpFiles/en/apiFunctions.htm#simSetVisionSensorImage)
+
+ # Arguments
+
+ display_name: the string display name of the sensor object in the CoppeliaSim scene
+ image: an rgb char array containing an image
+ convert: Controls how images are displayed. Options are:
+ None: Do not modify the data and display it as-is for rgb input data (not working properly for float depth).
+ 'depth_rgb': convert a floating point depth image to a straight 0-255 encoding of depths less than 3m
+ 'depth_encoded_rgb': convert a floating point depth image to the rgb encoding used by
+ the google brain robot data grasp dataset's raw png depth image encoding,
+ see https://sites.google.com/site/brainrobotdata/home/depth-image-encoding.
+ 'sim': add a sim prefix to any of the above commands to
+ rotate image by 180 degrees, flip left over right, then invert the color channels
+ after the initial conversion step.
+ This is due to a problem where CoppeliaSim seems to display images differently.
+ Examples include 'csim_depth_rgb' and 'csim_depth_encoded_rgb',
+ see http://www.forum.coppeliarobotics.com/viewtopic.php?f=9&t=737&p=27805#p27805.
+ """
+ strings = [display_name]
+ parent_handle = -1
+
+ # TODO(ahundt) support is_greyscale True again
+ is_greyscale = 0
+ csim_conversion = False
+ if convert is not None:
+ csim_conversion = 'sim' in convert
+
+ if 'depth_encoded_rgb' in convert:
+ image = np.array(FloatArrayToRgbImage(image, scale_factor=scale_factor, drop_blue=False), dtype=np.uint8)
+ elif 'depth_rgb' in convert:
+
+ image = img_as_uint(image)
+
+ elif not csim_conversion:
+ raise ValueError('set_vision_sensor_image() convert parameter must be one of `depth_encoded_rgb`, `depth_rgb`, or None'
+ 'with the optional addition of the word `sim` to rotate 180, flip left right, then invert colors.')
+
+ if csim_conversion:
+ # rotate 180 degrees, flip left over right, then invert the colors
+ image = np.array(256 - np.fliplr(np.rot90(image, 2)), dtype=np.uint8)
+
+ if np.issubdtype(image.dtype, np.integer):
+ is_float = 0
+ floats = []
+ color_buffer = bytearray(image.flatten().tobytes())
+ color_size = image.size
+ num_floats = 0
+ else:
+ is_float = 1
+ floats = [image]
+ color_buffer = bytearray()
+ num_floats = image.size
+ color_size = 0
+
+ cloud_handle = -1
+ res, ret_ints, ret_floats, ret_strings, ret_buffer = sim.simxCallScriptFunction(
+ client_id,
+ 'remoteApiCommandServer',
+ sim.sim_scripttype_childscript,
+ 'setVisionSensorImage_function',
+ [parent_handle, num_floats, is_greyscale, color_size], # int params
+ np.append(floats, []), # float params
+ strings, # string params
+ # byte buffer params
+ color_buffer,
+ operation_mode)
+ if res == sim.simx_return_ok:
+ print ('point cloud handle: ', ret_ints[0]) # display the reply from CoppeliaSim (in this case, the handle of the created dummy)
+ # set the transform for the point cloud
+ return ret_ints[0]
+ else:
+ print('insertPointCloud_function remote function call failed.')
+ print(''.join(traceback.format_stack()))
+ return res
+
+
+def create_point_cloud(client_id, display_name, transform=None, point_cloud=None, depth_image=None, color_image=None,
+ camera_intrinsics_matrix=None, parent_handle=-1, clear=True,
+ max_voxel_size=0.01, max_point_count_per_voxel=10, point_size=10, options=8,
+ rgb_sensor_display_name=None, depth_sensor_display_name=None, convert_depth=FLAGS.csimVisualizeDepthFormat,
+ convert_rgb=FLAGS.csimVisualizeRGBFormat, save_ply_path=None, rgb_display_mode='vision_sensor'):
+ """Create a point cloud object in the simulation, plus optionally render the depth and rgb images.
+
+ # Arguments
+
+ display_name: name string to use for the object in the sim scene
+ depth_image: A depth image of size [width, height, 3]
+ transform: [x, y, z, qw, qx, qy, qz] with 3 cartesian (x, y, z) and 4 quaternion (qx, qy, qz, qw) elements, same as sim
+ This transform is from the parent handle to the point cloud base
+ parent_handle: -1 is the world frame, any other int should be a sim object handle
+ clear: clear the point cloud if it already exists with the provided display name
+ maxVoxelSize: the maximum size of the octree voxels containing points
+ maxPtCntPerVoxel: the maximum number of points allowed in a same octree voxel
+ options: bit-coded:
+ bit0 set (1): points have random colors
+ bit1 set (2): show octree structure
+ bit2 set (4): reserved. keep unset
+ bit3 set (8): do not use an octree structure. When enabled, point cloud operations are limited, and point clouds will not be collidable, measurable or detectable anymore, but adding points will be much faster
+ bit4 set (16): color is emissive
+ pointSize: the size of the points, in pixels
+ reserved: reserved for future extensions. Set to NULL
+ save_ply_path: save out a ply file with the point cloud data
+ point_cloud: optional XYZ point cloud of size [width, height, 3], will be generated if not provided.
+ convert_rgb: Controls how images are displayed. Options are:
+ None: Do not modify the data and display it as-is for rgb input data (not working properly for float depth).
+ 'depth_rgb': convert a floating point depth image to a straight 0-255 encoding of depths less than 3m
+ 'depth_encoded_rgb': convert a floating point depth image to the rgb encoding used by
+ the google brain robot data grasp dataset's raw png depth image encoding,
+ see https://sites.google.com/site/brainrobotdata/home/depth-image-encoding.
+ 'sim': add a sim prefix to any of the above commands to
+ rotate image by 180 degrees, flip left over right, then invert the color channels
+ after the initial conversion step.
+ This is due to a problem where CoppeliaSim seems to display images differently.
+ Examples include 'csim_depth_rgb' and 'csim_depth_encoded_rgb',
+ see http://www.forum.coppeliarobotics.com/viewtopic.php?f=9&t=737&p=27805#p27805.
+ rgb_display_mode: Options help with working around quirks in input image data's layout.
+ 'point_cloud' to display the image when the point cloud is being generated.
+ 'vision_sensor' to make a separate call go the vison sensor display function.
+ """
+ if transform is None:
+ transform = np.array([0., 0., 0., 0., 0., 0., 1.])
+
+ if point_cloud is None:
+ point_cloud = depth_image_to_point_cloud(depth_image, camera_intrinsics_matrix)
+ point_cloud = point_cloud.reshape([point_cloud.size/3, 3])
+
+ # show the depth sensor image
+ if depth_sensor_display_name is not None and depth_image is not None:
+ # matplotlib.image.imsave(display_name + depth_sensor_display_name + '_norotfliplr.png', depth_image)
+ # rotate 180, flip left over right then invert the image colors for display in CoppeliaSim
+ # depth_image = np.fliplr(np.rot90(depth_image, 2))
+ # matplotlib.image.imsave(display_name + depth_sensor_display_name + '_rot90fliplr.png', depth_image)
+ set_vision_sensor_image(client_id, depth_sensor_display_name, depth_image, convert=convert_depth)
+
+ # show the rgb sensor image, this overwrites the rgb display
+ # done in insertPointCloud_function, which is buggy
+ if rgb_sensor_display_name is not None and color_image is not None and rgb_display_mode == 'vision_sensor':
+ # matplotlib.image.imsave(display_name + rgb_sensor_display_name + '_norotfliplr.png', color_image)
+ # rotate 180, flip left over right then invert the image colors for display in CoppeliaSim
+ # matplotlib.image.imsave(display_name + rgb_sensor_display_name + '_rot90fliplr.png', color_image)
+ set_vision_sensor_image(client_id, rgb_sensor_display_name, color_image, convert=convert_rgb)
+
+ # Save out Point cloud
+ if save_ply_path is not None:
+ write_xyz_rgb_as_ply(point_cloud, color_image, save_ply_path)
+
+ # color_buffer is initially empty
+ color_buffer = bytearray()
+ strings = [display_name]
+ if rgb_sensor_display_name is not None and rgb_display_mode == 'point_cloud':
+ strings = [display_name, rgb_sensor_display_name]
+
+ transform_entries = 7
+ if clear:
+ clear = 1
+ else:
+ clear = 0
+
+ cloud_handle = -1
+ # Create the point cloud if it does not exist, or retrieve the handle if it does
+ res, ret_ints, ret_floats, ret_strings, ret_buffer = sim.simxCallScriptFunction(
+ client_id,
+ 'remoteApiCommandServer',
+ sim.sim_scripttype_childscript,
+ 'createPointCloud_function',
+ # int params
+ [parent_handle, transform_entries, point_cloud.size, cloud_handle, clear, max_point_count_per_voxel, options, point_size],
+ # float params
+ [max_voxel_size],
+ # string params
+ strings,
+ # byte buffer params
+ color_buffer,
+ sim.simx_opmode_blocking)
+
+ setPose(client_id, display_name, transform, parent_handle)
+
+ if res == sim.simx_return_ok:
+ cloud_handle = ret_ints[0]
+
+ # convert the rgb values to a string
+ color_size = 0
+ if color_image is not None:
+ # see simInsertPointsIntoPointCloud() in sim documentation
+ # 3 indicates the cloud should be in the parent frame, and color is enabled
+ # bit 2 is 1 so each point is colored
+ simInsertPointsIntoPointCloudOptions = 3
+ # color_buffer = bytearray(np.fliplr(np.rot90(color_image, 3)).flatten().tobytes())
+ color_buffer = bytearray(color_image.flatten().tobytes())
+ color_size = color_image.size
+ else:
+ simInsertPointsIntoPointCloudOptions = 1
+
+ # Actually transfer the point cloud
+ res, ret_ints, ret_floats, ret_strings, ret_buffer = sim.simxCallScriptFunction(
+ client_id,
+ 'remoteApiCommandServer',
+ sim.sim_scripttype_childscript,
+ 'insertPointCloud_function',
+ [parent_handle, transform_entries, point_cloud.size, cloud_handle, color_size, simInsertPointsIntoPointCloudOptions],
+ np.append(point_cloud, []),
+ strings,
+ color_buffer,
+ sim.simx_opmode_blocking)
+
+ if res == sim.simx_return_ok:
+ print ('point cloud handle: ', ret_ints[0]) # display the reply from CoppeliaSim (in this case, the handle of the created dummy)
+ # set the transform for the point cloud
+ return ret_ints[0]
+ else:
+ print('insertPointCloud_function remote function call failed.')
+ print(''.join(traceback.format_stack()))
+ return res
+
+ else:
+ print('createPointCloud_function remote function call failed')
+ print(''.join(traceback.format_stack()))
+ return res
+
+
+def drawLines(client_id, display_name, lines, parent_handle=-1, transform=None, debug=FLAGS.csimDebugMode, operation_mode=sim.simx_opmode_blocking):
+ """Create a line in the simulation.
+
+ Note that there are currently some quirks with this function. Only one line is accepted,
+ and sometimes CoppeliaSim fails to delete the object correctly and lines will fail to draw.
+ In that case you need to close and restart CoppeliaSim.
+
+ # Arguments
+
+ transform_display_name: name string to use for the object in the sim scene
+ transform: 3 cartesian (x, y, z) and 4 quaternion (x, y, z, w) elements, same as sim
+ parent_handle: -1 is the world frame, any other int should be a sim object handle
+ lines: array of line definitions using two endpoints (x0, y0, z0, x1, y1, z1).
+ Multiple lines can be defined but there should be 6 entries (two points) per line.
+ """
+ # 2. Now create a dummy object at coordinate 0.1,0.2,0.3 with name 'MyDummyName':
+ empty_buffer = bytearray()
+ res, ret_ints, ret_floats, ret_strings, ret_buffer = sim.simxCallScriptFunction(
+ client_id,
+ 'remoteApiCommandServer',
+ sim.sim_scripttype_childscript,
+ 'addDrawingObject_function',
+ [parent_handle, int(lines.size/6)],
+ # np.append(transform, lines),
+ lines,
+ [display_name],
+ empty_buffer,
+ operation_mode)
+ if res == sim.simx_return_ok:
+ # display the reply from CoppeliaSim (in this case, the handle of the created dummy)
+ if debug is not None and 'print_drawLines' in debug:
+ print ('drawLines name:', display_name, ' handle: ', ret_ints[0], ' transform: ', transform)
+
+ if transform is not None:
+ # set the transform for the point cloud
+ setPose(client_id, display_name, transform, parent_handle)
+ else:
+ print('drawLines remote function call failed.')
+ print(''.join(traceback.format_stack()))
+ return -1
+ return ret_ints[0]
+
+
+def restore_cropped(cropped_image, crop_size, crop_offset, full_size):
+ """ Restore cropped_image to full size image with zero padding
+ First scale image back to crop_size, then padding
+ """
+
+ cropped_image = np.squeeze(cropped_image)
+ restored = np.zeros((full_size[0], full_size[1]), dtype=cropped_image.dtype)
+ scaled_crop = resize(cropped_image, (crop_size[0], crop_size[1]))
+ restored[crop_offset[0]:crop_offset[0]+crop_size[0],
+ crop_offset[1]:crop_offset[1]+crop_size[1]] = scaled_crop
+
+ return restored
diff --git a/7_Demo_youBotPickAndPlace/code/vrep/demoRemoteControl.py b/7_Demo_youBotPickAndPlace/code/vrep/demoRemoteControl.py
new file mode 100644
index 0000000..cfc5800
--- /dev/null
+++ b/7_Demo_youBotPickAndPlace/code/vrep/demoRemoteControl.py
@@ -0,0 +1,130 @@
+import time
+import math
+import sys
+sys.path.append('./VREP_remoteAPIs')
+
+''' Inverse kinematics '''
+def chassisInverseKinematics(vx, vy, omega, wheel_R, a, b):
+ omega_1 = (vy - vx + (a+b)*omega)/wheel_R
+ omega_2 = (vy + vx - (a+b)*omega)/wheel_R
+ omega_3 = (vy - vx - (a+b)*omega)/wheel_R
+ omega_4 = (vy + vx + (a+b)*omega)/wheel_R
+
+ # set the direction for each wheel
+ v_wheel = [0,0,0,0]
+ v_wheel[0] = -omega_1
+ v_wheel[1] = -omega_2
+ v_wheel[2] = -omega_3
+ v_wheel[3] = -omega_4
+
+ return v_wheel
+
+''' Arm control function of youBot '''
+def VREP_armControl(vrep_sim, clientID, arm_joints_handle, desired_arm_joint_angles):
+ for i in range(0,5):
+ vrep_sim.simxSetJointPosition(clientID, arm_joints_handle[i], desired_arm_joint_angles[i], vrep_sim.simx_opmode_blocking)
+
+''' Wheels control function of youBot '''
+def VREP_wheelsControl(vrep_sim, clientID, wheel_joints_handle, desired_wheel_velocities):
+ for i in range(0,4):
+ vrep_sim.simxSetJointTargetVelocity(clientID, wheel_joints_handle[i], desired_wheel_velocities[i], vrep_sim.simx_opmode_blocking)
+
+
+if __name__ == '__main__':
+ try:
+ import sim as vrep_sim
+ except:
+ print ('--------------------------------------------------------------')
+ print ('"sim.py" could not be imported. This means very probably that')
+ print ('either "sim.py" or the remoteApi library could not be found.')
+ print ('Make sure both are in the same folder as this file,')
+ print ('or appropriately adjust the file "sim.py"')
+ print ('--------------------------------------------------------------')
+ print ('')
+
+ ''' Initialization '''
+ print ('Program started')
+ vrep_sim.simxFinish(-1) # just in case, close all opened connections
+ clientID = vrep_sim.simxStart('127.0.0.1',19999,True,True,5000,5) # Connect to CoppeliaSim
+ if clientID != -1:
+ print ('Connected to remote API server')
+
+ return_code, youBot_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBot', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot ok.')
+
+ return_code, youBot_dummy_handle = vrep_sim.simxGetObjectHandle(clientID, 'youBotDummy', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBotDummy ok.')
+
+ # Prepare initial values for four wheels
+ wheel_joints_handle = [-1,-1,-1,-1]; # front left, rear left, rear right, front right
+ return_code, wheel_joints_handle[0] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_fr', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_fl ok.')
+
+ return_code, wheel_joints_handle[1] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_fl', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_rl ok.')
+
+ return_code, wheel_joints_handle[2] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_rl', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_rr ok.')
+
+ return_code, wheel_joints_handle[3] = vrep_sim.simxGetObjectHandle(clientID, 'rollingJoint_rr', vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object youBot rollingJoint_fr ok.')
+
+ # Prepare initial values for five arm joints
+ arm_joints_handle = [-1,-1,-1,-1,-1]
+ for i in range(0,4):
+ return_code, arm_joints_handle[i] = vrep_sim.simxGetObjectHandle(clientID, 'youBotArmJoint' + str(i), vrep_sim.simx_opmode_blocking)
+ if (return_code == vrep_sim.simx_return_ok):
+ print('get object arm joint ' + str(i) + ' ok.')
+
+ # Desired joint positions for initialization
+ desired_arm_joint_angles = [180*math.pi/180, 30.91*math.pi/180, 52.42*math.pi/180, 72.68*math.pi/180, 0]
+
+ # Initialization all arm joints
+ for i in range(0,4):
+ vrep_sim.simxSetJointPosition(clientID, arm_joints_handle[i], desired_arm_joint_angles[i], vrep_sim.simx_opmode_blocking)
+ else:
+ print ('Failed connecting to remote API server')
+
+
+ # Size information for youBot
+ wheel_R = 0.05
+ a = 0.165
+ b = 0.228
+
+ # User variables
+ simu_time = 0
+ center_velocity = [0,0,0]
+ desired_wheel_velocities = [0,0,0,0]
+
+ ''' Main control loop '''
+ print('begin main control loop ...')
+ while True:
+ # Motion planning
+ simu_time = simu_time + 0.05
+
+ for i in range(0,5):
+ if int(simu_time) % 2 == 0:
+ desired_arm_joint_angles[i] = desired_arm_joint_angles[i] - 0.04 # rad
+ else:
+ desired_arm_joint_angles[i] = desired_arm_joint_angles[i] + 0.04 # rad
+
+ # Control the youBot robot
+ VREP_armControl(vrep_sim, clientID, arm_joints_handle, desired_arm_joint_angles)
+ VREP_wheelsControl(vrep_sim, clientID, wheel_joints_handle, desired_wheel_velocities)
+
+
+ # Now send some data to CoppeliaSim in a non-blocking fashion:
+ vrep_sim.simxAddStatusbarMessage(clientID,'Over!',vrep_sim.simx_opmode_oneshot)
+
+ # Before closing the connection to CoppeliaSim, make sure that the last command sent out had time to arrive. You can guarantee this with (for example):
+ vrep_sim.simxGetPingTime(clientID)
+
+ # Now close the connection to CoppeliaSim:
+ vrep_sim.simxFinish(clientID)
+ print ('Program ended')
diff --git a/7_Demo_youBotPickAndPlace/vrep_scenes/youBot_pick_and_place.ttt b/7_Demo_youBotPickAndPlace/vrep_scenes/youBot_pick_and_place.ttt
new file mode 100644
index 0000000..4fd1098
Binary files /dev/null and b/7_Demo_youBotPickAndPlace/vrep_scenes/youBot_pick_and_place.ttt differ
diff --git a/7_Demo_youBotPickAndPlace/youBotPickAndPlace.gif b/7_Demo_youBotPickAndPlace/youBotPickAndPlace.gif
new file mode 100644
index 0000000..5ded6c4
Binary files /dev/null and b/7_Demo_youBotPickAndPlace/youBotPickAndPlace.gif differ
diff --git a/README.md b/README.md
index d78a777..6a5b7e2 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,11 @@ YouBot机器人的第一个简单控制代码,可以作为入门级学习代

+## 7. Demo_MatlabAndPythonControl
+使用Python编写控制代码远程控制V-REP中的YouBot机器人模型完成从A点抓取物体并移动到B点的任务。
+
+
## 文章教程