Skip to content

๐Ÿ“™CartoonTime's Appliaction (Android)

Notifications You must be signed in to change notification settings

swthewhite/CartoonTime-Application

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

CartoonTime - Application

CartoonTime์€ Alltime์—์„œ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ํฌํ•จํ•œ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์ž…๋‹ˆ๋‹ค. BLE(Bluetooth Low Energy), UWB(Ultra-Wideband), FCM(Firebase Cloud Messaging), MQTT(Message Queuing Telemetry transport) ๋“ฑ์„ ํ™œ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋„คํŠธ์›Œํฌ ๋ฐ ๊ธฐ๊ธฐ ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ์„ ์ง€์›ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž์—๊ฒŒ ํŽธ๋ฆฌํ•œ UI/UX๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์†Œ๊ฐœ

์†Œ๊ฐœ

  • ์†Œ์ค‘ํ•œ ์‹œ๊ฐ„์„ ์•„๊ปด์ฃผ๊ณ 
  • ๊ฐœ์ธ์ •๋ณด๋ฅผ ํ™•์‹คํ•˜๊ฒŒ ์ง€์ผœ์ฃผ๊ณ 
  • ๊ด€๋ฆฌ ์ž๋™ํ™”๋กœ ๋ถ€๋‹ด์„ ์ค„์—ฌ์ฃผ๊ณ 
  • ์–ด๋Š ๋‹จ๋ง์—์„œ๋„ ์“ธ ์ˆ˜ ์žˆ๋Š”

์œ„์™€๊ฐ™์€ ํŠน์ง•์„ ๊ฐ€์ง„ ์ €ํฌ ์„œ๋น„์Šค๋Š” ๊ณ ๊ฐ๊ณผ ์‚ฌ์—…์ž ๋ชจ๋‘์—๊ฒŒ ํŽธ๋ฆฌํ•จ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ํ†ตํ•ฉ ์†”๋ฃจ์…˜ ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ

๊ฐ„ํŽธ ํšŒ์›๊ฐ€์ž…

ํšŒ์›๊ฐ€์ž… ์ „ํ™”๋ฒˆํ˜ธ ํ•˜๋‚˜๋กœ ์ง„ํ–‰๋˜๋Š” ํšŒ์›๊ฐ€์ž…์€ ๋ธ”๋ก์ฒด์ธ์„ ํ™œ์šฉํ•ด ๋”์šฑ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

์ž…/ํ‡ด์‹ค

์ž…์‹ค ํœด๋Œ€ํฐ์˜ ๋‹ค์–‘ํ•œ ์„ผ์„œ๋ฅผ ํ™œ์šฉํ•ด ๋ชจ์…˜์„ ์ธ์‹ํ•˜๊ณ  ํŠน์ • ๋ชจ์…˜์œผ๋กœ UWB๋ฅผ ํ™œ์„ฑํ™” ํ•œ ํ›„ ํ‚ค์˜ค์Šคํฌ์™€ ์—ฐ๊ฒฐํ•ด ์ž๋™์œผ๋กœ ์ž…ํ‡ด์‹ค์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. UWB ๊ธฐ๋Šฅ์ด ๊ผญ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ์•ฝ ๋‹จ๋ง๊ธฐ๊ฐ€ UWB๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ด์šฉํ•˜์‹ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ถฉ์ „

์ถฉ์ „ ์นด์นด์˜คํŽ˜์ด API๋ฅผ ์—ฐ๋™ํ•˜์—ฌ ์‰ฝ๊ฒŒ ํฌ์ธํŠธ๋ฅผ ์ถฉ์ „ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด ๋˜ํ•œ, ๋ธ”๋ก์ฒด์ธ ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฐ„ํŽธํ•จ์„ ์ถ”๊ตฌํ•˜๋ฉด์„œ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์†ก๊ธˆ/์ž…๊ธˆ

์†ก๊ธˆ ์ž…๊ธˆ 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
        }
    }

UWB ํ†ต์‹  ๋ชจ๋“ˆ

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);
    }
});

BLE ํ†ต์‹  ๋ชจ๋“ˆ

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()

๊ตฌ์„ฑ

ํ”„๋ ˆ์ž„์›Œํฌ

ํ”„๋ ˆ์ž„์›Œํฌ

ERD

ERD

ํ๋ฆ„๋„

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["์ž๋™ ํฌ์ธํŠธ ๊ฒฐ์ œ ๋ฐ ํ‡ด์‹ค ์™„๋ฃŒ"]
Loading

About

๐Ÿ“™CartoonTime's Appliaction (Android)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published