code: def inverse_kinematics(
          self,
          target_position_right,
          target_orientation_right,
          target_position_left,
          target_orientation_left,
          rest_poses,
      ):
          
  
          ndof = 48
  
          ik_solution = list(
              p.calculateInverseKinematics(
                  self.ik_robot,
                  self.effector_right,
                  target_position_right,
                  targetOrientation=target_orientation_right,
                  restPoses=rest_poses[:7],
                  lowerLimits=self.lower,
                  upperLimits=self.upper,
                  jointRanges=self.ranges,
                  jointDamping=[0.7] * ndof,
              )
          )
          ik_solution2 = list(
              p.calculateInverseKinematics(
                  self.ik_robot,
                  self.effector_left,
                  target_position_left,
                  targetOrientation=target_orientation_left,
                  restPoses=rest_poses[7:],
                  lowerLimits=self.lower,
                  upperLimits=self.upper,
                  jointRanges=self.ranges,
                  jointDamping=[0.7] * ndof,
              )
          )
          for i in range(8, 15):
              ik_solution[i] = ik_solution2[i]
  
          return ik_solution[1:]
docs: Helper function to do inverse kinematics for a given target position and
          orientation in the PyBullet world frame.
  
          Args:
              target_position_{right, left}: A tuple, list, or numpy array of size 3 for position.
              target_orientation_{right, left}: A tuple, list, or numpy array of size 4 for
                  a orientation quaternion.
              rest_poses: A list of size @num_joints to favor ik solutions close by.
  
          Returns:
              A list of size @num_joints corresponding to the joint angle solution.