이 단계에서는 ROS2와 Arduino Mega 간의 시리얼 통신을 설정하여, Arduino에서 수집한 IMU와 GPS 데이터를 ROS2 토픽으로 전달하고, BLDC 모터 제어 명령을 ROS2를 통해 Arduino로 전송하는 방법을 다룹니다. 이를 통해 Jetson Nano에서 ROS2를 사용해 센서 데이터를 수신하고 모터를 제어할 수 있습니다. 이 과정에서는 rosserial 또는 ros2arduino 패키지를 사용하여 ROS2와 Arduino 간의 통신을 설정합니다.
ROS2에서 Arduino와 통신하려면 시리얼 통신을 통해 데이터를 주고받아야 합니다. Arduino는 주로 센서 데이터를 전송하고, Jetson Nano에 ROS2 노드를 통해 이 데이터를 전달합니다. 반대로, ROS2에서 생성된 제어 명령은 Arduino로 전송되어 모터를 제어하거나 특정 작업을 수행하게 됩니다.
이를 위해, rosserial 또는 ros2arduino와 같은 시리얼 통신 라이브러리를 사용하여 Arduino와 Jetson Nano 간의 시리얼 브리지를 설정합니다.
ROS2와 Arduino의 통신을 위해 ros2arduino 라이브러리를 사용하여 시리얼 연결을 설정합니다.
ros2arduino를 검색하여 설치할 수 있습니다.Jetson Nano에서 micro-ROS 또는 ros2serial을 사용하여 시리얼 연결을 설정할 수 있습니다. 이를 통해 ROS2 노드에서 시리얼 포트를 통해 Arduino와 통신할 수 있습니다.
sudo apt update
sudo apt install ros-foxy-micro-ros-agent
설치가 완료되면 micro-ROS 에이전트를 사용하여 Jetson Nano와 Arduino 사이의 시리얼 통신을 활성화할 수 있습니다.
이 단계에서는 Arduino가 IMU와 GPS 데이터를 수집한 후, 이를 시리얼 통신을 통해 Jetson Nano의 ROS2 노드로 전송하는 방법을 다룹니다.
Arduino에서 수집한 IMU와 GPS 데이터를 Jetson Nano로 전송하는 코드를 작성합니다. Arduino는 데이터를 시리얼 통신을 통해 전송하며, Jetson Nano는 이를 ROS2 토픽으로 수신하여 다른 노드와 공유합니다.
#include <Wire.h>
#include <TinyGPS++.h>
#include <Adafruit_MPU6050.h>
#include <ros2arduino.h>
Adafruit_MPU6050 mpu;
TinyGPSPlus gps;
void setup() {
Serial.begin(115200);
ros2.init();
if (!mpu.begin()) {
Serial.println("MPU6050 초기화 실패!");
while (1);
}
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
}
void loop() {
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
// IMU 데이터 전송
ros2.publish("imu_data", a.acceleration.x, a.acceleration.y, a.acceleration.z, g.gyro.x, g.gyro.y, g.gyro.z);
// GPS 데이터 전송
if (gps.location.isUpdated()) {
ros2.publish("gps_data", gps.location.lat(), gps.location.lng());
}
ros2.spinOnce();
delay(100);
}
위 코드에서는 ros2.publish() 함수를 통해 IMU와 GPS 데이터를 각각 imu_data와 gps_data라는 토픽으로 ROS2에 전송합니다. Jetson Nano에서는 이 토픽을 구독하여 IMU와 GPS 데이터를 수신할 수 있습니다.
Jetson Nano에서 imu_data와 gps_data 토픽을 구독하는 ROS2 노드를 작성하여, Arduino에서 전송된 데이터를 수신합니다.
# imu_gps_listener.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float32MultiArray
class ImuGpsListener(Node):
def __init__(self):
super().__init__('imu_gps_listener')
self.imu_subscription = self.create_subscription(
Float32MultiArray,
'imu_data',
self.imu_callback,
10)
self.gps_subscription = self.create_subscription(
Float32MultiArray,
'gps_data',
self.gps_callback,
10)
def imu_callback(self, msg):
self.get_logger().info(f'IMU Data - Acceleration: {msg.data[0]}, {msg.data[1]}, {msg.data[2]} | Gyro: {msg.data[3]}, {msg.data[4]}, {msg.data[5]}')
def gps_callback(self, msg):
self.get_logger().info(f'GPS Data - Latitude: {msg.data[0]}, Longitude: {msg.data[1]}')
def main(args=None):
rclpy.init(args=args)
listener = ImuGpsListener()
rclpy.spin(listener)
listener.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
이 코드에서는 imu_data와 gps_data라는 토픽을 구독하여 Arduino에서 전송된 IMU와 GPS 데이터를 수신하고, 터미널에 출력합니다.
이제 Jetson Nano에서 생성한 모터 제어 명령을 Arduino로 전달하여 BLDC 모터를 제어하는 방법을 알아보겠습니다. Jetson Nano에서는 ROS2를 통해 모터 속도와 방향 명령을 전송하고, Arduino는 이를 해석하여 모터를 제어합니다.
Arduino에서 ROS2로부터 모터 제어 명령을 수신하고 이를 실행하는 코드를 작성합니다. 이 코드는 모터의 속도와 방향을 제어합니다.
#include <ros2arduino.h>
const int pwmPin = 9;
const int dirPin = 8;
void motor_callback(const std_msgs::Int32 &msg) {
int speed = abs(msg.data);
digitalWrite(dirPin, msg.data >= 0 ? HIGH : LOW);
analogWrite(pwmPin, speed);
}
void setup() {
Serial.begin(115200);
ros2.init();
pinMode(pwmPin, OUTPUT);
pinMode(dirPin, OUTPUT);
ros2.subscribe("motor_command", motor_callback);
}
void loop() {
ros2.spinOnce();
delay(100);
}
이 코드에서 motor_callback 함수는 motor_command 토픽에서 수신한 명령을 해석하여 모터의 속도와 방향을 제어합니다. 속도가 양수면 정방향, 음수면 역방향으로 회전하도록 설정되어 있습니다.
Jetson Nano에서 motor_command 토픽을 발행하여 Arduino로 모터 제어 명령을 전송합니다.
# motor_controller.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import Int32
class MotorController(Node):
def __init__(self):
super().__init__('motor_controller')
self.publisher_ = self.create_publisher(Int32, 'motor_command', 10)
def send_motor_command(self, speed):
msg = Int32()
msg.data = speed # 양수면 정방향, 음수면 역방향
self.publisher_.publish(msg)
self.get_logger().info(f'Sent motor speed: {speed}')
def main(args=None):
rclpy.init(args=args)
motor_controller = MotorController()
try:
while True:
speed = int(input("Enter motor speed (-255 to 255): "))
motor_controller.send_motor_command(speed)
except KeyboardInterrupt:
pass
motor_controller.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
위 코드에서는 사용자가 입력한 값을 motor_command 토픽에 발행하여, Arduino가 모터 속도를 제어할 수 있도록 합니다.
이제 ROS2와 Arduino 간의 통신을 테스트하여, 데이터가 잘 송수신되는지 확인합니다.
_data와 gps_data` 토픽으로 Jetson Nano에 전송하면, Jetson Nano에서 해당 데이터를 수신하여 터미널에 출력합니다.
motor_command 토픽을 통해 모터 속도 명령을 발행하면, Arduino가 이를 수신하여 BLDC 모터를 제어합니다.이 테스트를 통해 ROS2와 Arduino 간의 통신이 원활히 이루어지고, 로봇이 ROS2 명령을 바탕으로 센서 데이터를 수집하고 모터를 제어할 수 있는지 확인할 수 있습니다.
이 단계에서는 ROS2와 Arduino 간의 시리얼 통신을 설정하고, IMU 및 GPS 데이터를 ROS2 토픽으로 전송하는 방법과, ROS2에서 모터 제어 명령을 전송하여 Arduino가 이를 실행하는 방법을 학습했습니다. 이를 통해 Jetson Nano는 Arduino와의 통신을 통해 로봇의 상태를 모니터링하고 제어 명령을 내릴 수 있습니다. 다음 단계에서는 RPLIDAR와 RealSense 데이터를 통합하여 로봇의 자율 주행을 위한 SLAM 및 내비게이션 기능을 구현하겠습니다.
https://stupidly-honest.tistory.com/39
https://stupidly-honest.tistory.com/40
비슷한 프로젝트를 진행 중인데 몇가지 질문이 있어 댓글 남깁니다:)
1. 사용하신 Jetson Nano가 Jetson Orin Nano인가요? Jetson Nano는 우분투18.04기반이라 ROS2가 불가능한 것으로 알고 있습니다.
2. Jetson에서 수신한 Arduino의 IMU데이터의 주파수를 알 수 있을까요? Jetson과 Arduino 둘 사이의 딜레이가 궁금합니다.
좋은 포스팅 감사합니다!