노아의 무인선 ROS와 드론키트의 통신을 기반으로

아뮤랩의 노아 무인선이 출시된지 꽤 되었는데 개발사에 대해 많은 조사를 해본 결과 노아 무인선의 통신 구현에 많은 개발자들이 관심을 가지고 있는 것으로 나타났습니다. 노아의 무인선에 사용된 리눅스 프로그래밍 기술과 ROS 시스템에 대한 경험을 여러분과 공유할 것입니다.

Ardupilot 기반 오픈소스 자율 무인선 icon-default.png?t=N4P3https://www.bilibili.com/video/BV1AR4y167ne/?vd_source=83d699d29d0a56e0274cd41e59a6c3a9

아두파일럿 플랫폼 기반으로 개발된 무인선박 '노아(2022년형)'는 빠른 주행 속도와 긴 배터리 수명은 물론, 4G 원격제어, 경유지 계획, 영상 회신 등의 기능을 갖추고 있어, 다양한 개발 장면에 적용할 수 있습니다. Amu Lab, 공식 계정: Amu Lab의 신제품 출시 | 2022년 "노아" 무인선 정식 발매!

무인선이라고 하면 먼저 ROS에 대해 이야기해야 하는데, ROS란?

ROS는 Robot Operating System(Robot Operating System)의 약자로 사실 우리의 전통적인 운영체제가 아니다. 운영 체제가 컴퓨터의 여러 부분을 관리하는 것처럼 로봇의 구성 요소는 로봇 개발을 간단하고 효율적으로 만듭니다.

ROS 간의 통신을 더 잘 이해하는 데 도움이 되도록 작은 거북이를 달리는 시뮬레이션을 예로 들어 보겠습니다.

먼저 3개의 터미널을 열고 roscore를 입력하여 rosmaster 노드를 열고 rosrun turtlesim turtlesim_nod를 입력하여 작은 거북이 시뮬레이션 노드를 실행하고 px -ef를 입력하여 시스템의 모든 프로세스를 봅니다.

여기서 위 그림에서 동그라미 친 프로세스에 주목하세요 처음 두 프로세스는 roscore 명령을 입력하면 생성되는데 두 프로세스의 부모 프로세스는 4069이고 4069 프로세스는 pts/0에 마운트되어 있는 것을 볼 수 있기 때문에, 및 /usr/bin/python3/opt/ros/noetic/bin/roscore 명령. 이 명령어는 roscore 입력 후 ROS 명령줄 스크립트에 의해 해석되어 리눅스에서 실제로 실행되는 명령어로, 직접 해보시면 위의 명령어를 터미널에 직접 입력하여도 roscore를 실행할 수 있음을 알 수 있습니다. 그럼 우리가 roscore를 시작했을 때 무슨 일이 일어났는지 짐작할 수 있을까요?

