About me
home
Portfolio
home

블루투스 메모장

진행 상태
완료
팀원
마감일
2023/11/14 → 2023/11/18
태그
작업 (하위 작업)에 관계됨
3 more properties
크기 (43 ×\times 15 ×\times 7 mm)
동작 전압 : 3.6V ~ 6V
통신 거리 : 약 10m
baud rate : 1200 ~ 115200bps
사용 전류 : ~10mA
결선 회로도
소스코드
#include <SoftwareSerial.h> // 블루투스 시리얼 통신 라이브러리 추가 #define BT_RXD 8 #define BT_TXD 7 SoftwareSerial bluetooth(BT_RXD, BT_TXD); // 블루투스 설정 BTSerial(Tx, Rx) void setup() { Serial.begin(9600); bluetooth.begin(9600); // 블루투스 통신 시작 } void loop() { if (bluetooth.available()) { // 블루투스에서 보낸 내용은 시리얼모니터로 전송 Serial.write(bluetooth.read()); } if (Serial.available()) { // 시리얼모니터에서 보낸 내용은 블루투스로 전송 bluetooth.write(Serial.read()); } }
Arduino
복사
블루투스 모듈과 핸드폰과 연결이 가능함(IOS)는 안됨
안녕하세요 메카솔루션입니다.
블루투스로 rssi를 측정하신다면 기존의 HC-06으로는 불가능합니다.
다만 AT명령어를 쓸 수 있는 경우 INQ라는 명령을 이용하면 rssi를 받을 수 있다고 나와 있었습니다.
HM-10 + rssi + 칼만필터 출처:

2. 센서 제어

2.1 아두이노 블루투스 모듈(HM-10)

기존 HC-06 모듈보다 더 다양한 기능을 사용할 수 있는 HM-10 블루투스 모듈을 사용함
사용 목적 : 사람과 멀리 떨어지면 안내로봇이 기다리기 기능
아두이노 보드로 마스터 - 슬레이브 연결로 블루투스 통신 가능
동작 전압 : 2.5V ~ 3.3V
통신 거리 : 약 10m (HC-06) → 40m(HM-10)
baud rate : 1200 ~ 115200bps
사용 전류 : ~50mA
HC-06의 경우 안드로이드 핸드폰만 연결 가능했지만, HM-10인 경우 아이폰도 가능하다.

2.2 아두이노 환경

2.3 소스 코드

master
#include <SoftwareSerial.h> SoftwareSerial bluetooth(2, 3); // RX, TX void setup() { Serial.begin(9600); bluetooth.begin(9600); delay(1000); sendATCommand("AT+RENEW"); delay(1000); sendATCommand("AT"); delay(1000); sendATCommand("AT+ROLE1"); delay(1000); sendATCommand("AT+IMME1"); delay(3000); sendATCommand("AT+CON10CEA9FCDF5B"); } void loop() { sendATCommand("AT+RSSI?"); delay(10); } void sendATCommand(String command) { bluetooth.print(command); delay(500); while (bluetooth.available()) { char c = bluetooth.read(); Serial.print(c); } Serial.print("\r\n"); }
Arduino
복사
slave
#include <SoftwareSerial.h> SoftwareSerial bluetooth(2,3); // RX, TX void setup() { //기본 통신속도는 9600입니다. Serial.begin(9600); bluetooth.begin(9600); delay(1000); // 명령 실행에 충분한 시간을 줍니다. sendATCommand("AT+RENEW"); delay(1000); sendATCommand("AT"); delay(1000); sendATCommand("AT+ROLE0"); delay(7000); // sendATCommand("AT+IMME1"); // delay(1000); // sendATCommand("AT+ADDR?"); } void loop() { if (bluetooth.available()) { Serial.write(bluetooth.read()); } if (Serial.available()) { bluetooth.write(Serial.read()); } } void sendATCommand(String command) { bluetooth.print(command); delay(500); // 명령 실행에 충분한 시간을 줍니다. //Serial.print("hi1"); while (bluetooth.available()) { char c = bluetooth.read(); //Serial.print("hi2"); Serial.print(c); } Serial.print("\r\n"); }
Arduino
복사

2.4 노이즈 제거

