alter_motion()

정의

alter_motion(pos)

기능

입력 인자 pos에 해당하는 양만큼 경로 수정을 진행합니다.

주의

  • alter_motion()은 사용자 thread 내에서만 동작합니다.

  • alter_motion()은 posx의 orientation type이 None인 경우, DR_FIX_XYZ로 설정됩니다.

  • n 을 권장 범위로 맞춰도 가속도 리플은 구조적으로 남습니다. 크기는 보정의 최대 속도에 비례하므로, 소음이 문제인 경우 진폭 또는 주파수를 낮추십시오.

  • 증분량 모드(DR_DVEL)에서는 제어기가 Tn선착순 1 건만 받아들이므로 그 뒤에 도착한 증분이 알람 없이 버려질 수 있습니다. 폐루프로 구성해 누락분이 다음 측정에서 보정되도록 하십시오.

알아두기

  • alter_motion()은 enable_alter_motion()을 통해 경로보정기능이 활성화된 경우에만 유효합니다.

  • enable_alter_motion의 설정 값 limit_dPOS, limit_dPOS_per에 따라 경로 수정량은 조정될 수 있습니다.

  • alter_motion()은 SW 버전 V3.4부터 pos를 posx()로 입력하면 다양한 Orientation type을 지원하며, list(float[6]) 형식으로 입력하는 경우, Fixed XYZ로 동작합니다.

  • n × 10ms 는 실측한 최대 공급 주기 이상이어야 합니다. 산정 방법은 아래 사용 조건을 참고하십시오.

인수

인수명

자료형

기본값

설명

pos

list (float[6])

posx

-

position list

posx (if ori_type is None, then ori_type is DR_FIX_XYZ)

사용 조건

동작 원리

경로 수정은 보정 1 건마다 정지 → 정지 궤적을 경로 생성 주기 Tn = n × 10ms 로 계획하는 방식으로 동작합니다. 진행 중인 궤적은 새 보정이 도착해도 중단되지 않고, 다음 궤적이 현재 궤적의 감속 구간에서 이어받아 합산됩니다. 제어기는 Tn 당 보정을 한 건만 받아들입니다. 새 궤적이 시작할 때 열린 수용 창은 가장 먼저 도착한 한 건을 받은 즉시 닫히므로, 같은 Tn 안에 2 건이 들어오면 뒤에 온 값(더 최신 보정)이 알람 없이 버려집니다. 최신값으로 덮어쓰는 방식이 아닙니다.

따라서 n 은 이 함수가 보정을 실제로 전달할 수 있는 주기에 맞춰 정해야 합니다. 그 주기는 보정 계산 · 호출 비용 · thread 경합이 모두 더해진 값이므로 실측한 최대값을 쓰십시오. Tn 이 그 값보다 짧으면 보정이 멈춰 선 채 대기하는 구간이 매 주기 생겨 진동 · 소음이 납니다. 증분량 모드(DR_DVEL)는 n 을 하한에 가능한 한 붙여 잡고, 간헐적으로 누락되는 증분을 보정할 수 있도록 폐루프로 구성하십시오. 어려우면 누적량 모드를 쓰십시오.

공급 주기 실측과 n 산정의 상세한 절차는 enable_alter_motion() 페이지의 사용 조건을 참고하십시오.

예외

예외

설명

DR_Error (DR_ERROR_TYPE)

인수들의 데이터형 오류 시

DR_Error (DR_ERROR_VALUE)

인수의 값이 유효하지 않을 시

DR_Error (DR_ERROR_RUNTIME)

C Extension 모듈 에러 발생 시

DR_Error (DR_ERROR_STOP)

프로그램 강제 종료 시

예제

Python
# ---------------------------------------------------------------
# 실시간 경로 보정
#   예제1 누적량 모드(DR_DPOS) - 절대 오프셋을 아는 경우
#   예제2 증분량 모드(DR_DVEL) - 외부 센서로 남은 오차를 재는 경우
# ---------------------------------------------------------------
drl_report_line(0)    # 보정 주기를 코드량과 무관하게 만듭니다

DT      = 0.05        # 공급 주기 기준값 [sec]. 실제 주기는 이보다 큽니다
AMP     = 5.0         # 예제1 보정 진폭 [mm]
FREQ    = 0.25        # 예제1 보정 주파수 [Hz]
GAIN    = 0.5         # 예제2 보정 이득 (0 < GAIN <= 1)
LAT_MAX = 0.25        # 예제1 허용 보정 지연 [sec]. 지연 = 약 2 x n x 10ms
LIM_POS = [50, 90]    # limit_dPOS     : 누적 보정 한계 [mm, deg]
LIM_INC = [10, 10]    # limit_dPOS_per : 1 주기 증분 한계 [mm, deg]

g_mode  = 0           # 0 = 누적량 / 1 = 증분량
g_gain  = 0.0         # 보정 배율. 0 이면 보정이 걸리지 않습니다
g_t0    = 0.0
g_calls = 0
g_prev  = 0.0
g_max   = 0.0         # 실측 공급 주기의 최대값 [sec]

def read_path_error():
    # 외부 센서(비전 등)가 측정한 "현재 남은 경로 오차" [mm] 를 반환하도록
    # 교체하십시오. 보정이 반영된 뒤의 잔여 오차여야 합니다.
    return 0.0

