CartoonTime์ Alltime์์ ์ ๊ณตํ๋ ๋ค์ํ ๊ธฐ๋ฅ์ ํฌํจํ ์๋๋ก์ด๋ ์ฑ์ ๋๋ค. BLE(Bluetooth Low Energy), UWB(Ultra-Wideband), FCM(Firebase Cloud Messaging), MQTT(Message Queuing Telemetry transport) ๋ฑ์ ํ์ฉํ์ฌ ๋ค์ํ ๋คํธ์ํฌ ๋ฐ ๊ธฐ๊ธฐ ๊ฐ ์ํธ์์ฉ์ ์ง์ํ๋ฉฐ, ์ฌ์ฉ์์๊ฒ ํธ๋ฆฌํ UI/UX๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์์คํ ์๊ฐ์ ์๊ปด์ฃผ๊ณ
- ๊ฐ์ธ์ ๋ณด๋ฅผ ํ์คํ๊ฒ ์ง์ผ์ฃผ๊ณ
- ๊ด๋ฆฌ ์๋ํ๋ก ๋ถ๋ด์ ์ค์ฌ์ฃผ๊ณ
- ์ด๋ ๋จ๋ง์์๋ ์ธ ์ ์๋
์์๊ฐ์ ํน์ง์ ๊ฐ์ง ์ ํฌ ์๋น์ค๋ ๊ณ ๊ฐ๊ณผ ์ฌ์ ์ ๋ชจ๋์๊ฒ ํธ๋ฆฌํจ์ ์ ๊ณตํ๊ธฐ ์ํ ํตํฉ ์๋ฃจ์ ์๋น์ค์ ๋๋ค.
์ ํ๋ฒํธ ํ๋๋ก ์งํ๋๋ ํ์๊ฐ์ ์ ๋ธ๋ก์ฒด์ธ์ ํ์ฉํด ๋์ฑ ์์ ํ๊ฒ ๊ด๋ฆฌ๋ฉ๋๋ค. |
---|
UWB์ BLE๋ฅผ ์ฌ์ฉํ์ฌ ๊ทผ๊ฑฐ๋ฆฌ์์ ์ ๋ขฐ์ฑ ์๋ ์ก๊ธ ๊ธฐ๋ฅ์ ๊ตฌํํ์์ต๋๋ค. |
---|
๋ค์ด๋ฒ ์นํฐ์ ๋์ ํฌ๋กค๋งํ์ฌ ์ฌ์ฉ์์ ์ทจํฅ์ ๋ถ์ํฉ๋๋ค. ํน์ ์นํฐ์ ์ ์ฒด ํ์ฐจ์ ๋๋น ์ฝ์ ํ์ฐจ์๋ฅผ ํตํด ์ ์๋ฅผ ๋ถ์ฌํ๊ณ ์ด๋ฅผ ํ์ฉํฉ๋๋ค. |
---|
ํด๋ํฐ์ ํฌํจ๋ ๋ค์ํ ์ผ์๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
- ๊ฐ์๋ ์ผ์๋ฅผ ์ฌ์ฉํด ๋ชจ์ ์ ์ธ์ํ๊ณ UWB ์๋น์ค ๊ธฐ๋ฅ์ ํ์ฑํํฉ๋๋ค.
- ์ผ์ ์ ๋ถ๋ฅผ ์ฌ์ฉํด ์ค๋ด์์ ์ฌ์ฉํ ์ ์๋ ๋ด๋น๊ฒ์ด์ ์๋น์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
// ์ผ์๋ฅผ ํ์ฉํด ์ขํ๊ณ, ๋ฐฉํฅ์ ํน์ ํจ
fun calculateTargetDirection(current: Location, target: Location): Float {
// ์ขํ๊ณ: X์ ์ฆ๊ฐ ๋ฐฉํฅ์ด ์๋์ชฝ, Y์ ์ฆ๊ฐ ๋ฐฉํฅ์ด ์ผ์ชฝ
//val dx = current.x - target.x // X์ ์ฆ๊ฐ ๋ฐฉํฅ์ด ์๋์ชฝ์ด๋ฏ๋ก ๋ฐฉํฅ ๋ฐ๋๋ก ๊ณ์ฐ
val dx = -(target.x - current.x)
val dy = target.y - current.y // Y์ ์ฆ๊ฐ ๋ฐฉํฅ์ด ์ผ์ชฝ์ด๋ฏ๋ก ๋ฐฉํฅ ๋ฐ๋๋ก ๊ณ์ฐ
// ๊ฐ๋๋ฅผ ๊ณ์ฐํ๊ณ , 360๋๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ณด์
return Math.toDegrees(atan2(dy.toDouble(), dx.toDouble())).toFloat()
}
private fun calculateOrientation() {
// ๊ฐ์๋๊ณ์ ์๊ธฐ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฉํฅ ๊ณ์ฐ
val rotationMatrix = FloatArray(9)
val inclinationMatrix = FloatArray(9)
val orientationValues = FloatArray(3)
if (SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, accelerometerValues, magnetometerValues)) {
SensorManager.getOrientation(rotationMatrix, orientationValues)
val azimuth = Math.toDegrees(orientationValues[0].toDouble()).toFloat()
_direction.value = azimuth
}
}
Ultra-Wideband (UWB) ํต์ ์ ์ํ ๋ ๊ฐ์ ํด๋์ค๋ฅผ ํฌํจํ๊ณ ์์ต๋๋ค.
- ๋ ํด๋์ค ๋ชจ๋ Android์
UwbManager
์ RxJava๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฑฐ๋ฆฌ ์ธก์ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ๋ฉฐ, ์ธ์ ์์ฑ๊ณผ ์๋ฉธ์ ๋ช ํํ๊ฒ ๊ด๋ฆฌํฉ๋๋ค.
UwbController: UWB ์ปจํธ๋กค๋ฌ ์ธ์ ์ ์ด๊ธฐํํ๊ณ , UWB Controlee์์ ๊ฑฐ๋ฆฌ ์ธก์ ๊ณผ์ ์ ๊ด๋ฆฌํฉ๋๋ค. ๋ก์ปฌ UWB ์ฃผ์์ ์ฑ๋์ ๊ฐ์ ธ์ค๊ณ , ๊ฑฐ๋ฆฌ ์ธก์ ์ ์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํ๋ฉฐ, ํต์ ์ค์ ์ธก์ ๋ ๊ฑฐ๋ฆฌ๋ฅผ ์ฝ๋ฐฑ์ผ๋ก ์ ๋ฌํฉ๋๋ค. ์ธ์ ์ ์ข ๋ฃ ์ ๋ช ์์ ์ผ๋ก ์ค์งํ๊ณ ์์์ ํด์ ํ ์ ์์ต๋๋ค.
UwbController uwbController = new UwbController(context);
String uwbAddress = uwbController.getUwbAddress(); // ๋ก์ปฌ UWB ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ
uwbController.createRanging("12345", new RangingCallback() {
@Override
public void onDistanceMeasured(float distance) {
Log.d("UWB", "Measured Distance: " + distance);
}
});
UWBControlee: UWB controlee ์ธ์ ์ ์ด๊ธฐํํ์ฌ UWB Controller์์ ์ฐ๊ฒฐ์ ์ค์ ํฉ๋๋ค. ๋ก์ปฌ UWB ์ฃผ์๋ฅผ ๊ฐ์ ธ์ค๊ณ , ์ปจํธ๋กค๋ฌ์ ์ฃผ์์ ์ฑ๋์ ์ฌ์ฉํ์ฌ ๊ฑฐ๋ฆฌ ์ธก์ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ตฌ์ฑํ๋ฉฐ, ์ธก์ ๋ ๊ฑฐ๋ฆฌ๋ฅผ ์ฝ๋ฐฑ์ผ๋ก ๋ฐํํฉ๋๋ค. ์ธ์ ์ข ๋ฃ ์ ์์์ ํด์ ํ ์ ์์ต๋๋ค.
UWBControlee uwbControlee = new UWBControlee(context);
String uwbAddress = uwbControlee.getUWBAddress(); // ๋ก์ปฌ UWB ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ
uwbControlee.createRanging("54321", "9", new RangingCallback() {
@Override
public void onDistanceMeasured(float distance) {
Log.d("UWB", "Measured Distance: " + distance);
}
});
Bluetooth Low Energy (BLE) ๋ฅผ ์ด์ฉํ์ฌ ๊ธฐ๊ธฐ ๊ฐ UWB ํต์ ์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๊ณ , UWB ํต์ ์ ํตํด ๊ฑฐ๋ฆฌ๋ฅผ ์ธก์ ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- BLE ๊ธฐ๊ธฐ ๊ฒ์ ๋ฐ ์ฐ๊ฒฐ
- BLE ์๋น์ค ํ์ ๋ฐ ํน์ฑ ์ฝ๊ธฐ/์ฐ๊ธฐ
- ๋ค์ํ BLE ๋ชจ๋(KIOSK, WITCH)์ ๋ฐ๋ฅธ ํํฐ ์ ์ฉ
BLEScanner: BLE ๊ธฐ๊ธฐ ๊ฒ์์ ๋ด๋นํ๋ ํด๋์ค์
๋๋ค. ํน์ ๋ชจ๋(KIOSK
, WITCH
)์ ๋ฐ๋ผ ๋ค์ํ ์๋น์ค UUID๋ฅผ ๊ธฐ์ค์ผ๋ก BLE ๊ธฐ๊ธฐ๋ฅผ ๊ฒ์ํ๋ฉฐ, ๊ฒ์๋ ๊ธฐ๊ธฐ๋ฅผ ์ ์ฅ ๋ฐ ๊ด๋ฆฌํฉ๋๋ค.
// BLE ์ค์บ๋ ์์
val bleScanner = BLEScanner(context)
bleScanner.start("KIOSK")
BLEClient: BLE ํด๋ผ์ด์ธํธ๋ก์, ๋ค๋ฅธ ๊ธฐ๊ธฐ์ ์ฐ๊ฒฐํ๊ณ UWB ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์์ต๋๋ค. GATT ํ๋กํ ์ฝ์ ํตํด BLE ์๋น์ค์ ํน์ฑ์ ํ์ํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฐ๋ ์์ ์ ์ํํฉ๋๋ค.
// BLE ๊ธฐ๊ธฐ์ ์ฐ๊ฒฐ ํ ๋ฐ์ดํฐ ํต์
val bleClient = BLEClient(context, device, myUWBData, myIdData, "WITCH")
bleClient.connect()
bleClient.communicate()
BLEServerManager: BLE ์๋ฒ ์ญํ ์ ์ํํ์ฌ ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ๋ ํ ํน์ฑ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. UWB ์ฃผ์์ ์ฑ๋์ ์ ๊ณตํ๊ณ , ํด๋ผ์ด์ธํธ์์ ์ ์ก๋ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก BLE ํต์ ์ ๊ด๋ฆฌํฉ๋๋ค.
// BLE ์๋ฒ ์์
val bleServerManager = BLEServerManager(context, myIdData, "KIOSK", viewModel)
bleServerManager.startServer()
graph TD
A["์ฑ ์คํ"] --> B{"ํ์๊ฐ์
or ๋ก๊ทธ์ธ"}
B --> |"๋ก๊ทธ์ธ"| C["๋ค์ด๋ฒ ์์ด๋๋ก ์ทจํฅ ๋ถ์ (๋์ ํฌ๋กค๋ง)"]
B --> |"ํ์๊ฐ์
"| C
C --> D["ํค์ค์คํฌ ์ ์ด ๋ฐ UWB ์ฐ๊ฒฐ"]
D --> E["์
์ค ์งํ"]
E --> F["์ถ์ฒ ๋งํ ํ์ธ"]
F --> G{"ํฌ์ธํธ ์ถฉ์ ํ์"}
G --> |"์ถฉ์ "| H["์นด์นด์คํ์ด API ์ฐ๋์ผ๋ก ํฌ์ธํธ ์ถฉ์ "]
G --> |"์ถฉ์ ์ํจ"| I["ํฌ์ธํธ ์ก๊ธ/์
๊ธ"]
I --> J["๊ทผ๊ฑฐ๋ฆฌ BLE/UWB ์ก๊ธ"]
J --> K["ํค์ค์คํฌ ์ ์ด ๋ฐ ํด์ค ์งํ"]
K --> L["์๋ ํฌ์ธํธ ๊ฒฐ์ ๋ฐ ํด์ค ์๋ฃ"]