roscore를 시작할 때 ROS는 두 개의 프로세스를 생성합니다. 첫 번째 프로세스는 마스터 프로세스이고 매개변수는 --core -p 11311입니다. 여기서 11311은 ROS 시스템의 기본 TCP 포트 번호입니다(TCP 네트워크 통신이 프로세스 Inter로 사용되기 때문입니다. -통신이 금지되면 이는 ROSMaster가 노드와 동일한 로컬 영역 네트워크에만 있으면 되고 동일한 호스트에 있을 필요가 없다는 것을 의미하며 이는 ROS 다중 머신 통신의 핵심이기도 합니다. ROS 노드 간의 통신 및 정보 교환에 사용됩니다. ROS 노드가 다른 노드와 통신하려면 먼저 마스터 노드(ROS Master)에 연결하여 이름, 유형, URI 및 기타 정보를 등록해야 합니다. 이러한 정보의 전송은 TCP/IP 프로토콜을 통해 포트 11311에서 완료됩니다.

두 번째 프로세스는 ROS 로그 메시지를 수신하고 게시하는 데 사용되는 rosout입니다. ROS에서 로그 메시지는 프로그램의 실행 상태 정보, 경고 및 오류를 기록하는 데 사용됩니다. 위의 단계가 완료되면 시작된 작은 거북이 시뮬레이션이 프로세스를 생성합니다.

일반적으로 ROS 노드는 하나의 프로세스이며 리눅스에서 프로세스 간 통신을 통해 데이터를 교환하므로 프로세스 간 통신이 용이합니다.

노아의 무인선에서 우리는 dronekit이 Python 언어를 기반으로 개발되고, 구문이 비교적 간단하고, 개발자가 시작하기 쉬운 APM 비행 제어 지원에 더 친숙하기 때문에 ROS와 통신하기 위해 dronekit을 사용합니다.

그래서 문제는 dronekit이 ROS 노드의 데이터를 가져오도록 하는 방법입니다. 즉, 프로세스 간 통신 수단은 무엇입니까?

공유 메모리, 잘 알려진 파이프 등과 같이 프로세스 간에 통신하는 방법에는 여러 가지가 있습니다. 이번에는 소켓 통신을 사용합니다.

먼저 무인선의 온보드 컴퓨터(라즈베리 파이)에 ROS 노드를 구현하고, 주제를 구독하여 드론에서 원하는 데이터를 얻은 다음 소켓 통신을 통해 사용자에게 전송하는 방식으로 드론키트가 작성한 제어 코드는 . 이 모든 과정에서 무인선의 ROS 노드는 환승역의 역할을 하며, 드론의 주제를 수신한 후 이를 소켓으로 무인선에 전달하고 무인선의 소켓 정보를 주제로 전달한다. 드론에.

이 통신 과정에서 ROS 노드가 직면할 수 있는 문제는 ROS 주제의 콜백 함수(즉, Subscribe의 마지막 매개변수)가 스레드이고 이 스레드의 트리거가 ROS, 즉 ros에 의해 결정된다는 것입니다. ::spinOnce() 및 ros::spin()은 프로그램이 ros::spinOnce()로 실행될 때 콜백 함수가 실행되고(메시지가 있는 경우) ros::spin()이 항상 실행되도록 결정합니다. 콜백 함수(메시지가 있는 경우), 이 문제를 해결하려면 프로세스 간 통신에서 소켓 모드의 비차단 모드를 사용하여 콜백 함수가 항상 모니터링되도록 할 필요가 있습니다.

ROS 노드가 선박 정보를 수신하기 위한 의사 코드는 아래와 같습니다. 메인 루프 이전에는 주로 소켓 프로그래밍에 필요한 초기화 과정을 거친 후 정보를 받을 때까지 기다리며, 정보를 받지 못한 경우 ROS는 콜백 함수를 한 번 확인해야 합니다.

int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //创建套接字sockfd,指定协议为UDP
struct sockaddr_in server_addr;//创建用来绑定自身信息的结构体server_addr
memset(&server_addr, 0, sizeof(server_addr));//将server_addr数据全部置0
server_addr.sin_family = AF_INET;//设置协议族
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//设置本地IP
server_addr.sin_port = htons(8080);//设置本地端口
bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr))//将IP和端口绑定
char buffer[BUFFER_SIZE];
struct sockaddr_in client_addr;//得到的有关于发送端的数据都会保存在clint_addr里面
socklen_t addr_len = sizeof(client_addr);
while(ros::ok){
    int recv_bytes = recvfrom(sock, buffer, sizeof(buffer),
                    MSG_DONTWAIT, 
                    (struct sockaddr*)&addr, &client_address_len);
                    //第四个参数为设置成非阻塞,recv_bytes为接收到的数据大小
    if(recv_bytes > 0){
        //说明接收到船的数据,就可以进行处理后,用ROS的topic发送出去
    }
    ros::spinOnce();
    rate.sleep();
}

Dronekit이 소켓간 프로세스 통신을 구현하는 것이 더 쉽고 편리합니다.코드 주석은 매우 명확합니다.예제는 다음과 같습니다.

localaddr = ("127.0.0.1",12345)
server_address = "127.0.0.1"
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#套接字初始化
udp_socket.setblocking(False)#设置为非阻塞
udp_socket.bind(localaddr)
sendbuf = '(' + str(vehicle.location.local_frame.east) + ','
            + str(vehicle.location.local_frame.east)+')'
while True:
    #recvfrom如果没有接收到信息会抛出异常,
    try:
        data, address = udp_socket.recvfrom(1024)
        print("got server data: ", data, "IP address", address)
    except socket.error as e: #捕获这个异常,就可以知道没收到信息
        udp_socket.sendto(sendbuf, server_address)#将信息发给ROS节点

소켓 통신 방식은 조작이 간단하고 난이도가 낮으며 ROS+드론키트간 통신을 쉽게 구현할 수 있음을 알 수 있다. 또한 소켓 통신 방법은 네트워크 통신을 실현하고 다른 호스트 간의 통신을 지원하며 풍부한 응용 시나리오를 가질 수 있습니다. 후속 개발자들도 이 통신 방식을 통해 QT에 호스트 컴퓨터 인터페이스를 작성하고, 소켓을 통해 드론키트 제어부에 명령을 내릴 수 있으며, 심지어 매트랩을 이용해 선박의 방향을 제어하는 ​​명령을 내릴 수도 있어 운용성이 높다.

제한된 공간과 내용으로 인해 오늘의 공유는 여기까지입니다 ROS+dronekit 간의 통신을 배우기 전에 후속 학습을 피하기 위해 스레드, 프로세스, 네트워크 프로그래밍 및 Linux에 대한 기본 지식을 미리 이해하는 것이 좋습니다. . 또한 저희 노아 무인선에 관심이 있으시거나 사용 중 기타 궁금한 사항이 있으시면 글을 남겨주시면 관련 기술에 대해 상담해드리겠습니다~

추천

출처blog.csdn.net/msq19895070/article/details/131175192