# thread_run(loop=True) 는 함수가 반환할 때마다 다시 호출하므로 함수 안에
# while 루프를 두지 않습니다. while 을 두면 thread_stop 이 걸리지 않습니다.
def alter_thread():
    global g_calls, g_prev, g_max
    if g_mode == 0:
        var_y = g_gain * AMP * sin(6.28318 * FREQ * (time.time() - g_t0))
        alter_motion(posx(0, var_y, 0, 0, 0, 0))       # 지금 있어야 할 오프셋
    else:
        var_e = g_gain * GAIN * read_path_error()
        alter_motion(posx(0, var_e, 0, 0, 0, 0))       # 남은 오차의 일부만큼 더
    # 호출 간격을 매 주기 재서 최대값을 남깁니다.
    var_now = time.time()
    if g_prev > 0.0:
        if var_now - g_prev > g_max:
            g_max = var_now - g_prev
    g_prev  = var_now
    g_calls = g_calls + 1
    wait(DT)

# 기저 모션 양단 자세 - 측정값(get_current_posx)이 아니라 지령값을 씁니다.
# 측정 자세에는 추종 잔차가 섞여 있어 목표로 되돌려 쓰면 오차가 누적됩니다.
movej(posj(30, 45, 45, 0, 90, 0), vel=60, acc=60)
X1 = get_desired_posx(DR_BASE)
movej(posj(-30, 45, 45, 0, 90, 0), vel=60, acc=60)
X2 = get_desired_posx(DR_BASE)

# --- 공급 주기 실측 -------------------------------------------
# 실제로 쓸 모션과 thread 구성 그대로 한 번 돌립니다.
# g_gain = 0.0 이라 보정량은 0 이지만 계산과 호출은 그대로 일어나므로,
# 로봇 궤적은 변하지 않으면서 실사용과 같은 부하로 측정됩니다.
movel(X1, vel=30, acc=60)
mwait(0)
enable_alter_motion(n=20, mode=DR_DPOS, ref=DR_BASE,
                    limit_dPOS=LIM_POS, limit_dPOS_per=LIM_INC)
g_mode  = 0
g_gain  = 0.0
g_calls = 0
g_prev  = 0.0
g_max   = 0.0
g_t0    = time.time()
th_id   = thread_run(alter_thread, loop=True)

movel(X2, vel=30, acc=60)

thread_stop(th_id)
disable_alter_motion()

var_supply = DT                                # 실측 실패 시 대비값
if g_calls > 5:
    var_supply = g_max                         # 최대 공급 주기 [sec] - n 산정 기준
tp_log("supply max = {0} ms".format(int(var_supply * 100000) / 100.0))

# 하한 : 최대 공급 주기 / 10ms 를 올림한 값
N_MIN = int(var_supply * 100)
if var_supply * 100 > N_MIN:
    N_MIN = N_MIN + 1
if N_MIN < 1:
    N_MIN = 1

# --- 예제 1. 누적량 모드 (DR_DPOS) ----------------------------
# 매 전송이 완결된 오프셋입니다. 제어기가 한 건을 받지 못해도 다음 전송이
# 그대로 복구하므로 손실이 없습니다.
# 지연 예산이 허용하는 최대로 잡습니다.
N_DPOS = int(LAT_MAX * 100 / 2)
if N_DPOS < N_MIN:
    N_DPOS = N_MIN                             # 하한이 우선입니다

movel(X1, vel=30, acc=60)
mwait(0)                                       # 정지 상태에서 보정 시작
enable_alter_motion(n=N_DPOS, mode=DR_DPOS, ref=DR_BASE,
                    limit_dPOS=LIM_POS, limit_dPOS_per=LIM_INC)
g_mode = 0
g_gain = 1.0
g_t0   = time.time()
th_id  = thread_run(alter_thread, loop=True)

movel(X2, vel=30, acc=60)                      # 보정이 중첩된 기저 모션

# 종료 순서 : 보정 정지 -> thread_stop -> disable_alter_motion
# 비활성화 후에도 thread 가 살아 있으면 alter_motion() 호출이 남아 에러가 납니다.
g_gain = 0.0
thread_stop(th_id)
disable_alter_motion()

# --- 예제 2. 증분량 모드 (DR_DVEL) ----------------------------
# 센서가 남은 오차를 계속 재는 폐루프에서만 쓰십시오. 제어기가 받지 못한
# 증분은 되돌아오지 않지만, 폐루프면 다음 측정에서 자동으로 재시도됩니다.
# n 은 하한에 붙여 잡습니다. 간헐적으로 누락되는 증분은 폐루프가 다음
# 측정에서 보정합니다.
# read_path_error() 가 폐루프가 아니라면 이 예제 대신 예제 1 을 쓰십시오.
N_DVEL = N_MIN

movel(X1, vel=30, acc=60)
mwait(0)
enable_alter_motion(n=N_DVEL, mode=DR_DVEL, ref=DR_BASE,
                    limit_dPOS=LIM_POS, limit_dPOS_per=LIM_INC)
g_mode = 1
g_gain = 1.0
g_t0   = time.time()
th_id  = thread_run(alter_thread, loop=True)

movel(X2, vel=30, acc=60)                      # 센서 보정이 중첩된 기저 모션

g_gain = 0.0
thread_stop(th_id)
disable_alter_motion()

관련 명령어

Keyword

alter / motion / alter_