Управляйте перемещениями руки PR2 Используя действия ROS и инверсную кинематику

Этот пример показывает, как отправить команды в автоматизированные манипуляторы в MATLAB®. Объединенные команды положения отправляются через клиент действия ROS по сети ROS. Этот пример также показывает, как вычислить объединенные положения для желаемого положения исполнительного элемента конца. Дерево твердого тела задает геометрию робота и объединенные ограничения, который используется с инверсной кинематикой, чтобы получить положения соединения робота. Можно затем отправить эти объединенные позиции траектории, чтобы управлять, чтобы робот переместился.

Поднимите симуляцию PR2 Gazebo

Породите PR2 в простой среде (только с таблицей, и кокс может) в Средстве моделирования Gazebo. Выполните шаги в Запуске с Gazebo и Моделируемым TurtleBot, чтобы запустить Gazebo PR2 Simulator с рабочего стола виртуальной машины Ubuntu®.

Соединитесь с сетью ROS от MATLAB®

В вашем экземпляре MATLAB на хосте - компьютере запустите следующие команды, чтобы инициализировать глобальный узел ROS в MATLAB и соединить с ведущим устройством ROS в виртуальной машине через ее IP-адрес ipaddress. Замените '192.168.245.130' на IP-адрес своей виртуальной машины. Задайте порт в случае необходимости.

ipaddress = '192.168.203.129';
rosinit(ipaddress,11311);
Initializing global node /matlab_global_node_11112 with NodeURI http://192.168.203.1:59756/

Клиенты действия по созданию для манипуляторов и отправляют команды

В этой задаче вы отправляете объединенные траектории в руки PR2. Руками можно управлять через действия ROS. Объединенные траектории вручную заданы для каждой руки и отправлены, когда отдельная цель обменивается сообщениями через отдельные клиенты действия.

Создайте ROS простой клиент действия, чтобы отправить целевые сообщения, чтобы переместить правую руку робота. Объект rosactionclient и целевое сообщение возвращены. Ожидайте клиента, чтобы соединиться с сервером действия ROS.

[rArm, rGoalMsg] = rosactionclient('r_arm_controller/joint_trajectory_action');
waitForServer(rArm);

Целевое сообщение является сообщением trajectory_msgs/JointTrajectoryPoint. Каждая точка траектории должна задать положения и скорости соединений.

disp(rGoalMsg)
  ROS JointTrajectoryGoal message with properties:

    MessageType: 'pr2_controllers_msgs/JointTrajectoryGoal'
     Trajectory: [1×1 JointTrajectory]

  Use showdetails to show the contents of the message
disp(rGoalMsg.Trajectory)
  ROS JointTrajectory message with properties:

    MessageType: 'trajectory_msgs/JointTrajectory'
         Header: [1×1 Header]
     JointNames: {0×1 cell}
         Points: [0×1 JointTrajectoryPoint]

  Use showdetails to show the contents of the message

Определите объединенные имена, чтобы совпадать с именами соединения робота PR2. Обратите внимание на то, что существует 7 соединений, чтобы управлять. Чтобы найти, какие соединения находятся в правой руке PR2, введите эту команду в терминале виртуальной машины:

rosparam get /r_arm_controller/joints 
rGoalMsg.Trajectory.JointNames = {'r_shoulder_pan_joint', ...
                                   'r_shoulder_lift_joint', ...
                                   'r_upper_arm_roll_joint', ...
                                   'r_elbow_flex_joint',...
                                   'r_forearm_roll_joint',...
                                   'r_wrist_flex_joint',...
                                   'r_wrist_roll_joint'};

Создайте заданные значения в траектории соединения руки путем создания ROS сообщения trajectory_msgs/JointTrajectoryPoint и определения положения и скорости всех 7 соединений как вектор. Задайте время от запуска как объект длительности ROS.

% Point 1
tjPoint1 = rosmessage('trajectory_msgs/JointTrajectoryPoint');
tjPoint1.Positions = zeros(1,7);
tjPoint1.Velocities = zeros(1,7);
tjPoint1.TimeFromStart = rosduration(1.0);

