여러 ROS Master를 동시에 운영하는 환경
# Master에 접속
rosobj = xmlrpclib.ServerProxy(master_uri)
# 전체 시스템 상태 요청
code, msg, systemState = rosobj.getSystemState(caller_id)
# systemState에 포함된 정보:
# - Publishers: 어떤 노드가 어떤 토픽 발행
# - Subscribers: 어떤 노드가 어떤 토픽 구독
# 두 노드가 같은 토픽을 사용하는지 확인
if beforeNode.pub_topic != afterNode.pub_topic:
return False # 발행 토픽 다름
if beforeNode.sub_topic != afterNode.sub_topic:
return False # 구독 토픽 다름
# Master A에 new_node 등록
for topic in afterNode.pub_topic:
beforeNodeMaster.registerPublisher(...)
for topic in afterNode.sub_topic:
beforeNodeMaster.registerSubscriber(...)
# Master A에서 old_node 제거
for topic in beforeNode.pub_topic:
beforeNodeMaster.unregisterPublisher(...)
beforeNode.stop() # 프로세스 종료
# Subscriber들에게 Publisher 변경 알림
afterNode.publisherUpdate(topic, new_publishers)
import rospy
rospy.init_node('my_node')
# 고수준 API - 편하지만 Master 제어 불가
import xmlrpclib
rosobj = xmlrpclib.ServerProxy(master_uri)
rosobj.registerPublisher(...)
# 저수준 RPC API - Master 직접 제어 가능
def Copy_Node(target_master, target_node):
# target_master에 등록만 함
RegistNode(target_master, target_node)
# Publisher 정보 업데이트
DiffApply(target_master, target_node)
# 원본 노드는 그대로
// 드래그 시작
public void OnBeginDrag(PointerEventData eventData) {
clone = Instantiate(gameObject); // 복제본 생성
clone.transform.SetParent(canvas.transform);
}
// 드래그 중
public void OnDrag(PointerEventData eventData) {
clone.transform.position = eventData.position; // 마우스 따라감
}
// 드롭
public void OnEndDrag(PointerEventData eventData) {
var slot = hit.GetComponent<RosSlot>();
if (slot.SlotFilled) {
// 기존 노드 있음 → changeNode
} else {
// 빈 슬롯 → copyNode
}
}
# 노드 전환 요청
Unity → Python:
"changeNode/old_node/new_node/192.168.5.100/192.168.5.101"
Python → Unity:
"clear!!" (성공) 또는 "diff!!" (실패)
# 노드 복사 요청
Unity → Python:
"copy_node/192.168.5.100/192.168.5.101/node_name"
class DEReceiver:
def __init__(self, ip, port):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def act(self):
# Unity에서 명령 수신
data, addr = self.sock.recvfrom(1024)
func = data.split('/')
# 해당 함수 실행
result = getattr(self, func[0])(func)
# 결과 전송
if result != "":
self.sock.sendto(result, addr)
def DiffApply(target_master, target_node):
# 1. 새 Publisher URI 리스트 생성
publishers = [node.node_uri for node in pub_nodes]
# 2. Subscriber에게 강제 알림
target_node.publisherUpdate(topic, publishers)
# 3. Publisher도 준비시키기
for pub_node in publishers:
pub_node.requestTopic(topic)
// 별도 스레드: UDP 처리
private void RunClientThread() {
while (loop) {
received = udpClient.Receive(ref srv);
srv_q.Enqueue(received); // Queue에 저장
}
}
// 메인 스레드: UI 업데이트
void Update() {
if (srv_q.Count() > 0) {
string data = srv_q.Dequeue();
UpdateUI(data); // 여기서만 UI 조작
}
}
# 처음 시도
def DiffApply(target_master, target_node):
target_node.publisherUpdate(topic, publishers)
# 이것만 하면 일부만 성공
# 개선
def DiffApply(target_master, target_node):
target_node.publisherUpdate(topic, publishers)
# 이거 추가하니까 100% 성공
for pub_node in publishers:
pub_node.requestTopic(topic)
감사합니다. 질문이 있으시면 편하게 물어보세요.