•
크기 (43 15 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 전송 속도를 바꿀 수 있는 듯?