F/T 센서를 이용한 마찰보상
시스템 구성
F/T 센서를 이용한 기본적인 제어기를 적용해 봄으로써 F/T센서의 좌표계 변환 및 F/T센서의 bias값 초기화에 대해서 설명한다. 이를 위해서 엔드이펙터 (또는 엔드툴; end tool)에 F/T센서가 설치된 로봇에 대해서 설명하며 F/T센서의 부착은 로봇 엔드이펙터의 x축 좌표계와 센서의 x축 좌표계가 일치하도록 설치한다.

F/T센서를 이용한 제어를 수행하기 위한 시스템 구성 개략도
본 예제에서는 다음을 살펴본다.
- F/T센서의 좌표계 변환을 수행한다.
- 변환된 F/T센서 값을 이용하여 로봇의 관성질량 및 마찰효과를 줄여본다.
예제 코드 작성
관절 제어 컴포넌트(Joint Control Component)를 생성하고 F/T센서 값을 획득하기 위하여 공유 메모리 헤더파일을 추가하고 ShmemManager 포인터 변수와 데이터 획득을 위한 구조체 변수들을 선언한다 (공유메모리를 이용하여 F/T센서 값을 획득하는 구체적인 방법은 F/T 센서 값 획득 및 그리퍼 구동를 참고).
| #include <NRMKFramework/Indy/Sharedmemory/SharedData.h>
NRMKFramework::ShmemManager * indyShm = NULL;
NRMKIndy::SharedData::ExtraIOData extioData;
NRMKIndy::SharedData::RobotControlSharedData ctrData;
|
관절 제어 컴포넌트 헤더파일에 다음의 함수 및 변수들을 선언한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | //
typedef typename ROBOT::JointMat JointMat; //
typedef NRMKFoundation::CompositeHTransformTaskPosition TaskPosition; //
typedef NRMKFoundation::CompositeHTransformTaskVelocity TaskVelocity; //
typedef Eigen::Matrix<double, DIM, 1> TaskVec; //!< Typedef of task vector
typedef Eigen::Matrix<double, DIM, JOINT_DOF> TaskJac; //!< Typedef of task Jacobian matrix
void readFTSensor(ROBOT & robot);
void setBias(){_ftBias = _ftSensor;}
TaskPosition _tposT;
TaskVelocity _tvelT;
LieGroup::Wrench _ftBias;
LieGroup::Wrench _ftSensor;
LieGroup::Rotation _ft_sensor_orientation;
|
생성자와 파괴자에서 ShmemManager 포인터 변수 indyShm 에 메모리를 할당하고 및 해제하는 코드를 다음과 같이 작성한다.
| JointControlComponent::JointControlComponent()
: AbstractController(USERNAME, EMAIL, SERIAL)
, _robotNom(NULL)
{
indyShm = new NRMKFramework::ShmemManager(INDY_SHM_NAME, INDY_SHM_LEN);
}
|
| JointControlComponent::~JointControlComponent()
{
if (_robotNom != NULL) delete _robotNom;
// TODO Auto-generated destructor stub
if (indyShm != NULL)
delete indyShm;
}
|
setTFTSensor() 함수를 이용하여 F/T센서와 엔드이펙터(또는 엔드툴; end tool)간의 좌표계를 설정한다. 아래의 두 가지 예시 중 첫 번째 예시에서는 엔드이펙터와 F/T센서의 좌표계가 z축은 일치하며 x,y축에 대해서는 부호가 반대인 것을 나타내며 두 번째 예시에서는 첫 번째 예시의 상황에서 z축으로 일정한 각도만큼 더 틀어져 있는 것을 나타낸다. 본 예제 에서는 첫 번째 경우에 해당하며 엔드이펙터에 직접 붙어있기 때문에 변위를 0으로 설정한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | void JointControlComponent::initialize(ROBOT & robot, double delt)
{
//define nominal robot (this is not the consideration of this example)
_robotNom = AbstractController::createRobotObj();
//example 1.
ft_sensor_orientation = LieGroup::Rotation(-1,0,0,0,-1,0,0,0,1);
//example 2.
//ft_sensor_orientation = LieGroup::Rotation(2, -5.0/12.0*M_PI).
//cascade(LieGroup::Rotation(-1,0,0,0,-1,0,0,0,1));
robot.setTFTSensor(ft_sensor_orientation, LieGroup::Displacement::Zero());
}
|
위치제어기는 잘 설계되어 있다고 가정하고 본 예제에서는 직접교시모드에서 F/T센서 값을 이용하여 마찰보상을 적용한다. computeGravityTorq() 에 다음의 코드를 추가하도록 하자 (위치제어기에 대한 자세한 예시는 비선형 최적 위치제어기 참조).
- readFTsensor 함수를 정의하여 공유메모리로 부터 F/T센서 값을 획득하고 좌표계 변환을 수행한다.
- 중력보상을 위해 idyn_gravity 함수를 이용하여 중력 값을 계산한다.
- 엔드이펙터에 가해지는 힘을 관절에 가해지는 힘으로 변환하기 위해서 순기구학을 계산하고 자코비안 행렬을 획득한다.
- 본 예제에서는 로봇의 관성질량 및 마찰을 감소시키는데에 목적이 있으므로 로봇제어를 위해 사용될 제어 입력(u)는 정의하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 | int IntertiaReshapingwFTsensor::computeGravityTorq(ROBOT & robot,
LieGroup::Vector3D const & gravDir, JointVec & torque)
{
if (indyShm == NULL)
{
printf("Shared memory is missed\n");
}
//read F/T sensor
readFTSensor(robot);
//calculate torque control input to compensate for the effect of friction
JointVec u, tauGrav, tauExt, K_ir;
TaskJacobian J, Jdot;
//calculate the gravity
robot.idyn_gravity(LieGroup::Vector3D(0, 0, -GRAV_ACC));
tauGrav = robot.tau();
//calculate forward kinematics and jacobian
robot.computeFK(_tposT, _tvelT);
robot.computeJacobian(_tposT, _tvelT, J, Jdot);
//calculate external torque from measured external force
tauExt = J.transpose()*_ftSensor;
//define new control input: in this example, this is set to zero
u.setZero();
//set inertia and friction reshaping gains
K_ir << 5.0, 5.0, 3.0, 3.0, 3.0, 3.0;
//update final control input
torque = tauGrav - tauExt + K_ir.cwiseProduct(u + tauExt);
return true;
}
|
공유메모리로 부터 F/T센서 값을 획득하고 좌표계를 변환하기위해 사용된 readFTSensor 함수는 다음과 같다.
- getControlData 함수를 이용하여 F/T센서 값을 획득한 후, Bias 값을 반영한다.
- F/T센서 좌표계에서 표현된 힘의 값을 타겟(엔드 이펙터) 좌표계에 대한 표현으로 변환한다.
- 변환된 F/T센서 값의 힘 부분을 전체 좌표계에 대하여 표현한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | void JointControlComponent::readFTSensor(ROBOT & robot)
{
NRMKIndy::SharedData::getExtraIOData(*indyShm, extioData);
NRMKIndy::SharedData::getControlData(*indyShm, ctrData);
//reflect the biased force value
LieGroup::Wrench _ftSensorRaw;
for (int i=0; i<6; i++) _ftSensorRaw[i] = ctrData.Fext[i];
_ftSensorRaw -= _ftBias;
//transform the coordinate
// * Tft: transformation from reference coordinate to f/t sensor
// * Ttarget: transformation from reference coordinate to end effector
LieGroup::HTransform T_ft_target = robot.Ttarget().icascade(robot.Tft());
LieGroup::Wrench _ftSensorTemp = T_ft_target.itransform(_ftSensorRaw);
TaskPosition _tartget_pos;
TaskVelocity _tartget_vel;
robot.computeFK(_tartget_pos, _tartget_vel);
LieGroup::Wrench _ftSensorTransformed
= LieGroup::Wrench(_tartget_pos.R()*_ftSensorTemp.f(), _ftSensorTemp.n());
for (int i=0; i<3; i++) _ftSensor[i] = _ftSensorTransformed[i+3];
for (int i=0; i<3; i++) _ftSensor[i+3] = _ftSensorTransformed[i];
}
|
민감한 힘 제어를 수행하거나 센서의 반복성이 보장이 되지 않을 때 다음과 같이 작업이 종료된 후 재시작 시 bias 값을 업데이트 할 수 있도록 한다. 본 예제에서는 직접교시를 종료 시 센서의 bias 값이 설정되며 재시작 시 리셋을 수행한다.
| void JointControlComponent::reset()
{
NRMKIndy::SharedData::getExtraIOData(*indyShm, extioData);
NRMKIndy::SharedData::getControlData(*indyShm, ctrData);
for (int i=0; i<6; i++) _ftSensor[i] = ctrData.Fext[i];
setBias();
}
|