% Point 2
tjPoint2 = rosmessage('trajectory_msgs/JointTrajectoryPoint');
tjPoint2.Positions = [-1.0 0.2 0.1 -1.2 -1.5 -0.3 -0.5];
tjPoint2.Velocities = zeros(1,7);
tjPoint2.TimeFromStart = rosduration(2.0);

Создайте объектный массив с точками в траектории и присвойте ее целевому сообщению. Отправьте цель с помощью клиента действия. Функция sendGoalAndWait блокирует выполнение, пока рука PR2 не закончит выполнять траекторию

rGoalMsg.Trajectory.Points = [tjPoint1,tjPoint2];

sendGoalAndWait(rArm,rGoalMsg);

Создайте другой клиент действия, чтобы отправить команды в левую руку. Задайте объединенные имена робота PR2.

[lArm, lGoalMsg] = rosactionclient('l_arm_controller/joint_trajectory_action');
waitForServer(lArm);

lGoalMsg.Trajectory.JointNames = {'l_shoulder_pan_joint', ...
                                   'l_shoulder_lift_joint', ...
                                   'l_upper_arm_roll_joint', ...
                                   'l_elbow_flex_joint',...
                                   'l_forearm_roll_joint',...
                                   'l_wrist_flex_joint',...
                                   'l_wrist_roll_joint'};

Установите точку траектории для левой руки. Присвойте его целевому сообщению и отправьте цель.

tjPoint3 = rosmessage('trajectory_msgs/JointTrajectoryPoint');
tjPoint3.Positions = [1.0 0.2 -0.1 -1.2 1.5 -0.3 0.5];
tjPoint3.Velocities = zeros(1,7);
tjPoint3.TimeFromStart = rosduration(2.0);

lGoalMsg.Trajectory.Points = tjPoint3;

sendGoalAndWait(lArm,lGoalMsg);

Вычислите инверсную кинематику для положения исполнительного элемента конца

В этом разделе вы вычисляете траекторию для соединений на основе желаемого исполнительного элемента конца (механизм захвата права PR2) положения. Класс robotics.InverseKinematics> вычисляет все необходимые объединенные положения, которые могут быть отправлены как сообщение цели траектории через клиент действия. robotics.RigidBodyTree класс используется, чтобы задать параметры робота, сгенерировать настройки и визуализировать робота в MATLAB®.

Выполните следующие шаги:

  • Получите текущее состояние робота PR2 от сети ROS и присвойте его объекту robotics.RigidBodyTree работать с роботом в MATLAB®.

  • Задайте положение цели исполнительного элемента конца.

  • Визуализируйте настройку робота с помощью этих объединенных положений, чтобы гарантировать соответствующее решение.

  • Используйте инверсную кинематику, чтобы вычислить объединенные положения от целевых положений исполнительного элемента конца.

  • Отправьте траекторию объединенных положений к серверу действия ROS, чтобы управлять фактическим роботом PR2.

Создайте дерево твердого тела в MATLAB®

Загрузите робота PR2 как объект robotics.RigidBodyTree. Этот объект задает все кинематические параметры (включая объединенные пределы) робота.

pr2 = exampleHelperWGPR2Kinect;

Получите текущее состояние робота

Создайте подписчика, чтобы получить объединенные состояния от робота.

jointSub = rossubscriber('joint_states');

Получите текущее объединенное сообщение состояния.

jntState = receive(jointSub);

Присвойте объединенные положения от объединенного сообщения состояний до полей struct настройки, что объект pr2 понимает.

jntPos = exampleHelperJointMsgToStruct(pr2,jntState);

Визуализируйте текущую настройку робота

Используйте show, чтобы визуализировать робота с данным объединенным радиус-вектором. Это должно совпадать с текущим состоянием робота.

show(pr2,jntPos)

ans = 
  Axes (Primary) with properties:

             XLim: [-2 2]
             YLim: [-2 2]
           XScale: 'linear'
           YScale: 'linear'
    GridLineStyle: '-'
         Position: [0.1300 0.1100 0.7750 0.8150]
            Units: 'normalized'

  Show all properties

Создайте объект robotics.InverseKinematics из объекта робота pr2. Цель инверсной кинематики состоит в том, чтобы вычислить объединенные углы для руки PR2, которая помещает механизм захвата (т.е. исполнительный элемент конца) в желаемом положении. Последовательность положений исполнительного элемента конца в течение времени называется траекторией.

