수역의 총 용존 고형물 (TDS), 온도, pH 및 탁도를 모니터링하고 데이터를 SD 카드에 기록 할 수있는 환경 모니터링 시스템을 구축, 프로그래밍 및 배포하는 방법을 보여줍니다.
이 프로젝트는 자연 수역의 환경 모니터링과 폐수 처리장의 수질 모니터링에 모두 적용됩니다.
테스트에서 TDS, 온도 및 pH 센서는 이 가이드를 따르는 동안 예상대로 작동하는 반면 탁도 센서는 부정확한 결과를 생성하므로 추가 교정 및 개발을 통해 해결해야 합니다.
공급
-아두이노 우노
-USB 유형 A 유형 B 케이블
-브레드보드
-점퍼 와이어
-4.7k 옴 저항기
-마이크로 SD 카드 – Arduino가 5 분마다 판독 할 때 일주일 분량의 데이터는 100kb 미만이므로 대용량 카드가 필요하지 않으며 4GB이면 충분합니다.
-20,000mAh USB 배터리 팩: 현장 테스트에서 새 20,000mAh 배터리로 조립된 시스템에 약 325주일 동안 전원을 공급할 수 있는 것으로 나타났습니다. 우리는 앵커 휴대용 충전기, 20 파워 뱅크 (파워 코어 에센셜 07K)를 사용했습니다 : https://www.amazon.com/Anker-PowerCore-Technology-High-Capacity-Compatible/dp/B829S1LBX/ref=sr_5_208?crid=8ARKCHV20DGQ&keywords=2k%2Bmah%1663975864Bpowerbank&qid=2&qu=eyJxc4MiOiIyLjAwIiwicXNhIjoiMC6wMCIsInFzcCI3IjAuMDAifQ%3D%20D&sprefix=2%2Bk%2Bmah%2Bpowebank%2Caps%152C8&sr=5-1&th=20 처음에는 연장된 테스트 기간 동안 시간 초과되지 않는 연속 전원 모드가 있기 때문입니다. 프로젝트를 더 저렴하게 만들려고 노력하는 동안 우리는 저렴한 000,20 MAH 배터리를 고소하기 시작했으며 Amazon에서 좋은 평가를 받은 대부분의 000,<>mAh 배터리가 작동한다는 것을 발견했습니다.
● 방수 케이스: 우리는 이것을 사용했습니다 : https://www.amazon.com/dp/B003FYMVXM/?coliid=I2L2ITZ7RGRUYS&colid=G9X5Z2M6GXGY&ref_=lv_ov_lig_dp_it&th=1
그러나 크기가 약 11.1"L x 7.6"W x 4.2"H인 방수 케이스는 모두 작동합니다. 공공 장소에서 이 시스템을 사용하려는 경우 눈에 잘 띄지 않도록 검은색 또는 위장 케이스를 사용하는 것이 좋습니다.
-1 피트의 1 "PVC 파이프
-1" PVC 캡
-1-1/4인치 x 1인치 PVC 부싱
-6 피트의 16 AWG 스피커 와이어
-열수축 튜브
-PVC 시멘트
-실리콘 실란트
● 덕트 테이프
● 플렉스 테이프
● 지퍼 타이
센서:
-DFRobot 중력: 아두이노를 위한 아날로그 탁도 감지기: https://www.dfrobot.com/product-1394.html
-DFRobot 중력: 아두이노 https://www.dfrobot.com/product-1662.html 용 아날로그 TDS 센서/미터
-DFRobot 중력: 아날로그 pH 센서/미터 프로 키트 V2
다른 모델을 사용해 보았지만 보정이 쉽고 안정적이며 내구성이 있기 때문에이 모델을 선택했습니다. 다음에서 구입할 수 있습니다 : https://www.dfrobot.com/product-2069.html
- DS18B20 방수 온도 센서
1단계: 소프트웨어 설정
아두이노를 프로그래밍하려면 아두이노 IDE를 설치해야 합니다. 최신 버전은 다음에서 찾을 수 있습니다 : https://www.arduino.cc/en/software
조립된 센서 시스템이 작동하려면 특정 하드웨어 부품에 대한 라이브러리가 필요합니다. zip 파일에서 Arduino 라이브러리를 설치하는 방법에 대한 지침은 다음 지침을 참조하십시오. https://docs.arduino.cc/software/ide-v1/tutorials/installing-libraries
DF 로봇 PH 라이브러리의 경우 다음 링크를 사용하십시오 : https://github.com/DFRobot/DFRobot_PH/archive/master.zip
온도 센서에 사용되는 최신 버전의 OneWire 라이브러리를 설치하려면 다음 링크를 사용하십시오.
https://www.arduino.cc/reference/en/libraries/onewire/
달라스 온도 라이브러리를 설치하려면 Arduino IDE를 열고 다음으로 이동하십시오. 스케치 > 포함 라이브러리 > 라이브러리 관리
"Dallas"를 검색한 다음 Miles Burton의 DallasTemperature 라이브러리를 설치합니다.
2단계: PH 센서 하드웨어 조립
전체 시스템을 조립하기 전에 pH 센서를 교정하고 테스트해야 하며 교정 프로세스 중 간섭을 방지하기 위해 Arduino에 연결된 유일한 센서입니다. 첨부 된 다이어그램과 같이 하드웨어를 조립하고 아래 코드를 복사하여 Arduino IDE에 붙여 넣거나 첨부 파일을 다운로드하십시오.
/*!
* @file DFRobot_PH_Test.h
* @brief 이것은 중력에 대한 샘플 코드입니다: 아날로그 pH 센서/미터 키트 V2, SKU: SEN0161-V2.
* @n 정밀도를 보장하기 위해 자동 온도 보상을 실행하기 위해 DS18B20과 같은 온도 센서가 필요합니다.
* @n 직렬 모니터에서 명령을 보내 보정을 실행할 수 있습니다.
* @n 직렬 명령:
* @n 엔터 -> 교정 모드로 들어갑니다.
* @n calph -> 표준 완충액 으로 구경측정하십시오, 4개의 완충액 (0.7와 0.<>)는 자동적으로 인식될 것입니다
* @n exitph - > 교정 된 매개 변수를 저장하고 교정 모드를 종료합니다.
*
* @copyright 저작권 (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @license MIT 라이센스 (MIT)
* @author [자웨이 Zhang](jiawei.zhang@dfrobot.com)
* @version V1.0
* @date 2018-11-06
* @url https://github.com/DFRobot/DFRobot_PH
*/
#include "DFRobot_PH.h"
#include <EEPROM.h>
#define PH_PIN A1
float voltage,phValue,temperature = 25;
DFRobot_PH ph;
void setup()
{
Serial.begin(115200);
ph.begin();
}
void loop()
{
static unsigned long timepoint = millis();
if(millis()-timepoint>1000U){ //time interval: 1s
timepoint = millis();
//temperature = readTemperature(); // read your temperature sensor to execute temperature compensation
voltage = analogRead(PH_PIN)/1024.0*5000; // read the voltage
phValue = ph.readPH(voltage,temperature); // convert voltage to pH with temperature compensation
Serial.print("temperature:");
Serial.print(temperature,1);
Serial.print("^C pH:");
Serial.println(phValue,2);
}
ph.calibration(voltage,temperature); // calibration process by Serail CMD
}
float readTemperature()
{
//add your code here to get the temperature from your temperature sensor
}
3단계: DFRobot Pt 1의 세부 지침에 따라 보정
정확성을 보장하기 위해 프로브는 처음 사용할 때와 장기간 사용하지 않은 후(이상적으로는 한 달에 한 번) 교정해야 합니다. 이 자습서에서는 4점 교정을 사용하므로 0.7 및 0.<>의 두 가지 표준 버퍼 솔루션이 필요합니다. 다음 단계는 <>점 교정을 작동하는 방법을 보여줍니다.
- 샘플 코드를 Arduino 보드에 업로드 한 다음 온도와 pH를 확인한 후 직렬 모니터를 엽니 다. 온도 센서를 추가 한 경우 해당 함수를 작성하고 호출해야합니다.
- 탐침을 증류수로 씻은 다음 종이로 남아있는 물방울을 흡수하십시오. pH 프로브를 7.0의 표준 버퍼 용액에 넣고 값이 안정될 때까지 부드럽게 저어줍니다.
- 값이 안정되면 첫 번째 점을 보정할 수 있습니다.
- 직렬 모니터에 enterph 명령을 입력하여 보정 모드로 들어갑니다.
4단계: DFRobot Pt 2의 세부 지침에 따라 보정
직렬 모니터에 calph 명령을 입력하여 교정을 시작합니다. 프로그램은 두 가지 표준 버퍼 솔루션 중 4.0 또는 7.0 중 어느 것이 있는지 자동으로 식별합니다. 이 단계에서는 7.0의 표준 버퍼 용액을 식별합니다.
5단계: DFRobot Pt 3의 세부 지침에 따라 보정
교정 후 직렬 모니터에 exitph 명령을 입력하여 관련 매개변수를 저장하고 교정 모드를 종료합니다. 참고: 직렬 모니터에서 exitph 명령을 입력한 후에만 관련 매개변수를 저장할 수 있습니다.
위의 단계가 끝나면 첫 번째 포인트 보정이 완료됩니다. 두 번째 포인트 교정은 아래에서 수행됩니다.
- 탐침을 증류수로 씻은 다음 종이로 남아있는 물방울을 흡수하십시오. pH 프로브를 4.0의 표준 버퍼 용액에 넣고 값이 안정될 때까지 부드럽게 저어줍니다.
- 값이 안정되면 두 번째 점을 보정할 수 있습니다. 이 단계는 첫 번째 보정 단계와 동일합니다. 구체적인 단계는 다음과 같습니다.
- 직렬 모니터에 enterph 명령을 입력하여 보정 모드로 들어갑니다.
- 직렬 모니터에 calph 명령을 입력하여 교정을 시작합니다. 프로그램은 두 가지 표준 버퍼 용액 중 어느 것이 존재하는지 자동으로 식별합니다 : 4.0 및 7.0 이 단계에서는 4.0의 표준 버퍼 솔루션이 식별됩니다.
- 교정 후 직렬 모니터에 exitph 명령을 입력하여 관련 매개변수를 저장하고 교정 모드를 종료합니다. 참고: 직렬 모니터에서 exitph 명령을 입력한 후에만 관련 매개변수를 저장할 수 있습니다.
위의 단계가 끝나면 두 번째 포인트 보정이 완료됩니다.
위의 단계를 완료하면 2점 교정이 완료된 다음 센서를 실제 측정에 사용할 수 있습니다. 교정 프로세스의 관련 매개변수는 주 제어 보드의 EEPROM에 저장되었습니다.
6단계: 하드웨어 조립
시작하려면 다이어그램에 설명된 대로 모든 전선과 센서를 연결합니다. 더 높은 품질의 다이어그램을 보려면 이 단계에 첨부된 svg 파일을 다운로드하여 엽니다.
중요 사항:
· 탁도 센서의 다이어그램과 같이 케이블이 올바른 방식으로 연결되어 있는지 확인하십시오(올바르게 연결되지 않으면 센서가 작동하지 않음)!
· 저항기는 5k 옴 저항입니다.
7단계: 탁도 센서 방수 Pt. 1
다음으로 탁도 센서를 방수 처리해야 합니다. 불행히도 우리가 찾을 수 있는 유일한 Arduino 호환 탁도 센서는 잠수가 아니므로 이 프로세스를 통해 해당 문제를 해결할 수 있습니다. 완제품의 사진이 첨부되어 있습니다.
8단계: 탁도 센서 방수 Pt. 2
먼저 전선을 늘려야합니다. 탁도 센서의 전선을 절단하고 3AWG 스피커 와이어의 16피트에 납땜했습니다.
9단계: 탁도 센서 방수 Pt. 3
그 후, 납땜 연결을 보호하기 위해 열수축 튜브를 적용했습니다.
10단계: 탁도 센서 방수 Pt. 4
그런 다음 1피트 길이의 1" PVC 파이프를 가져와 PVC 시멘트를 사용하여 1-1/4인치 x 1인치 PVC 부싱에 연결합니다.
11단계: 탁도 센서 방수 Pt. 5
탁도 센서의 뒷면을 제거하고 덕트 테이프로 뒷면을 덮고 탁도 와이어를 부싱을 통과시킵니다.
12단계: 탁도 센서 방수 Pt. 6
그런 다음 탁도 센서와 부싱 모두에 PVC 시멘트를 바르십시오.
13단계: 탁도 센서 방수 Pt. 7
마지막으로 1인치 크기의 캡을 잡고 상단에 구멍을 뚫어 전선을 통과시킵니다. (필요한 경우 Dremel은 구멍의 크기를 늘릴 수 있습니다).
14단계: 탁도 센서 방수 Pt. 8
그런 다음 구멍과 전선 사이에 실런트를 바르면 방수가 됩니다. 캡에 PVC 시멘트를 바르고 부착하십시오. 탁도 센서는 이제 방수 처리되었습니다.
Step 15: Code Setup
To begin, copy and paste this code in to the Arduino IDE or download the attached file.
***************************************************
DFRobot Gravity: Analog TDS Sensor / Meter For Arduino
<https://www.dfrobot.com/wiki/index.php/Gravity:_Analog_TDS_Sensor_/_Meter_For_Arduino_SKU:_SEN0244>
Created 2017-8-22
By Jason <jason.ling@dfrobot.com@dfrobot.com>
GNU Lesser General Public License.
See <http://www.gnu.org/licenses/> for details.
All above must be included in any redistribution
/***********Notice and Trouble shooting***************
1. This code is tested on Arduino Uno and Leonardo with Arduino IDE 1.0.5 r2 and 1.8.2.
2. More details, please click this link: <https://www.dfrobot.com/wiki/index.php/Gravity:_Analog_TDS_Sensor_/_Meter_For_Arduino_SKU:_SEN0244>
****************************************************/
// also used https://www.youtube.com/watch?v=5Dp-XatLySM
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SD.h>
#include <SPI.h>
#include "DFRobot_PH.h" //added from PH Code
#include <EEPROM.h> //Added from PH Code
File myFile;
#define ONE_WIRE_BUS 7
#define TdsSensorPin A1 //verify plugged in here
#define PH_PIN A2 //
#define VREF 5.0 // analog reference voltage(Volt) of the ADC 0ther option is 3.3/5.0
#define SCOUNT 30 // sum of sample point
int analogBuffer[SCOUNT]; // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0,copyIndex = 0;
int pinCS = 53; // Pin 10 on Arduino UNO
int sensorPin = A0; //added from turbidity
float averageVoltage = 0,tdsValue = 0,temperature = 25;
float voltage,phValue;
float Celcius=0;
float Fahrenheit=0;
float volt; //added from turbidity
float ntu; //added from turbidity
DFRobot_PH ph;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup()
{
Serial.begin(115200);
ph.begin(); //added from ph
sensors.begin();
pinMode (pinCS, OUTPUT);
pinMode(TdsSensorPin,INPUT);
// SD Card Initialization
if (SD.begin())
{
Serial.println("SD card is ready to use.");
} else
{
Serial.println("SD card initialization failed");
return;
}
}
void loop()
{
volt = 0; //beginning of added from turbidity
for(int i=0; i<800; i++)
{
volt += ((float)analogRead(sensorPin)/1023)*5;
}
volt = volt/800;
volt = round_to_dp(volt,1);
if(volt < 2.8){
ntu = 1540;
}else{
ntu = -576.12*square(volt)+3393.2*volt-3443.2;
// ntu = -1120.4*square(volt)+5742.3*volt-4353.8;
} //end of added from turbidity
static unsigned long analogSampleTimepoint = millis();
if(millis()-analogSampleTimepoint > 40U) //every 40 milliseconds,read the analog value from the ADC
{
analogSampleTimepoint = millis();
analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin); //read the analog value and store into the buffer
analogBufferIndex++;
if(analogBufferIndex == SCOUNT)
analogBufferIndex = 0;
}
static unsigned long timepoint = millis(); //added from ph
if(millis()-timepoint>1000U){ //time interval added from ph
timepoint = millis(); //added from ph
voltage = analogRead(PH_PIN)/1024.0*5000; // read the voltage
phValue = ph.readPH(voltage,temperature); //added from ph
}
static unsigned long printTimepoint = millis();
if(millis()-printTimepoint > 800U)
{
printTimepoint = millis();
for(copyIndex=0;copyIndex<SCOUNT;copyIndex++)
analogBufferTemp[copyIndex]= analogBuffer[copyIndex];
averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0; // read the analog value more stable by the median filtering algorithm, and convert to voltage value
float compensationCoefficient=1.0+0.02*(temperature-25.0); //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationVolatge=averageVoltage/compensationCoefficient; //temperature compensation
tdsValue=(133.42*compensationVolatge*compensationVolatge*compensationVolatge - 255.86*compensationVolatge*compensationVolatge + 857.39*compensationVolatge)*0.5; //convert voltage value to tds value
// Serial.print("voltage:");
// Serial.print(averageVoltage,2);
//Serial.print("V ");
sensors.requestTemperatures();
Celcius=sensors.getTempCByIndex(0);
Fahrenheit=sensors.toFahrenheit(Celcius);
//Serial.print(compensationCoefficient);
//Serial.print("compensationCoefficient");
//Serial.print(temperature);
//Serial.print("temperature");
Serial.print(millis());
Serial.print("time since start in milliseconds");
Serial.print(" C ");
Serial.print(Celcius);
Serial.print(" F ");
Serial.println(Fahrenheit);
Serial.print(volt );
Serial.print(" V ");
Serial.print(ntu );
Serial.print(" NTU ");
Serial.print("pH:");
Serial.print(phValue);
Serial.print(" TDS Value:");
Serial.print(tdsValue,0);
Serial.println("ppm");
}
ph.calibration(voltage,temperature); // calibration process by Serail CMD
{
myFile = SD.open("test.txt", FILE_WRITE);
if (myFile){
myFile.print(millis());
myFile.print(",");
myFile.print(Celcius);
myFile.print(",");
myFile.print(Fahrenheit);
myFile.print(",");
myFile.print(phValue);
myFile.print(",");
myFile.print(volt);
myFile.print(",");
myFile.print(ntu);
myFile.print(",");
myFile.println(tdsValue,0);
//myFile.print(",");
myFile.close(); // close the file
}
//if the file didn't open, print an error:
else {
Serial.println("error opening test.txt");
}
} delay (300000); // use 500 for short term troubleshooting/lab testing,300000 for field testing, 300,000 milliseconds=5 minutes, 500 milliseconds=0.5 second
}
float round_to_dp( float in_value, int decimal_place ) //begin
{
float multiplier = powf( 10.0f, decimal_place );
in_value = roundf( in_value * multiplier ) / multiplier;
return in_value;
}
int getMedianNum(int bArray[], int iFilterLen)
{
int bTab[iFilterLen];
for (byte i = 0; i<iFilterLen; i++)
bTab[i] = bArray[i];
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++)
{
for (i = 0; i < iFilterLen - j - 1; i++)
{
if (bTab[i] > bTab[i + 1])
{
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0)
bTemp = bTab[(iFilterLen - 1) / 2];
else
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
return bTemp;
}
16단계: 현장 배포 Pt. 1
이제 모든 하드웨어가 작동하므로 어셈블리를 완료하고 현장에 배포할 차례입니다. 상자 측면에 와이어를 끼우기 위해 두 개의 구멍을 뚫은 다음 구멍 주위에 플렉스 테이프를 적용하여 물을 차단합니다. 이 경우 시스템이 물에 얼마나 노출되는지에 따라 실란트를 사용할 수도 있습니다.
17단계: 현장 배포 Pt. 2
필요한 모든 하드웨어를 상자에 넣으면 시스템이 다음과 같이 보일 것입니다.
18단계: 현장 배포 Pt. 3
위치에 따라 다양한 배포 옵션이 있습니다. 한 배치의 경우 상자를 지퍼로 묶은 아래에 도관이 있는 다리를 발견했습니다. 다른 배포의 경우 브리지 지원에 지퍼를 묶었습니다. 또한 두 번째 배치에서는 추가적인 안정성을 위해 센서 프로브를 개울 바닥으로 몰아넣은 말뚝에 지퍼로 묶었습니다. 20,000Mah 배터리로 한 번에 6일의 배터리 수명을 지속적으로 얻었습니다.
배포하기 직전에 SD 카드를 다시 포맷하고 코드의 delay 함수가 배포 위치에 따라 적절한 시간으로 설정되어 있는지 확인합니다. (현장 테스트에는 300,000밀리초, 실험실 테스트에는 500밀리초를 사용합니다.) 그런 다음 sd 카드를 sd 카드 어댑터에 삽입하고 arduino를 완전히 충전된 배터리에 연결합니다. 이제 arduino가 지정된 주파수에서 측정을 시작하고 센서를 물에 삽입 할 준비가되었습니다.
19단계: 데이터 검색 Pt. 1
Arduino에서 SD 카드를 검색하면 해당 데이터를 Excel 스프레드 시트로 변환하는 것이 비교적 쉬운 프로세스입니다. Arduino는 검색한 데이터를 각 변수를 쉼표로 구분하고 각 읽기를 새 줄에 있는 일반 텍스트 파일에 저장하도록 프로그래밍되어 있습니다.
변수는 <밀리초 단위의 시간>, <C>의 온도, <F>의 온도, <pH>, <탁도 측정기의 전압>, <NTU의 탁도> 및 <TDS(PPM)입니다>
20단계: 데이터 검색 Pt. 2
새 Excel 시트를 열고 파일 > 가져 오기로 이동 한 다음 텍스트 파일을 클릭하십시오.
21단계: 데이터 검색 Pt. 3
구분 기호로 구분된 항목이 선택되어 있는지 확인하고 다음을 클릭합니다.
22단계: 데이터 검색 Pt. 4
쉼표가 선택된 유일한 구분 기호인지 확인하고 다음을 클릭합니다.
23단계: 데이터 검색 Pt. 5
모든 열에 대해 "일반" 형식이 선택되어 있는지 확인한 다음 마침을 클릭합니다.
24단계: 데이터 검색 Pt. 6
데이터를 가져올 위치를 선택하고 확인을 클릭합니다. 그런 다음 연구의 의도된 응용 프로그램에 따라 데이터 형식을 지정/플로팅하는 것이 좋습니다.
25단계: 문제 해결 Pt. 1
이와 같은 프로젝트에서는 몇 가지 기술적 인 문제가 발생할 수 있습니다. 다음 포인터를 사용하면 개발 프로세스 중에 발생한 몇 가지 일반적인 오류를 해결할 수 있습니다.
-문제에 관계없이 문제에 대해 걱정하기 전에 Arduino와 컴퓨터를 모두 다시 시작하십시오.
-이상한 값을 얻는 경우 모든 것이 완전히 연결되어 있는지 확인하십시오!
-다른 모든 방법이 실패하고 오류 메시지가 표시되거나 이전에 본 적이없는 문제가 발생하면 오류 메시지 나 증상을 Google에 게시하는 것이 좋습니다.
26단계: 문제 해결 Pt. 2
때때로 Arduino를 실행할 때 다음 오류가 발생합니다.
27단계: 문제 해결 Pt. 3
이 오류가 발생하면 도구 -> 포트로 이동하여 usbmodem 포트를 선택하십시오. 이 오류는 컴퓨터가 연결되어 있을 때 Arduino를 자동으로 감지하지 못하는 경우에 발생합니다. Arduino가 연결된 포트를 선택하면 이 문제가 해결됩니다.
'아두이노' 카테고리의 다른 글
손 제스처 제어: 물리적 및 디지털의 움직임(원격 조작) (1) | 2023.10.18 |
---|---|
게이머를 위한 궁극의 모기채 모드: 킬 카운터, 사운드, 충전식 배터리를 추가 (1) | 2023.05.21 |
Arduino Nano를 사용하여 이진수-십진수 변환기 만들기 (0) | 2023.05.05 |
8×32 MAX7219 도트 매트릭스 LED 디스플레이(아두이노 포함) (0) | 2023.04.14 |
팅커캐드 회로와 아두이노를 사용한 가위바위보 (0) | 2023.03.06 |