[65호]Simple Touch
Simple Touch
글 | 동양미래대학교 박재범, 김도경, 김성곤, 김예빈, 김종혁, 이연수, 이정원, 장여원
1. 심사평
칩센 기술 자체가 어려운 것은 아니지만 아이디어가 매우 눈에 띄는 작품입니다. 특히 기존 시스템을 모두 교체하는 것이 아닌 일부만 대체하는 것만으로도 적용 가능하게 하는 부분은 훌륭한 발상입니다. 동작 방식 자체는 매우 심플하게 이해가 되었고, 실제 적용을 위해서 운용에 대한 방식은 조금 더 고민이 필요할 듯 합니다. 블루투스 보다 와이파이가 더 적절해 보이는 판단을 하고 적용하였으나, 이 또한 실제 적용에는 어려움이 있을 수 있습니다(주변 버스와의 구분등). 이러한 추가적인 고민을 통하면 매우 실용적인 장치가 될듯합니다.
펌테크 실생활에 활용될 수 있는 아이디어와 실용성을 지닌 작품이라고 생각합니다. 전체적으로 시스템을 꼼꼼하게 잘 구성하였고 생각하며 학부 과정의 학생이 구현하기에 적정한 난이도를 가진 작품이라고 생각합니다.
위드로봇 간단하지만 유용한 아이디어를 구현한 작품입니다.
2. 작품 개요
보도자료에 따르면 서울시에서만 하루 500만 명 이상의 시민들이 버스를 이용한다. 서울특별시 인구만으로 따져 보아도 2명 중 1명꼴로 버스를 이용하는 셈이다. 그만큼 버스는 우리에게 떼어놓을 수 없는 교통수단이다.
이렇게 많은 이들이 이용하는 까닭에 버스 이용 시 몇몇 불편함을 느낄 수 있는데, 특히 출퇴근 길 “러시아워” 시간대의 버스를 타기란 고통에 가깝다, 가까스로 버스 승차에 성공하더라도 하차하려는 것이 여간 어려운 것이 아닌데, 사람들로 가득 찬 버스 안에서 사람들 사이를 비집고 나아가 손으로 직접 하차벨을 누르기란 참으로 어려운 일이기 때문이다. 이에 최근 운행하는 신형 버스는 구형 버스보다 하차벨이 증설되었지만, 여전히 사람이 많은 버스에서 손으로 벨을 누르기에 불편한 상황임은 사실이다.
한편 최근 대두되고 있는 전염병 사태에서 직접 접촉에 의한 감염 사례도 나오고 있는 것을 보면 불특정 다수의 손길이 닿은 하차벨을 선뜻 누르기 어려운 경우도 있을 것이다. “직접적인 접촉을 하지 않고 하차벨을 누를 수 있는 방법은 없을까?” 이와 같은 물음에서 작품의 아이디어를 끌어내 보았다.
3. 작품 설명
3.1. 주요 동작 및 특징
3.1.1. 스마트폰 App으로 버스 하차벨 점등
· 통신을 위해 모든 하차벨을 교체할 필요 없이 하나의 하차벨 교체만으로도 시스템에 적용 가능함
· 하차벨을 누르기 위한 불필요한 움직임이 줄어들어 버스 내 안전사고 발생확률 감소를 기대할 수 있음
· 코로나19와 같은 전염병 사태에 불특정 다수가 접촉할 우려가 큰 하차벨에 접촉하지 않음으로서 접촉에 의한 전염병 감염사례 감소의 기대와 버스 이용 승객의 심적 안정을 도모할 수 있음
3.2. 전체 시스템 구성(전체 알고리즘)
3.3. 개발환경
4. 단계별 제작 과정
4.1. 시스템 설계
초기 스케치에서와 같이 일대다 통신 구현을 위해 Bluetooth와 WiFi 통신이 논의 되었으나, Bluetooth 통신 방식의 동시 접속 가능 기기 제한으로 인하여 WiFi 통신 방식을 채택한다.
WiFi 통신 모듈 선정
4.2. 하드웨어 제작
4.3. 하차벨 시스템 소프트웨어 작성
4.4. 스마트폰 App 소프트웨어 작성
4.5. 시스템 구현
4.6. 결론 및 전망
위와 같이 스마트폰 어플리케이션을 통해 버스 벨을 점등하는 테스트를 성공적으로 완료하였다. Java를 처음 다뤄보며 개발한 첫 어플리케이션이었기에 UI나 여러 편의사항 등에서 부족한 부분도 있었지만, 본 목적에 충실하게끔 구현했다는 점에서 큰 만족감을 가질 수 있었다.
본 아이디어는 비용과 시스템 구현 측면에서 여러 이점이 있는데, 제작 시 사용한 Lolin D1 mini를 대체해 ESP8266-01 등의 모듈을 사용한다면 저렴한 비용으로 단 하나의 벨 교체를 통해 무선 하차벨 시스템을 구현 할 수 있을 것으로 보인다.
한편 서울특별시 버스정책과에 문의해본 결과 올해 6월부터는 서울시내 버스 8000여대에서 공공와이파이를 이용할 수 있다고 하였다. 추후 공공와이파이를 이용한 시스템 구축을 통해 더 효율적이고 편리한 무선 하차벨 시스템을 제공할 수 있을 것으로 보인다.
경향신문 기사([‘코로나19’ 확산 비상]버스 하차벨 서로 미루고, 출입문 손 대신 어깨로 열어…‘거리두기’가 바꾼 일상)의 인터뷰에서는 코로나 19로 인한 버스에서의 현 상황이 잘 드러나고 있다. 본 아이디어는 이러한 대규모 전염병 사태에 있어 미약하게나마 감염 전파를 막는 요소가 될 수 있을 것이라 기대한다.
5. 기타
5.1. 회로도
bus_system.ino
int bell_led_1 = 22;
int bell_button_1 = 23;
int bell_test_1 = 24;
int bell_led_2 = 26;
int bell_button_2 = 27;
int bell_test_2 = 28;
int bell_led_3 = 30;
int bell_button_3 = 31;
int bell_test_3 = 32;
int bell_led_4 = 34;
int bell_button_4 = 35;
int bell_test_4 = 36;
int bell_led_5 = 38;
int bell_button_5 = 39;
int bell_test_5 = 40;
int door_button = 42;
boolean bell_signal_1;
boolean bell_signal_2;
boolean bell_signal_3;
boolean bell_signal_4;
boolean bell_signal_5;
boolean door_signal;
boolean total_signal;
boolean state;
void setup() {
pinMode(bell_led_1, OUTPUT);
pinMode(bell_led_2, OUTPUT);
pinMode(bell_led_3, OUTPUT);
pinMode(bell_led_4, OUTPUT);
pinMode(bell_led_5, OUTPUT);
pinMode(bell_button_1, INPUT);
pinMode(bell_button_2, INPUT);
pinMode(bell_button_3, INPUT);
pinMode(bell_button_4, INPUT);
pinMode(bell_button_5, INPUT);
pinMode(bell_test_1, OUTPUT);
pinMode(bell_test_2, OUTPUT);
pinMode(bell_test_3, OUTPUT);
pinMode(bell_test_4, OUTPUT);
pinMode(bell_test_5, OUTPUT);
pinMode(door_button, INPUT);
Serial.begin(115200);
Serial.println(“Setting done….”);
normal_state();
}
void normal_state() {
digitalWrite(bell_led_1, LOW);
digitalWrite(bell_led_2, LOW);
digitalWrite(bell_led_3, LOW);
digitalWrite(bell_led_4, LOW);
digitalWrite(bell_led_5, LOW);
digitalWrite(bell_test_1, HIGH);
digitalWrite(bell_test_2, HIGH);
digitalWrite(bell_test_3, HIGH);
digitalWrite(bell_test_4, HIGH);
digitalWrite(bell_test_5, HIGH);
state = 0;
}
void pushed_state() {
digitalWrite(bell_led_1, HIGH);
digitalWrite(bell_led_2, HIGH);
digitalWrite(bell_led_3, HIGH);
digitalWrite(bell_led_4, HIGH);
digitalWrite(bell_test_1, LOW);
digitalWrite(bell_test_2, LOW);
digitalWrite(bell_test_3, LOW);
digitalWrite(bell_test_4, LOW);
digitalWrite(bell_test_5, LOW);
state = 1;
}
void read_signal() {
bell_signal_1 = digitalRead(bell_button_1);
bell_signal_2 = digitalRead(bell_button_2);
bell_signal_3 = digitalRead(bell_button_3);
bell_signal_4 = digitalRead(bell_button_4);
bell_signal_5 = digitalRead(bell_button_5);
door_signal = digitalRead(door_button);
Serial.println(“b1, b2, b3, b4, b5, Door”);
Serial.print(bell_signal_1);
Serial.print(” “);
Serial.print(bell_signal_2);
Serial.print(” “);
Serial.print(bell_signal_3);
Serial.print(” “);
Serial.print(bell_signal_4);
Serial.print(” “);
Serial.print(bell_signal_5);
Serial.print(” “);
Serial.println(door_signal);
total_signal = bell_signal_1||bell_signal_2||bell_signal_3||bell_signal_4||bell_signal_5;
}
void self_holding () {
if (state==0) {
if (total_signal == 1) {
pushed_state();
Serial.println(“bell pushed….”);
}
}
else if (state == 1) {
if (door_signal == 0) {
normal_state();
Serial.println(“door opend….”);
}
}
}
void loop() {
read_signal();
self_holding();
delay(100);
}
5.2.2. Lolin D1 mini 소스코드
wifi_module.ino
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#ifndef APSSID
#define APSSID “ICT_TEST”
#define APPSK “ict_test”
#endif
const char *ssid = APSSID;
const char *password = APPSK;
ESP8266WebServer server(80);
uint8_t LED_PIN = 4;
bool LED_PIN_STATUS = LOW;
void handleRoot() {
LED_PIN_STATUS = LOW;
server.send(200, “text/html”, “<h1>You are connected</h1>”);
}
void handleRoot_on() {
LED_PIN_STATUS = HIGH;
server.send(200, “text/html”, “<h1> LED ON </h1>”);
}
void setup() {
delay(1000);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, 0);
Serial.begin(115200);
Serial.println();
Serial.print(“Configuring access point…”);
WiFi.softAP(ssid, password);
IPAddress myIP = WiFi.softAPIP();
Serial.print(“AP IP address: “);
Serial.println(myIP);
server.on(“/”, handleRoot);
server.on(“/on”, handleRoot_on);
server.begin();
Serial.println(“HTTP server started”);
}
void loop() {
server.handleClient();
if(LED_PIN_STATUS) {
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
LED_PIN_STATUS =!LED_PIN_STATUS;
}
else
{digitalWrite(LED_PIN, LOW);}
}
5.2.3. 스마트폰 App 소스코드
AndroidManifest.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.example.pleaseplease”>
<uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />
<uses-permission android:name=”android.permission.CHANGE_WIFI_STATE” />
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION”/>
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/>
<application
android:allowBackup=”true”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:roundIcon=”@mipmap/ic_launcher_round”
android:supportsRtl=”true”
android:theme=”@style/AppTheme”>
<activity android:name=”.MainActivity”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:orientation=”vertical”
tools:context=”.MainActivity”>
<Button
android:id=”@+id/button”
android:layout_width=”match_parent”
android:layout_height=”48dp”
android:text=”STOP”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />
</LinearLayout>
MainActivity.java
package com.example.pleaseplease;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private WebView webview;
private String networkSSID = “ICT_TEST”;
private String networkPass = “ict_test”;
private WifiManager wifiManager;
private WifiConfiguration wifiConfiguration;
private int size = 0;0
private ArrayList<String> arrayList = new ArrayList<>();
private ArrayAdapter<String> adapter;
private static final String TAG = “MyActivity”;
Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonScan = findViewById(R.id.button);
buttonScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scanWifi();
if (wifiManager.isWifiEnabled()) {
String url = “http://192.168.4.1/on”;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
}
});
wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
assert wifiManager != null;
if (!wifiManager.isWifiEnabled()) {
Toast.makeText(this, “wifi is disabled… connecting…”, Toast.LENGTH_SHORT).show();
wifiManager.setWifiEnabled(true);
}
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
scanWifi();
}
private void scanWifi() {
arrayList.clear();
registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
wifiManager.startScan();
Toast.makeText(this, “Scanning…..”, Toast.LENGTH_SHORT).show();
}
BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
List<ScanResult> results = wifiManager.getScanResults();
Log.i(TAG, String.format(“size—-%d”, results.size()));
unregisterReceiver(this);
for (ScanResult scanResult : results) {
Log.i(TAG, String.format(“—-%s”, scanResult.SSID));
arrayList.add(scanResult.SSID);
adapter.notifyDataSetChanged();
if (scanResult.SSID.equals(networkSSID)) {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = networkSSID;
wifiConfiguration.preSharedKey = networkPass;
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
int netId = wifiManager.addNetwork(wifiConfiguration);
Log.i(TAG, String.format(“netId = = = =%s”, netId));
if (netId == -1) {
existconnect();
Log.i(TAG, String.format(“connect to %s”, scanResult.SSID));
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
} else {
Log.i(TAG, String.format(“connect to %s”, scanResult.SSID));
wifiManager.disconnect();
wifiManager.enableNetwork(netId, true);
wifiManager.reconnect();
}
}
}
}
};
public void existconnect() {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
assert wifiManager != null;
List<WifiConfiguration> wifiConfigurations = wifiManager.getConfiguredNetworks();
if (wifiConfigurations != null) {
for (WifiConfiguration configuration : wifiConfigurations) {
int id = configuration.networkId;
String ssid = configuration.SSID;
Log.i(TAG, String.format(“NW———-%3d %s”, id, ssid));
if (ssid.equals(networkSSID)) {
Log.i(TAG, String.format(“coneect to %3d %s”, id, ssid));
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = ssid;
wifiConfiguration.preSharedKey = networkPass;
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
wifiManager.disconnect();
wifiManager.enableNetwork(id, true);
wifiManager.reconnect();
}
}
}
}
}
5.3. 참고자료
· 서울특별시 보도자료 『2019년 서울 돌아보기(20200211)』
· https://en.wikipedia.org/wiki/Bluetooth_Low_Energy
· https://opengov.seoul.go.kr/mediahub/19181864
· http://news.khan.co.kr/kh_news/khan_art_view.html?art_id=202003052147015