В этом примере мы будем только управлять руками робота. Поэтому мы устанавливаем трудные границы соединения лифта туловища во время планирования.

torsoJoint = pr2.getBody('torso_lift_link').Joint;
idx = strcmp({jntPos.JointName}, torsoJoint.Name);
torsoJoint.HomePosition = jntPos(idx).JointPosition;
torsoJoint.PositionLimits = jntPos(idx).JointPosition + [-1e-3,1e-3];

Создайте объект InverseKinematics.

ik = robotics.InverseKinematics('RigidBodyTree', pr2);

Отключите случайный перезапуск, чтобы гарантировать сопоставимые решения IK.

ik.SolverParameters.AllowRandomRestart = false;

Задайте веса для допусков на каждом компоненте целевого положения.

weights = [0.25 0.25 0.25 1 1 1];
initialGuess = jntPos; % current jnt pos as initial guess

Задайте положения исполнительного элемента конца, связанные с задачей. В этом примере PR2 достигнет к банке на таблице, схватит банку, переместит его в другое место и запишет его снова. Мы будем использовать объект InverseKinematics запланировать движения, что гладко переход от одного исполнительного элемента конца позирует другому.

Задайте имя исполнительного элемента конца.

endEffectorName = 'r_gripper_tool_frame';

Задайте начальное (текущее) положение банки и желаемое итоговое положение.

TCanInitial = trvec2tform([0.7, 0.0, 0.55]);
TCanFinal = trvec2tform([0.6, -0.5, 0.55]);

Задайте желаемое относительное преобразование между исполнительным элементом конца и банкой при схватывании.

TGraspToCan = trvec2tform([0,0,0.08])*eul2tform([pi/8,0,-pi]);

Задайте ключ waypoints желаемой Декартовой траектории. Банка должна пройти эта траектория. Траектория может быть разбита можно следующим образом:

  • Откройте механизм захвата

  • Переместите исполнительный элемент конца от текущего положения до T1 так, чтобы робот чувствовал себя комфортно, чтобы инициировать схватывание

  • Переместите исполнительный элемент конца от T1 до TGrasp (готовый схватить)

  • Закройте механизм захвата и захватите банку

  • Переместите исполнительный элемент конца от TGrasp до T2 (лифт может в воздухе),

  • Переместите исполнительный элемент конца от T2 до T3 (перемещение может levelly),

  • Переместитесь исполнительный элемент конца от T3 до TRelease (ниже может к поверхности стола и готовый выпустить),

  • Откройте механизм захвата и отпустите банки

  • Переместитесь исполнительный элемент конца от TRelease до T4 (отрекитесь от руки),

TGrasp = TCanInitial*TGraspToCan; % The desired end-effector pose when grasping the can
T1 = TGrasp*trvec2tform([0.,0,-0.1]);
T2 = TGrasp*trvec2tform([0,0,-0.2]);
T3 = TCanFinal*TGraspToCan*trvec2tform([0,0,-0.2]);
TRelease = TCanFinal*TGraspToCan; % The desired end-effector pose when releasing the can
T4 = T3*trvec2tform([-0.1,0,0]);

Фактическое движение будет задано положениями соединения numWaypoints в последовательности и отправлено в робота через ROS простой клиент действия. Эти настройки будут выбраны с помощью объекта InverseKinematics, таким образом, что положение исполнительного элемента конца интерполировано от начального положения до итогового положения.

Выполните движение

Задайте последовательность движений.

motionTask = {'Release', T1, TGrasp, 'Grasp', T2, T3, TRelease, 'Release', T4};

Выполните каждую задачу, заданную в motionTask один за другим. Отправьте команды с помощью заданных функций помощника.