Kalman filter(정지 상태에서 노이즈 제거, sampling 주기: 500ms)
Kalman filter(운동 상태에서 노이즈 제거, 일반적인 걸음 속도, 출발 지점과 도착 지점 왕복, sampling 주기 : 10ms)
Kalman filter의 경우 전체적인 추세를 잘 추종하지 못함 → 예측 모델에 대한 노이즈(0.1)에 대한 파라미터 값을 변화 시킴
예측 모델에 대한 노이즈를 증가시키면 센서 값에 더 fitting이 되지만 예측 모델에 대한 노이즈가 증가하는 단점이 있다. 아래 그림은 예측 모델에 대한 노이즈를 0.1 → 0.5로 증가시킨 그림이다.
칼만 필터는 이전 상태만 저장하면 되기 때문에 실시간으로 센서 정보를 활용할 때 좋다.
moving average filter
정지 상태에서 moving average filter(sampling 주기: 500ms)
이동 상태에서 moving average filter, 평균에 사용할 데이터 갯수 = 15개(sampling 주기 : 10ms)
아래 그림은 초기 부분을 제외하고 나머지 데이터를 plot한 그림이다. (필터 계산은 위 그림과 동일한 과정으로 진행하고 plot할 때만 출력을 진행 한함)
moving average filter 경우 초기에는 오차가 발생하지만 데이터가 누적이 되면서 데이터의 전체적인 추세를 잘 추종하는 것을 파악함(평균에 사용되는 데이터의 갯수 + 5 이후부터 어느 정도 데이터를 잘 추종함)
moving average filter 특징
데이터가 누적되면 noise 제거 성능이 올라간다.
급격한 변화에 잘 대응하지 못한다.

2.5 rssi 수신 세기에 따른 거리 계산

2.7 ROS를 활용한 실시간 거리 계산

메인 컴퓨터
#!/usr/bin/python # -*- coding: utf-8 -*- import rospy from std_msgs.msg import String import queue avg_num = 15 class KalmanFilter(): def __init__(self, processNoise=0.05, measurementNoise=20): super(KalmanFilter, self).__init__() self.initialized = False # 예측 모델의 noise self.processNoise = processNoise # 측정 값의 노이즈 self.measurementNoise = measurementNoise self.predictedRSSI = 0 self.errorCovariance = 10 # 초기 오차 공분산을 1로 설정합니다. def filtering(self, rssi): if not self.initialized: self.initialized = True self.predictedRSSI = rssi # 초기 예측값은 측정값과 같이 설정합니다. else: # 예측 단계 predictedRSSI = self.predictedRSSI # 오차 공분산 업데이트 errorCovariance = self.errorCovariance + self.processNoise # 업데이트 단계 kalmanGain = errorCovariance / (errorCovariance + self.measurementNoise) # rssi 예측 self.predictedRSSI = predictedRSSI + kalmanGain * (rssi - predictedRSSI) # 오차 공분산 업데이트 self.errorCovariance = (1 - kalmanGain) * errorCovariance return self.predictedRSSI class MovAvgFilter: # 이전 스텝의 평균 prevAvg = 0.0 # 가장 최근 n개의 값을 저장하는 큐 xBuf = queue.Queue() # 참조할 데이터의 갯수 global num def __init__(self, _n = avg_num): # 초기화로 n개의 값을 0으로 둡니다. for _ in range(_n): self.xBuf.put(0) # 참조할 데이터의 갯수를 저장합니다. self.n = _n def filtering(self, x): # 큐의 front 값은 x_(k-n) 에 해당합니다. front = self.xBuf.get() # 이번 스텝에 입력 받은 값을 큐에 넣습니다. self.xBuf.put(x) avg = self.prevAvg + (x - front) / self.n self.prevAvg = avg return avg def cal_distance(rssi, alpha = -60, n = 4): distance = 10**((alpha - rssi)/(10*n)) return distance def rssi_callback(data): # filter = MovAvgFilter(avg_num) filter = KalmanFilter() line = data.data remove_line = line.strip().replace('OK+Get:', '') rssi = float(remove_line) filtered_rssi = filter.filtering(rssi) final_distance = cal_distance(filtered_rssi, alpha=-60, n=4) rospy.loginfo("RSSI to Distance : %f", final_distance) def rssi_listener(): rospy.init_node('rssi_listener', anonymous=True) rospy.Subscriber("rssi", String, rssi_callback, 10) rospy.spin() if __name__ == '__main__': try: rssi_listener() except rospy.ROSInterruptException: pass
Python
복사
아두이노 master
#include <SoftwareSerial.h> #include <ros.h> #include <std_msgs/String.h> SoftwareSerial bluetooth(2, 3); // RX, TX ros::NodeHandle nh; std_msgs::String rssi_msg; ros::Publisher rssi_pub("rssi", &rssi_msg); void setup() { Serial.begin(9600); bluetooth.begin(9600); delay(1000); sendATCommand("AT+RENEW"); delay(1000); sendATCommand("AT"); delay(1000); sendATCommand("AT+ROLE1"); delay(1000); sendATCommand("AT+IMME1"); delay(3000); sendATCommand("AT+CON10CEA9FCDF5B"); nh.initNode(); nh.advertise(rssi_pub); } void loop() { sendATCommand("AT+RSSI?"); // cost 40ms delay(10); // cost 10ms // total 50ms // Read RSSI data from the Bluetooth module String rssiData = readATResponse(); // Publish the RSSI data as a string to the "rssi" topic rssi_msg.data = rssiData.c_str(); rssi_pub.publish(&rssi_msg); nh.spinOnce(); } void sendATCommand(String command) { bluetooth.print(command); delay(40); } String readATResponse() { String response = ""; while (bluetooth.available()) { char c = bluetooth.read(); response += c; } return response; }
Arduino
복사
아두이노에서 master 모듈이 slave를 이용해 블루투스 세기(rssi신호)를 측정하고, 측정값을 메인 컴퓨터로 string토픽을 보낸다. 이를 가공해 거리를 출력하게 된다.

