이전 글에서 DDS RTPS의 구조와 메세지에 대해서 알아보았다. 이번 시간에는 behavior specification을 통해 DDS RTPS의 동작(Writer와 Reader 사이에 메세지가 어떠한 sequence로 교환되는지)에 대해 알아보도록 하겠다.
* RTPS message는 빨간색으로 표시하였다. 메세지에 대한 내용은 이전 글(DDS RTPS의 구조(structure)와 메세지(message)) 참조.
RTPS reader와 writer의 종류
RTPS의 reader와 writer에는 stateless, stateful 두 가지 종류가 존재한다.
- stateless writer : writer는 reader에 대한 어떠한 상태 정보도 관리하지 않는다. 단지 어떤 reader에게 정보를 보내야 하는지만 관리한다.
- stateful writer : writer는 각각의 매칭된 reader의 상태를 관리한다. 각각의 reader들의 상태를 관리함으로써 writer는 모든 reader들이 어떤 CacheChange를 수신했는지 여부를 알 수 있다.
- stateless reader : reader는 writer에 대한 어떠한 상태 정보도 관리하지 않는다.
- stateful reader : reader는 매칭된 writer의 상태를 기록하고 관리한다. writer의 CacheChange들 중에 어떤 것을 수신했는지(received), 아직 수신하지 못했는지(missing) 또는 수신에 실패했는지(lost)를 기록한다.
위의 설명을 보면 stateless writer는 ROS의 best-effort publisher로, stateful writer는 ROS의 reliable publisher로, stateless reader는 ROS의 best-effort subscriber로, stateful reader는 ROS의 reliable subscriber로 이용될 것이란 것을 예상할 수 있다. 참고로, 모든 종류의 reader와 writer가 서로 매칭이 가능한 것은 아니다. stateless writer는 오직 stateless reader와만 매칭이 가능하다. stateful writer는 stateless reader 그리고 stateful reader와 모두 매칭이 가능하다.
다음은 각각의 reader와 writer의 동작에 대해서 state-machine을 이용하여 설명할 것이다. 내용과 설명이 많지만 시간을 두고 봐두면 DDS RTPS 동작을 이해하는데 도움이 될 것이다. (바쁘신 분은 바로 Summary로...)
stateless writer의 동작
- T1 : initial → idle. Discovery protocol을 통해 writer와 매칭되는 reader를 찾음으로써 ReaderLocator (CacheChange를 보내야하는 곳)가 구성이 되고, 이로 인해 T1 전환이 trigger된다.
- T2 : idle → pushing. Reader로 전송되지 않은 change가 writer HistoryCache에 있을 때 trigger된다.
- T3 : pushing → idle. 모든 writer HistoryCache에 있는 change가 reader로 전송되면 trigger된다. (* 이것이 모든 reader들이 change를 수신했다는 의미는 아니다.)
- T4 : pushing → pushing. writer가 reader로 송신할 수 있을 때 trigger된다. GAP과 DATA를 송신한다.
- T5 : any state → final. Discovery protocol을 통해 writer와 reader의 매칭을 break함으로써 writer는 더이상 reader로 송신을 하지 않게 된다. (ReaderLocator 삭제)
stateful writer의 동작
- T1 : initial → announcing. Discovery protocol을 통해 writer와 매칭되는 reader를 찾음으로써 ReaderProxy(매칭된 reader의 정보를 기록하기 위한 instance)가 구성되고, 이로 인해 T1 전환이 trigger된다.
- T2 : announcing → pushing. reader(ReaderProxy)로 전송되지 않은 change가 writer HistoryCache에 있을 때 trigger된다.
- T3 : pushing → announcing. 모든 writer HistoryCache에 있는 change가 reader(ReaderProxy)로 전송되면 trigger된다. (* 이것이 모든 reader들이 change를 수신했다는 의미는 아니다.)
- T4 : pushing → pushing. writer가 reader로 송신할 수 있을 때 trigger된다. GAP과 DATA를 송신한다.
- T5 : announcing → idle. writer HistoryCache의 모든 change들이 ReaderProxy에 모두 인지(acknowledged)했다고 기록되었을 때 trigger된다.
- T6 : idle → announcing. ReaderProxy에 인지(acknowledged)하지 않았다고 기록된 change가 writer HistoryCache에 있을 때 trigger된다.
- T7 : announcing → announcing. heartbeatPeriod의 주기 timer 설정에 맞춰 trigger된다. HEARTBEAT를 송신한다. (매칭된 reader가 stateful reader이면, ACKNACK를 송신할 것이다.)
- T8 : waiting → waiting. reader로 부터 RTPS message인 ACKNACK Message 수신 시 trigger된다. T8가 tigger될 때, reader로부터 인지된 change와 미인지되어 재전송을 요청한 change를 ReaderProxy에 기록한다.
- T9 : waiting → must_repair. reader가 재전송을 요청한 change가 있을 때 trigger된다.
- T10 : must_repair → must_repair. ACKNACK Message 수신 시 trigger된다. T8과 동일한 수행을 한다.
- T11 : must_repair → repairing. nackResponseDelay에 정의된 time이 지났을 때 trigger된다.
- T12 : repairing → repairing. writer가 reader로 송신할 수 있을 때 trigger된다. GAP과 DATA를 송신한다.
- T13 : repairing → waiting. reader에 의해 재전송이 요청된 change를 모두 송신하면 trigger된다.
- T14 : ready → ready. 새로운 CacheChange가 writer의 HistoryCache에 추가되었을 때 trigger된다.
- T15 : ready → ready. CacheChange가 writer의 HistoryCache로부터 제거될 때 trigger된다. (ex. history depth가 1이라면, 새로운 CacheChange가 있을 때마다 기존의 CacheChange가 제거된다.)
- T16 : any state → final. Discovery protocol을 통해 writer와 reader의 매칭을 break함으로써 writer는 더이상 read로 송신을 하지 않게 된다. (ReadProxy 삭제)
stateless reader
- T1 : initial → waiting. reader 생성에 의한 결과로 T1 전환이 trigger된다.
- T2 : waiting → waiting. reader가 DATA를 수신함으로써 trigger된다. Cachechange가 reader의 HistoryCache에 저장된다.
- T3 : any state → final. reader가 소멸할 때 trigger된다.
stateful reader
- T1 : initial1 → waiting. Discovery protocol을 통해 reader와 매칭되는 reader를 찾음으로써 WriterProxy(매칭된 writer의 정보를 기록하기 위한 instance)가 구성되고, 이로 인해 T1 전환이 trigger된다.
- T2 : waiting → must_send_ack/may_send_ack. HEARTBEAT 수신 시 trigger된다. 이 때 HEARTBEAT의 FinalFlag가 SET되어 있으면 may_send_ack로, NOT_SET되어 있으면 must_send_ack로 전환된다.
- T3 : may_send_ack → waiting. WriterPoxy의 기록을 통해 write의 HistoryCache에 있는 모든 change들이 reader로 모두 수신되었을 때 trigger된다.
- T4 : may_send_ack → must_send_ack. WriterPoxy의 기록을 통해 reader에서 수신하지 못한 change가 존재할 때 trigger된다.
- T5 : must_send_ack → waiting. heartbeatResponseDelay에 의해 정의된 time이 지났을 때, tigger된다. ACKNACK를 송신한다. (missing된 CacheChange들을 송신)
- T6 : initial2 → ready. T1과 동일한 조건으로 trigger.
- T7 : ready → ready. HEARTBEAT 수신 시 trigger된다. WriterProxy의 missing change와 lost change가 업데이트되게 된다. WriteProxy의 change중 status가 unkown이면서 Sequnece Number가 HEARTBEAT의 lastSN(가장 최신 SN)보다 작으면 missing change가 된다. WriteProxy의 change중에 missing이나 unknown이면서 Sequnece Number가 HEARTBEAT의 firstSN(가장 오래된 SN)보다 작다면 lost changes가 된다.
- T8 : ready → ready. DATA가 수신될 때 trigger된다. Cachechange가 reader의 HistoryCache에 저장이 되고 WriterProxy의 received change로 기록된다.
- T9 : ready → ready. GAP이 수신될 떄 trigger된다. WriterProxy에 해당 change가 더 이상 available하지 않다는 것을 기록한다.
- T10 : any state → final. Discovery protocol을 통해 writer와 reader의 매칭을 break함으로써 writer는 더이상 read로 송신을 하지 않게 된다. (WriterProxy 삭제)
Summary
DDS RTPS의 reader와 writer의 동작에 대해 알아보므로써, ROS에서 RTPS message가 어떻게 사용되어서 best-effort communication과 reliable communication이 이뤄지는지에 대해 알아보았다. best-effort에서는 writer가 reader에게 일방적으로 DATA정보를 송신하지만, reliable에서는 writer가 DATA정보뿐 아니라 HEARTBEAT와 GAP를 통해 writer의 HistoryCache정보를 같이 전달하고 reader는 ACKNACK를 통해 writer의 HistoryCache 중에 어떤 것을 수신하지 못했는지 전달한다.
References
'Robotics > ROS' 카테고리의 다른 글
DDS RTPS 패킷 확인해보기 (wireshark) (0) | 2022.03.01 |
---|---|
DDS RTPS의 Discovery Protocol (1) | 2022.02.12 |
DDS RTPS의 구조(structure)와 메세지(message) (0) | 2022.02.05 |
DDS와 RTPS 개념정리 (0) | 2022.02.04 |
ROS 2 설치 (Windows WSL 이용) (0) | 2022.02.03 |