for i = 1: length(motionTask)
    
    if strcmp(motionTask{i}, 'Grasp')
        exampleHelperSendPR2GripperCommand('right',0.0,1000,true); 
        continue
    end
    
    if strcmp(motionTask{i}, 'Release')
        exampleHelperSendPR2GripperCommand('right',0.1,-1,true);
        continue
    end  
    
    Tf = motionTask{i};
    % Get current joint state
    jntState = receive(jointSub);
    jntPos = exampleHelperJointMsgToStruct(pr2, jntState);
    
    T0 = getTransform(pr2, jntPos, endEffectorName);  
    
    % Interpolating between key waypoints
    numWaypoints = 10;
    TWaypoints = exampleHelperSE3Trajectory(T0, Tf, numWaypoints); % end-effector pose waypoints
    jntPosWaypoints = repmat(initialGuess, numWaypoints, 1); % joint position waypoints
    
    rArmJointNames = rGoalMsg.Trajectory.JointNames;
    rArmJntPosWaypoints = zeros(numWaypoints, numel(rArmJointNames));
    
    % Calculate joint position for each end-effector pose waypoint using IK
    for k = 1:numWaypoints
        jntPos = ik(endEffectorName, TWaypoints(:,:,k), weights, initialGuess);
        jntPosWaypoints(k, :) = jntPos;
        initialGuess = jntPos;
        
        % Extract right arm joint positions from jntPos
        rArmJointPos = zeros(size(rArmJointNames));
        for n = 1:length(rArmJointNames)
            rn = rArmJointNames{n};
            idx = strcmp({jntPos.JointName}, rn);
            rArmJointPos(n) = jntPos(idx).JointPosition;
        end  
        rArmJntPosWaypoints(k,:) = rArmJointPos'; 
    end
    
    % Time points corresponding to each waypoint
    timePoints = linspace(0,3,numWaypoints);
        
    % Estimate joint velocity trajectory numerically
    h = diff(timePoints); h = h(1);
    jntTrajectoryPoints = arrayfun(@(~) rosmessage('trajectory_msgs/JointTrajectoryPoint'), zeros(1,numWaypoints)) 
    [~, rArmJntVelWaypoints] = gradient(rArmJntPosWaypoints, h);
    for m = 1:numWaypoints
        jntTrajectoryPoints(m).Positions = rArmJntPosWaypoints(m,:);
        jntTrajectoryPoints(m).Velocities = rArmJntVelWaypoints(m,:);
        jntTrajectoryPoints(m).TimeFromStart = rosduration(timePoints(m));
    end
    
    % Visualize robot motion and end-effector trajectory in MATLAB(R)
    hold on
    for j = 1:numWaypoints
        show(pr2, jntPosWaypoints(j,:),'PreservePlot', false);
        exampleHelperShowEndEffectorPos(TWaypoints(:,:,j));
        drawnow;
        pause(0.1);
    end
    
    % Send the right arm trajectory to the robot
    rGoalMsg.Trajectory.Points = jntTrajectoryPoints;
    sendGoalAndWait(rArm, rGoalMsg);

end
jntTrajectoryPoints = 
  1×10 ROS JointTrajectoryPoint message array with properties:

    MessageType
    TimeFromStart
    Positions
    Velocities
    Accelerations
    Effort

jntTrajectoryPoints = 
  1×10 ROS JointTrajectoryPoint message array with properties:

    MessageType
    TimeFromStart
    Positions
    Velocities
    Accelerations
    Effort

jntTrajectoryPoints = 
  1×10 ROS JointTrajectoryPoint message array with properties:

    MessageType
    TimeFromStart
    Positions
    Velocities
    Accelerations
    Effort

jntTrajectoryPoints = 
  1×10 ROS JointTrajectoryPoint message array with properties:

    MessageType
    TimeFromStart
    Positions
    Velocities
    Accelerations
    Effort

jntTrajectoryPoints = 
  1×10 ROS JointTrajectoryPoint message array with properties:

    MessageType
    TimeFromStart
    Positions
    Velocities
    Accelerations
    Effort

jntTrajectoryPoints = 
  1×10 ROS JointTrajectoryPoint message array with properties:

    MessageType
    TimeFromStart
    Positions
    Velocities
    Accelerations
    Effort

Обернуть

Положите обратно руку к стартовой позиции.

exampleHelperSendPR2GripperCommand('r',0.0,-1)
rGoalMsg.Trajectory.Points = tjPoint2;
sendGoal(rArm, rGoalMsg);

Вызовите rosshutdown, чтобы завершить работу сети ROS и отключиться от робота.

rosshutdown
Shutting down global node /matlab_global_node_11112 with NodeURI http://192.168.203.1:59756/