2.7 앞으로 할 일

블루투스 세기에 따른 거리 계산 코드 구현
real-time으로 거리를 계산하도록 시스템 구축
실제 블루투스 테스트
HM-10 통신속도 수정
절대 AT+BAUD7하면 안됨!!! 그러면 하드웨어 먹통되어서 AT명령어 안됨
HM-10을 사면 AT+BAUD3으로 통신 속도를 57600으로 설정 ⇒ ros의 통신 속도가 57600이어서 이렇게 해줘야 함
#include <SoftwareSerial.h> #include <ros.h> #include <std_msgs/String.h> SoftwareSerial bluetooth(2, 3); // RX, TX ros::NodeHandle nh; std_msgs::String rssi_msg; ros::Publisher rssi_pub("rssi", &rssi_msg); void setup() { nh.initNode(); nh.advertise(rssi_pub); Serial.begin(57600); bluetooth.begin(57600); delay(1000); // sendATCommand("AT+RENEW"); // delay(1000); sendATCommand("AT"); delay(1000); sendATCommand("AT+ROLE1"); delay(1000); sendATCommand("AT+IMME1"); delay(3000); sendATCommand("AT+CON10CEA9FCDF5B"); } void loop() { // sendATCommand("AT+RSSI?"); // cost 40ms delay(10); // cost 10ms // total 50ms // Read RSSI data from the Bluetooth module String rssiData = readATResponse("AT+RSSI?"); // Publish the RSSI data as a string to the "rssi" topic rssi_msg.data = rssiData.c_str(); rssi_pub.publish(&rssi_msg); Serial.println(rssiData); nh.spinOnce(); } void sendATCommand(String command) { bluetooth.print(command); delay(500); while (bluetooth.available()) { char c = bluetooth.read(); Serial.print(c); } Serial.print("\r\n"); // } } String readATResponse(String command) { String response = "0"; bluetooth.print(command); delay(500); while (bluetooth.available()) { char c = bluetooth.read(); response += c; Serial.print(c); return "1" + response ; } char c = bluetooth.read(); response = c + "s"; return response; }
Arduino
복사
해당 코드를 조금 손봐야함
1.
slave에 해당 코드 넣기
#include <SoftwareSerial.h> // 블루투스 시리얼 통신 라이브러리 추가 #define BT_RXD 2 #define BT_TXD 3 SoftwareSerial bluetooth(BT_RXD, BT_TXD); // 블루투스 설정 BTSerial(Tx, Rx) void setup() { Serial.begin(57600); bluetooth.begin(57600); // 블루투스 통신 시작 } void loop() { if (bluetooth.available()) { // 블루투스에서 보낸 내용은 시리얼모니터로 전송 Serial.write(bluetooth.read()); } if (Serial.available()) { // 시리얼모니터에서 보낸 내용은 블루투스로 전송 bluetooth.write(Serial.read()); } }
Arduino
복사
2.
AT+ADDR? : 해당 블루투스 모듈(slave)에 mac주소를 받아옴
3. 이후 master의 AT+CON에 slave mac 주소 붙이기 ex) AT+CON10CEA9FCDF5B
터미널 실행 명령어
1.
roscore
2.
rosrun rosserial_python serial_node.py _port:=/dev/ttyACM0 _baud:=9600
3.
rostopic echo /rssi
ROS serial 전송 속도를 바꿀 수 있는 듯?