', { cookie_domain: 'auto', cookie_flags: 'max-age=0;domain=.tistory.com', cookie_expires: 7 * 24 * 60 * 60 // 7 days, in seconds }); '분류 전체보기' 카테고리의 글 목록 (2 Page) :: MakerLee's Workspace
728x90

기존 설계의 문제는 힘이 가해졌을 때 이스케이프 휠에 팰릿이 잠겨서 움직이지 않기 때문에 밸런스 휠을 손으로 한번 흔들어 줘야 움직임이 시작된다는 것이었습니다. 

 

 

 

그러던 중 팔로우하고 있던 일본 작가분의 작품을 보게 되었는데요

https://x.com/BellTreeNursing

이 작품을 출력해서 움직여 보니 제것과 달리 힘만 주면 바로 작동을 하더군요

 

 

 

 

 

원인을 찾다 보니 펠릿 쥬얼의 각도가 문제였습니다. 

기계식 시계에서는 진짜 쥬얼을 쓰지만 제 물건은 그냥 플라스틱 덩어리일 뿐이라 마찰계수가 달라서 작동을 하지 않는 거였습니다. 

각도를 수정해 가며 여러 번 출력해 가며 부드럽게 움직이는 각도를 찾았습니다. 

 

 

 

 

 

밸런스 휠과 스프링도 약간 수정했습니다. 

 

 

 

 

https://www.youtube.com/watch?v=SOrmzYx_KAM

이게 그 결과입니다. 

 

 

 

 

 

 

탈진기의 중심 부분은 어느정도 완성이 된 것 같아 주변 기어와 태엽을 추가하려고 계속 작업중입니다. 

주변에 기어와 축이 많이 추가되다 보니 축의 길이를 정밀하게 절단해야 할 일이 많더군요.

 

 

 

 

 

3d 프린트 뚜르비옹을 만들었던 유튜브의 @mechanistic3d 의 작업중 좋아 보이는 것이 있어 따라했습니다. 

 

https://www.youtube.com/watch?v=iwKXmwjGt9U

 

 

 

절단작업을 해 보니 훨씬 편리하긴 한데 좀 더 정밀한 작업을 위해선 수정할 부분이 있네요. 

 

 

 

 

 

 

728x90

'Making > 탈진기 설계와 제작' 카테고리의 다른 글

두번째 설계한 탈진기 테스트  (0) 2024.04.16
새 탈진기 설계와 조정.  (0) 2024.04.04
탈진기 첫 테스트.  (0) 2024.03.01
포크와 롤러 설계  (0) 2024.02.25
팔레트 설계  (0) 2024.02.25
728x90

구매한 지는 꽤 되었는데 리뷰가 늦었네요. 

 

올해 초 E3D 사의 Rapidchange Revo 가 Bigtreetech 사와의 협업으로 뱀부랩용 제품으로 출시되었습니다. 

 

 

제가 최근에 탈진기 등의 작업을 하다 보니 정밀한 출력이 필요했고 그에 따라 0.2mm 노즐 등을 바꿔 사용하곤 했습니다. 

당연하게도 노즐 교환의 귀찮음이 심각하게 다가와서 이 제품이 눈에 들어왔고요. 

저는 3월 말 쯤 구입하여 써보게 되었는데요. 

 

 

 

 

문제는 Revo 노즐은 0.4mm / 0.6mm 는 똑같이 있으면서 미세 노즐은 0.25mm / 0.15mm 라는 이상한 규격을 만들어서 사용한다는 것이었습니다. 

그리고 이 노즐은 뱀부랩 스튜디오에서 지원하지 않습니다. 

 

바쁜 일이 많아서 이걸 어떻게 하질 못하고 그냥 0.4 / 0.6 노즐만 사용하고 있었는데 이것만 해도 상당히 편하더라고요.

그래서 P1S 용까지 추가구매를 했습니다. 

 

 

 

최근에 좀 여유가 생겨서 다시 검색을 해 보니 다행히 OrcaSlicer에서 편집이 가능하다고 하더라고요. 

Makerworld 에서 'revo profile'로 검색을 해 보면 anselor 라는 유저가 만들어 놓은 프로파일이 있어 고생을 많이 덜었습니다. 

 

 

다만 Orcaslicer 최신 버전을 사용해 보니 뱀부랩 스튜디오처럼 노즐 프로파일과 저장된 노즐이 다르다며 출력이 불가능하더군요. 

오르카슬라이서 2.1.0버전을 써야만 출력을 할 수 있습니다. 

 

 

 

benchy를 30% 축소해서 0.15mm 노즐로 출력해 봤습니다.

깔끔하게 잘 나오는 편입니다만 진동에 의한 물결무늬가 좀 더 잘 보이긴 합니다. 

728x90

'Review' 카테고리의 다른 글

엘가토 스트림덱  (0) 2024.11.20
BTT PANDA LUX - 뱀부랩 X1C/P1S용 LED 라이트 바 리뷰  (0) 2024.05.08
키크론 K10 pro 구매.  (0) 2023.06.28
FNIRSI-FNB58 USB 테스터 리뷰  (0) 2023.01.11
폴리튠 클립 튜너 간단리뷰.  (0) 2022.12.25
728x90

 


뱀부랩 카페에서 알게 된 곳인데 타오바오 필라멘트 셀러 중에 R3D 라는 곳이 있습니다. 

그런데 불량재고를 16개씩 묶어서 굉장히 저렴하게 판매한다더군요. 

구매한 분들 리뷰를 보니 퀄리티도 나쁘지 않고요. 

 

 

 

 

 

 

링크 : https://detail.tmall.com/item.htm?id=742776751219

지금은 이미 재고가 많이 나가 많이 줄었습니다만 16롤 묶음판매는 여전히 판매는 하고 있습니다. 

사진의 마우스 커서가 위치한 물품이 그것입니다. 

색깔과 종류를 불문하고 PLA/PETG 를 섞어서 16롤을 320위안(=61000원) 에 판매합니다. 

 

사실 지난번에 한번 구매를 해 봤는데, PLA/PETG 반반에 흰색부터 핑크색에 투명에 목분PLA도 하나 섞여있고 진짜 랜덤입니다. 

진공은 풀려있는 경우가 좀 있는데 그래도 퀄리티는 대부분 정상이더군요. 

저같이 PLA/PETG 돌아가면서 사용하는데다 색은 별로 중요하지 않고 사용량이 많은 사람에게는 정말 좋더군요. 

 

 

 

 

 

 

 

 

그래서 한번 더 샀다는 이야기입니다. 

방엔 둘 데가 없어서 트렁크에 실어뒀습니다. 

 

 

 

728x90
728x90

OLED 통합한다고 해놓고 한참 걸렸네요.

부품 수급과 드라이버 회로 테스트하고 이것저것 하다보니 많이 늦었습니다. 

 

처음 만든 회로는 실패하는 바람에 다시 한번 관련 자료를 찾아 회로를 수정하고 부품을 수급하고 테스트 과정을 거쳤습니다. 

관련 포스팅 : https://pashiran.tistory.com/1375

 

 

 

 

 

 

 

 

 

 

 

 

실크스크린을 이용해 납을 올리고 핀셋으로 하나하나 부품을 올려줍니다. 

 

 

 

 

 

저는 오븐이 아니라 핫 플레이트를 사용하는지라 앞면에 부품이 납땜된 후에 뒷면에 부품을 올리기 어렵습니다. 

그래서 급하게 솔리드웍스에서 지그 설계를 하고 출력해 사용했습니다. 

 

 

 

 

 

 

이후 뒷면은 히팅 건으로 가열해서 마무리를 해 줍니다. 

 

 

 

 

 

 

아두이노 부트로더를 올려줍니다. 

 

 

 

 

아두이노 나노를 베이스로 삼았기 때문에 위와 같이 세팅하고 부트로더를 올려주면 됩니다.

저는 아두이노에 arduino as isp 스케치를 올려 프로그래머로 사용하기에 [Programmer :"Arduino as ISP"] 를 선택했습니다. 

 

 

 

 

부트로더가 올라간 보드에 간단하게 blink 스케치를 약간 편집해 넣었습니다.

업로드해서 테스트해보면 잘 되는 것을 볼 수 있습니다. 

 

 

 

 

U8glib 예제를 넣어봤습니다. OLED도 잘 되는군요. 

점검해 보니

1. USB 커넥터를 Bottom으로 보내야 겠고

2. Reset 스위치를 제거했더니 쓰기가 불편해서 다시 넣어야 할 것 같습니다. 

3. OLED 위치도 약간 조정이 필요하네요.

 

 

 

[진짜진짜_마지막_최종] 수정 버전의 PCB를 주문했습니다. 

주문한 PCB가 올 때까지는 기존 보드를 사용하면서 스케치를 수정하려 합니다. 

728x90
728x90

여느 때처럼 타오바오 중고물품 순회를 하다가 이런 걸 발견했습니다. 

 

 

 

 

 

도착한 물건을 조립해 보니 괜찮아 보입니다. 

태양광 패널의 고정이 확실치 않아 바람이 세게 불면 돌아갈 것 같긴 한데요. 

 

 

 

 

 

 

 

볼트 너트가 포함이긴 한데 와셔를 추가하고 렌치볼트를 쓰는 등 갖고 있던 재료로 업그레이드를 했습니다. 

 

 

 

 

 

 

 

배터리는 무려 10Ah.

충방전도 잘 됩니다. 

문제는 리튬인산철 배터리란 거죠.

 

 

 

 

 

 

 

제가 스무개나 만들어 놓은 충방전 회로는 리튬이온 용인데 말이죠

 

 

 

 

 

 

이 문제는 일단 넘어가고

분해해 보니 방수 패킹도 잘 되어있고 공간도 나쁘지 않아 보입니다. 

LED 패널은 필요없으니 제거합니다. 

 

 

 

 

 

 

 

태양광 패널도 10W 라 나쁘지 않아 보이네요

 

 

 

 

 

 

 

 

안테나 케이블을 상단에 설치하려 구멍을 뚫었는데 뚜껑을 닫아보니 높이가 살짝 높아서 안 닫히는군요. 

하단으로 옮겼습니다. 

 

 

 

 

 

 

 

배터리를 넣고 위쪽에 회로를 넣으면 딱 맞을 것 같습니다. 

728x90
728x90

노드를 하나 외부에 설치할 계획을 세우고 나니 더욱 많은 문제가 있습니다. 

 

1. 기술적 문제

-노드는 태양광으로 자체적으로 돌아가야 합니다. 

태양광 패널과 충전 시스템, 배터리로 구동되며 방수 케이스에 넣어져 환경으로부터 보호되어야 하죠. 

기술적 문제들은 스스로 해결할 수 있긴 하지만, 각각에 대해 추가 비용이 들어간다는 점은 상당히 부담이 됩니다. 

 

2. 환경적 문제

-태양광 패널은 그림자가 지지 않는 노출된 곳에 설치되어야 합니다. 

개인이 접근할 수 있는 곳에서 이런 위치를 찾기는 쉽지 않습니다. 

-또한 전파의 특성상 가능한한 높은 곳에 설치되어야 합니다. 

 

3. 법적 문제

위와 같은 사항을 따르려 하면 고층 빌딩을 여러 개 갖고 있는 엄청난 건물주가 아닌 이상, 

서울의 야산 등에서 적당한 설치 위치를 찾아야 합니다. - 다른 방법이 있다면 알려주세요

공유지에 개인 물건을 설치하는 것은 당연히 법적 문제가 따릅니다. 

 

동네 야산의 휴게 위치 등에는 동네 주민들의 물건들도 놓여진 경우가 많아 크게 문제가 되진 않을 것 같습니다만, 

엄밀하게 따지자면 경범죄에 속할 수밖에 없는 게 사실이겠죠.

 

허가를 얻는 것도 방법입니다만, 사업자도 아니고 개인이 이런 물건을 설치하겠다고 하면 과연 허가가 날까요?

 

4. 기타 문제

설치 위치를 시뮬레이션 해 보면 손이 닿는 높이(1.5m정도) 에 설치하는 것은 시각적으로 문제가 될 수 있습니다. 

적어도 2~2.5m의 높이에 설치해야 위화감이 없을 것 같습니다. 

결론적으로 동네 야산을 사다리까지 짊어지고 올라가야 하며, 사다리 구매 비용은 별도라는 문제가 있습니다. 

 

 

728x90
728x90

강아지 산책하는 김에 여기저기 새가 보이면 기록을 해보려 합니다. 

아무래도 산책길 특성상 참새,까치,직박구리,비둘기가 99%이긴 한데요

그래도 운 좋으면 하나씩 늘릴 수 있지 않을까 합니다. 

 

직박구리

 

 

 

 

 

까치. 

요즘은 어린 새들이 많아서 경계심이 적어 근처까지 막 오고 그러네요

 

 

 

 

 

 

한강 산책중 박새랑 참새들이 계속 왔다갔다 하며 시끄럽게 굴길래 봤더니 스프링클러 틀어놓은 곳에서 샤워하느라 정신없더군요. 

 

 

 

 

 

청둥오리 수컷. 암컷과 새끼들도 있었는데 카메라 맞추는사이 사각으로 사라졌네요.

 

 

 

 

 

 

 

 

 

새끼 까마귀인가? 했던 대륙검은지빠귀

저번에도 한번 봤었는데 사진을 못 찍었고 이번에는 사진을 찍어 도감에서 자세히 찾아봤습니다. . 

몸 전체가 검은색이고 부리와 눈가가 노란색. 직박구리보다 약간 큰 정도에 몸은 더 통통. 

낙엽을 파헤치며 지렁이 찾아 먹는중이었습니다. 

 

 

 

 

 

그리고 안타까운 사건 2가지.

새끼까치 한마리 죽어가는 것 발견. 

그동안 몇번 까치를 구조한 경험은 있으나 첫 발견시부터 살 수 있을지 모르겠을 정도로 매우 약한 상태였는데요. 

물과 음식을 조금씩 급여했으나 몇시간 뒤 사망했습니다. 

 

 

 

 

 

 

도로 인근 분수대. 사람이 거의 찾지 않는 곳인데 이상하게 물까치들이 시끄럽게 날아다니더군요. 

분수를 한바퀴 돌다 보니 물까치가 한마리 죽어서 떠있었고요. 

아마도 분수대 위에 앉아 있다가 분수의 갑작스런 분출에 맞아서 물에 빠진 뒤 나오지 못한 것으로 추정합니다. 

건져서 물까치들이 **장례식을 치를 수 있도록 한쪽에 두고 나왔습니다. 

 

**새들도 죽은 동료가 있으면 주변 여러 마리의 새들이 한참동안 추모하듯 시끄럽게 모여서 울곤 합니다. 

 

 

 

 

일단 쌍안경에 핸드폰 카메라 맞추는 건 어떻게 좀 개선을 해야 할 것 같네요. 

728x90
728x90

0.96" 와 같이 구매했던 1.3" OLED입니다. 

첫번째 것이 구동했으니 이것도 당연히 될 것 같지만 그래도 테스트를 하지 않고 넘기기엔 뭔가 찜찜해서 작업을 합니다. 

 

이제는 노안이 심해져 현미경의 도움이 필수에요. 

 

 

 

 

 

30핀을 일일이 하나하나 선을 까서 납땜합니다.  

 

 

 

 

 

 

 

 

 

0.96" 와 1.3" 두개 했더니 한나절이 후딱 지나가네요

좌측 0.96" 는 사실 다른 곳에서 떨이로 산거라 드라이빙 칩이 뭔지 모릅니다. 

그냥 SH1106 기준으로 납땜해서 동작시켜 보고 안되면 버릴 생각입니다. 

 

 

 

주변 회로를 연결하고 납땜을 해 봤는데 동작을 안 하네요.

주말내내 이 작업만 했는데 뭔가 잘못된 부분 찾는것도 힘들어 그냥 기존 OLED 모듈을 하나 잡았습니다. 

 

뒷면의 OLED 연결을 떼어냈습니다. 

 

 

 

 

 

그리고 1.3" 모듈을 붙여 다시 납땜했더니 동작합니다. 

이 작업은 이걸로 마무리를 하려 합니다. 

이제 회로 구성해서 스탑된지 반년이 넘어가는 디스펜서 작업을 계속 해야겠습니다. 

 

728x90
728x90

예전부터 회로를 제작할 때 별도의 OLED 모듈이 아니라 온보드 형태로 제작하고 싶은 경우가 있었습니다. 

자료를 찾기가 힘들어서 미뤄왔는데 SSD1306 드라이버를 쓰는 OLED의 경우 비교적 주변 회로가 간단한 듯 하여 도전해보게 되었습니다. 

 

 

 

 

 

 

 

요즘은 타오바오 직구를 많이 합니다.

아무래도 살 물건이 많다보니 알리보다 조금이라도 저렴해지고 직배송도 가능해서 배송도 그리 늦지 않네요.

 

 

 

 

 

셀러가 보내준 데이터를 참조해 회로를 만듭니다. 

비교적 간단하죠?

원래는 SH1106 OLED 를 구매했다가 보다 주변 회로가 간단한 물건을 찾아 SSD1306으로 변경하게 되었습니다. 

 

 

 

 

납땜을 하고 U8G2 라이브러리 예제를 올려봅니다. 

 

 

 

 

 

 

 

잘 되는군요. 

바쁘다 보니 취미 프로젝트 할 시간 내기가 힘드네요. 

 

 

728x90
728x90

아무래도 제 개인의 코딩 능력을 많이 벗어난 데이터셋 정리 등이 필요하다 보니 ChatGPT에게 도움을 청했습니다. 

한동안 이녀석과 질답을 주고받으며 코드를 많이 쌓긴 했습니다

하지만 대화가 길어지면 점점 버벅대고 결과가 산으로 가기도 하네요.

 

그래서 일단 단계별로 진행하고 코드 내용을 따로 기록하기로 합니다.

 

#include <WiFi.h>
#include <HTTPClient.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "GetLocate.h"
#include <Arduino_JSON.h>

// Wi-Fi 설정
const char* ssid = "ssid";
const char* password = "password";

const char* apiKey = "API_KEY";
const long utcOffsetInSeconds = 3600 * 9; // 한국 표준시 (UTC+9)

// 타임서버 설정
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

// 업데이트 간격 (예: 10분)
unsigned long updateInterval = 600000;
unsigned long previousMillis = 0;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // 타임서버 연결
  timeClient.begin();
  timeClient.update();

  // 위치 정보 가져오기
  Location loc = getLocation();
  Serial.print("Location - Country: "); Serial.print(loc.country);
  Serial.print(", Region: "); Serial.print(loc.regionName);
  Serial.print(", City: "); Serial.println(loc.city);

  // 초기 날씨 정보 업데이트
  getWeatherUpdate();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= updateInterval) {
    previousMillis = currentMillis;

    // 타임서버 업데이트
    timeClient.update();

    // 현재 시간 출력
    Serial.print("Current time: ");
    Serial.println(timeClient.getFormattedTime());

    // 날씨 정보 업데이트
    getWeatherUpdate();
  }
}

// 날씨 정보를 업데이트하는 함수
void getWeatherUpdate() {
  Location loc = getLocation();
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    String weatherURL = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst";
    weatherURL += "?serviceKey=" + String(apiKey);
    weatherURL += "&numOfRows=60&pageNo=1&base_date=" + getCurrentDate();
    weatherURL += "&base_time=0630&nx=" + String(loc.nx) + "&ny=" + String(loc.ny);
    weatherURL += "&dataType=JSON"; // JSON 형식으로 요청

    http.begin(weatherURL);
    int httpCode = http.GET();

    if (httpCode > 0) {
      String payload = http.getString();
      Serial.println("Weather Data: ");
      
      // 특수문자 및 따옴표 제거 및 줄바꿈 출력
      String formattedPayload = formatPayload(payload);
      Serial.println(formattedPayload);
    } else {
      Serial.print("Error on HTTP request: ");
      Serial.println(httpCode);
    }
    http.end();
  }
}

// 날씨 API의 응답 데이터를 포맷하는 함수
// 이 함수는 JSON 응답에서 불필요한 특수문자와 따옴표를 제거하고,
// 쉼표를 기준으로 줄바꿈을 추가하여 가독성을 높인다.
String formatPayload(String payload) {
  payload.replace("{", ""); // '{' 제거
  payload.replace("}", ""); // '}' 제거
  payload.replace("[", ""); // '[' 제거
  payload.replace("]", ""); // ']' 제거
  payload.replace("(", ""); // '(' 제거
  payload.replace(")", ""); // ')' 제거
  payload.replace("\"", ""); // '"' 제거
  payload.replace(",", ",\n"); // ',' 뒤에 줄바꿈 추가
  return payload;
}

// 현재 날짜를 YYYYMMDD 형식으로 반환하는 함수
// 이 함수는 NTPClient를 사용하여 현재 시간을 가져오고,
// tm 구조체를 사용하여 로컬 시간으로 변환한 후, strftime 함수를 사용하여
// 날짜를 문자열 형식으로 반환한다.
String getCurrentDate() {
  time_t now = timeClient.getEpochTime(); // 현재 epoch 시간 가져오기
  struct tm* timeinfo = localtime(&now); // epoch 시간을 로컬 시간으로 변환
  char buffer[11]; // 날짜를 저장할 버퍼
  strftime(buffer, sizeof(buffer), "%Y%m%d", timeinfo); // 날짜를 YYYYMMDD 형식으로 포맷팅
  return String(buffer); // 문자열로 반환
}

이게 메인 코드이고요

 

 

 

#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

// Grid 구조체 정의
struct Grid {
  int x;
  int y;
};

// dfs_xy_conv 함수 선언
Grid dfs_xy_conv(const char* code, double v1, double v2);

// Location 구조체 정의
struct Location {
  String country;
  String regionName;
  String city;
  int nx;
  int ny;
};

Location getLocation() {
  HTTPClient http;
  Location loc;
  http.begin("http://ip-api.com/json");
  int httpCode = http.GET();

  if (httpCode > 0) {
    String payload = http.getString();
    JSONVar doc = JSON.parse(payload);

    if (JSON.typeof(doc) != "undefined" && strcmp((const char*)doc["status"], "success") == 0) {
      loc.country = (const char*)doc["country"];
      loc.regionName = (const char*)doc["regionName"];
      loc.city = (const char*)doc["city"];
      float lat = (double)doc["lat"];
      float lon = (double)doc["lon"];

      // 좌표를 NX, NY로 변환
      auto grid = dfs_xy_conv("toXY", lat, lon);
      loc.nx = grid.x;
      loc.ny = grid.y;
    } else {
      Serial.println("Failed to parse location data");
    }
  } else {
    Serial.println("Failed to retrieve location data");
  }
  http.end();
  return loc;
}

// dfs_xy_conv 함수 정의
Grid dfs_xy_conv(const char* code, double v1, double v2) {
  const double RE = 6371.00877;
  const double GRID = 5.0;
  const double SLAT1 = 30.0;
  const double SLAT2 = 60.0;
  const double OLON = 126.0;
  const double OLAT = 38.0;
  const double XO = 43;
  const double YO = 136;

  const double DEGRAD = M_PI / 180.0;
  const double RADDEG = 180.0 / M_PI;

  double re = RE / GRID;
  double slat1 = SLAT1 * DEGRAD;
  double slat2 = SLAT2 * DEGRAD;
  double olon = OLON * DEGRAD;
  double olat = OLAT * DEGRAD;

  double sn = tan(M_PI * 0.25 + slat2 * 0.5) / tan(M_PI * 0.25 + slat1 * 0.5);
  sn = log(cos(slat1) / cos(slat2)) / log(sn);
  double sf = tan(M_PI * 0.25 + slat1 * 0.5);
  sf = pow(sf, sn) * cos(slat1) / sn;
  double ro = tan(M_PI * 0.25 + olat * 0.5);
  ro = re * sf / pow(ro, sn);

  Grid rs = {0, 0};
  if (strcmp(code, "toXY") == 0) {
    double ra = tan(M_PI * 0.25 + (v1) * DEGRAD * 0.5);
    ra = re * sf / pow(ra, sn);
    double theta = v2 * DEGRAD - olon;
    if (theta > M_PI) theta -= 2.0 * M_PI;
    if (theta < -M_PI) theta += 2.0 * M_PI;
    theta *= sn;
    rs.x = floor(ra * sin(theta) + XO + 0.5);
    rs.y = floor(ro - ra * cos(theta) + YO + 0.5);
  }
  return rs;
}

 

이건 GetLocate.h 코드입니다.

Wifi 주소를 추적해서 현재 위치를 파악하고, 그 위치정보를 기상청 API에서 요구하는 그리드 격자정보로 변환합니다.
https://gist.github.com/fronteer-kr/14d7f779d52a21ac2f16
의 코드를 참조하도록 했습니다. 

 

 

이 코드를 실행한 결과는 다음과 같습니다.

Connecting to WiFi...
Connecting to WiFi...
Connected to WiFi
Location - Country: South Korea, Region: Gyeonggi-do, City: Seongnam-si
Weather Data: 
response:header:resultCode:00,
resultMsg:NORMAL_SERVICE,
body:dataType:JSON,
items:item:baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1000,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1000,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0700,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0800,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0900,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1000,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1100,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1200,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0700,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0800,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1100,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1200,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0700,
fcstValue:17,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0800,
fcstValue:19,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0900,
fcstValue:21,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1000,
fcstValue:23,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1100,
fcstValue:24,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1200,
fcstValue:25,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0700,
fcstValue:75,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0800,
fcstValue:70,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0900,
fcstValue:65,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1000,
fcstValue:60,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1100,
fcstValue:50,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1200,
fcstValue:45,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0700,
fcstValue:-0.8,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0800,
fcstValue:-0.4,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0.5,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1100,
fcstValue:2.2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1200,
fcstValue:2.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0.5,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0.9,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1.1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1.1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0.8,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0700,
fcstValue:118,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0800,
fcstValue:151,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0900,
fcstValue:204,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1000,
fcstValue:236,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1100,
fcstValue:250,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1200,
fcstValue:257,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0700,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0800,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1000,
fcstValue:2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1100,
fcstValue:2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1200,
fcstValue:3,
nx:62,
ny:122,
pageNo:1,
numOfRows:60,
totalCount:60

 

현재 위치정보는 성남시로 나오는데요.

핸드폰 핫스팟으로 접속했더니 현재 위치정보가 좀 많이 어긋나네요. 

이건 급한게 아니니 천천히 수정하려고 합니다. 

 

 

항목설명

baseDate 예보 발표 날짜 (YYYYMMDD 형식)
baseTime 예보 발표 시각 (HHMM 형식)
category 예보 항목 코드
fcstDate 예보 날짜 (YYYYMMDD 형식)
fcstTime 예보 시각 (HHMM 형식)
fcstValue 예보 값
nx 예보 지점의 X 좌표
ny 예보 지점의 Y 좌표

 

코드 (category)설명

LGT 낙뢰 가능성
PTY 강수 형태
RN1 1시간 강수량
SKY 하늘 상태
T1H 1시간 기온
REH 습도
UUU 동서바람성분
VVV 남북바람성분
VEC 풍향
WSD 풍속

 

 

모든 코드와 자료정리는 ChatGPT가 했습니다. 
다음은 이 데이터를 간결하게 정리해서 저장하는 부분을 추가하려고 합니다. 

728x90
728x90

*아두이노 기상청 등으로 검색이 많이 들어오는데, 잘 정리된 블로그 링크를 걸어놓겠습니다. 

관련 프로젝트를 하시는 분들은 아래 링크를 참조하세요. 

https://postpop.tistory.com/86

 

아두이노 - ESP01 모듈, 기상청 / 오픈웨더맵 API 날씨 정보 받기

아두이노에서 날씨 정보를 받기 위해서는 기상 서비스 사이트의 API KEY가 있어야 합니다. 한국의 경우 공공데이터포털, 외국 사이트는 OpenWeatherMap에서 회원가입한 뒤 KEY를 할당받아 코딩해 주어

postpop.tistory.com

 

 

 

날씨 예보를 받는 서비스는 오픈웨더맵 외에 '공공 데이터 포털'을 들 수 있습니다. 

이곳에서는 단기예보와 중기예보, 미세먼지 데이터 등 한국 상황에 훨씬 더 잘 맞는 데이터들을 얻을 수 있죠. 

https://www.data.go.kr/

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

 

 

 

 

공공데이터를 이용하려면 일단 인증키를 발급받아야 하는데요

메뉴를 조금만 찾아보시면 쉽게 인증키 신규발급 메뉴를 찾으실 수 있습니다.

발급받은 인증키는 마이페이지 메뉴에서 바로 확인 가능합니다. 

 

 

 

그리고 나서 이제 원하는 API 사용신청을 하면 됩니다. 

보통 간단한 날씨예보는 "단기예보" 를 확인하면 오늘의 시간별 날씨와 3일간의 날씨를 확인할 수 있습니다. 

[데이터찾기] - [데이터목록] 을 클릭하고 "단기예보"를 입력해 검색합니다. 

 

 

 

 

 

 

 

그리고 창을 약간 내려서 오픈API 탭을 클릭하면 "기상청_단기예보 ((구)_동네예보) 조회서비스" 가 나옵니다. 

"활용신청" 버튼을 클릭합니다. 

 

신청 메뉴에는 사용 목적 등을 간단하게 적으면 되며, 신청 즉시 사용이 가능합니다. 

 

 

 

개발용 계정은 즉시 승인되어 바로 사용할 수 있습니다.

단기예보는 하루에 10000건, 대기오염정보는 500건 제한이 있긴 한데 개인용으로 쓰기엔 전혀 문제없는 용량이죠.

 

 

 

 

 

자세한 활용방법을 알고 싶으면 조회서비스를 들어가서 하단의 .zip 파일을 다운받으면 내용을 확인할 수 있습니다. 

 

 

 

 

 

 

728x90
728x90

제가 뭐 주변지역으로 노드를 쫙 깔거나 그런 것 까지는 생각을 안했지만요. 

테스트를 하건 뭐건 적어도 주변에 고정 노드는 하나 있어야 뭔가를 하기 쉽겠더군요.

설치 위치가 고민인데 서울 도심에서 설치하는 것도 난관이고 무엇보다 자체전원을 갖춰야 한다는 것도 문제입니다.




https://austinmesh.org/#building-a-solar-powered-repeater

 

Austin Mesh

Austin Mesh is a community group working to build a mesh network of solar-powered meshtastic radios in Austin. This network acts like a city-wide text messaging system, allowing people to communicate publicly or privately with anyone on the network. All of

austinmesh.org

검색해 보니 외국의 리피터 설치 경험담이 있는데요.

텍사스 오스틴(위도 30.2672N) 에서 소형 5W 급 태양전지 등을 사용했다가 몇달만에 자꾸 노드가 죽어 몇번씩 장비를 교체한 내용들이 있습니다. 

 

이것저것 고민해보니 소형 태양광 전지를 쓰더라도 장비만 그럭저럭 가동되면 테스트는 가능할 것 같습니다. 

RAK wisblock 장비가 그나마 전력 소모가 적다고 하니 그 장비를 기준으로 할까 하는데요.

검색해 보니 이것도 태양광이 적어 전압이 불안정하면 애매하게 죽어서 복구가 안 되는 경우가 있는 듯 하더군요. 

 

그렇다면 애초에 저전압 컷 기능이 있는 태양광 충전기는 없나? 하고 또 알아보게 되었습니다.

그리고 우리의 멋진 GreatScott 형님의 과거 동영상을 보게 되었죠.
https://www.youtube.com/watch?v=kEttqWJrdww

 


내용을 몇번씩 검토해 봤는데 원하는 기능을 완벽하게 구현해 놓아 그대로 써도 될 것 같습니다.

과충전 / 과방전 / 과전류 보호에 5V 출력 부스트, MPPT까지 모두 돌아가는 충전 및 보호회로입니다.

 

 

 

 

 

다행히 회로도를 제공해 주셔서 그대로 쓰면 될 것 같지만

 

 

 

 

 

 

좀 깔끔하게 정리를 했고요. 

BOM 을 뽑아서 LCSC에 넘겨보니 재고가 없는 부품들이 있어서 대체 부품으로 다시 넣었습니다. 

 

 

 

 

 

 

 

 

 

재고없는 제품, 재고 모자란 제품 등등이 섞여서 BOM 정리하고 주문하는 게 PCB 제작보다 오래 걸렸네요

 

 

 

 

 

부품이 도착하고 납땜을 했습니다. 

일단 배터리 입력에 18650을 하나 연결하고 출력단 전압을 체크해보니 승압이 잘 되고 있습니다. 

이후 배터리 대신 파워 서플라이를 연결하고 전압을 오르락 내리락 해보니 2.5V에서 전압이 컷오프 되는 것을 볼 수 있었습니다. 

다만 다시 전압을 올리면 출력이 되지 않고 스위치를 off/on 해야 다시 출력이 나오더군요. 

만약 배터리가 위험전압까지 떨어진다면 수동으로 스위치를 껐다 켜야만 할 것 같습니다. 

 

 

 

아직 R8, R9은 납땜하지 않았는데 이는 태양전지 MPPT 전압에 맞춰야 하기 때문입니다. 
위의 GreatScott 영상에서는 9:20초쯤부터 나옵니다. 

전압분배를 이용해서 MPPT 핀에 1.205V 가 입력되도록 하면 된다는군요

 

 

태양전지의 MPPT는 잘 알지 못하므로 GPT에게 물어봤습니다. 

 

 

회로 자체는 검증된 것이라 작동에는 문제가 없을 듯 하고요.

적당한 태양전지 판을 구해서 테스트를 해 봐야 할 것 같습니다.

 

 

728x90
728x90

요즘 탐조(야생새 관찰)에 발을 들여놓을까 말까 하는 중입니다. 

원래 동물 보는건 좋아하고 새에도 관심이 많거든요. 

 

문제는 제가 극 내향형 인간에 방콕을 매우 좋아하는 사람이라는 거지요. 

주말에 방문하기로 혼자 계획을 세우고 주말이 되자 역시나 가기싫다 귀찮다 속으로 외치다가 

큰맘먹고 출발을 했습니다. 

 

 

 

 

주차하고 길을 가는데 뭐가 옆에서 후다닥 좌우로 왔다갔다 뛰네요.

사슴인지 노루인지가 울타리로 막힌 곳에서 길을 찾고 있었습니다. 

 

 

 

 

 

차를 대놓고 책방으로 향하는데 탐조하기 딱 좋은 곳이더군요.

 

 

 

 

 

뭔가 거창하게 생긴 농민회관. 

주말에는 결혼식 등 행사관계로 복잡하고 주차비도 비싸다고 하니 되도록 인근 주차를 이용하는게 좋다고 합니다. 

 

 

 

 

 

건물을 뚫고 뒤편으로 넘어가면 바로 고즈넉한 건물이 있고 간판이 보입니다. 

 

 

 

 

 

 

 

 

워크샵이나 외부 탐조행사 등이 있어 항상 오픈되어 있지 않습니다. 

그래서 네이버 블로그나 인스타그램 페이지 등에 행사관련 공지가 항상 있는데 오늘은 그런게 없었습니다.

그런데 잠겨있네요?

 

마침 시계를 보니 12시 쯤이라 식사를 하러 가셨나 하고 주변이나 둘러보려고 나왔습니다. 

쌍안경을 들고 마침 건물 외벽 배수구로 들락날락 하는 참새를 잠깐 보는데 방금 옆에 주차한 차량에서 나오신 분이

'탐조책방 오셨나요?' 하고 묻네요. 

 

타이어에 펑크가 나서 수리하느라 늦으셨다는군요. 

마침 제가 쌍안경을 들고 있어서 바로 알아채셨는데 타이밍이 잘 맞아서 다행이네요

 

 

 

 

 

 

 

아기자기한 내부와 귀여운 소품들.

목적이던 조류도감류와 함께 몇권의 책을 구매하고 재미있는 설명을 듣고 나왔습니다. 

사장님이 참 친절하시고 부담스럽지 않게 설명도 잘 해주셔서 먼 거리를 왔던 보람이 있네요

 

 

 

 

 

이곳은 새들 때문에 일부러 심었는지 사방에 오디나무가 가로수마냥 있어 땅바닥에도 많이 떨어져 있습니다. 

어르신 두분이 열심히 줍고 있네요. 

보통 저런거 보면 좀 눈쌀이 찌푸려 질 때도 있는데

여긴 워낙 많으니 땅에 떨어져 밟히고 썩는 것보다 차라리 나아 보일 정도입니다. 

 

 

 

 

 

 

 

구매한 책을 차에 두고 호수를 한바퀴 돌아보기로 합니다. 

 

 

 

 

 

 

 

 

핸드폰 카메라로 찍은 왜가리 

 

 

 

 

 

쌍안경으로 보니 순 국내산 민물장어를 잡아먹고 있던 왜가리.

맛있겠다...

 

 

 

 

 

 

 

 

여긴 가마우지들이 바글바글 합니다. 

깃털의 방수력이 좋지 않다고 하는데, 물에 떠있을 때도 다른 물새들과 달리 몸통이 거의 잠겨있더군요. 

눈앞에서 잠수하는 걸 봤는데 각기 다른 녀석들이 한놈은 나뭇가지를 물고 올라오고 한놈은 잎사귀를 물고 올라오고.. 

제게 이녀석의 이미지는 약간 맹탕으로 굳어지고 있습니다. 

 

 

 

 

 

 

 

호수를 한바퀴 돌아보니 이런것도 있는데, 배율이 높긴 하지만 관리가 잘 안되어 살짝 뿌옇고 별로네요

그냥 쌍안경 보는게 나았습니다. 

 

 

 

 

 

 

집에 와서 오늘 구매한 책으로 동정.

처음 본게 대백로인듯 하군요. 다리가 살짝 노랬습니다. 

 

 

 

 

 

오리는 청둥오리 암컷인가 했는데 흰뺨검둥오리네요. 

옆에서 봤을 때 흰 줄무늬가 두줄. 부리 끝이 노란색. 

 

 

탐조활동이 나름 재미있긴 하지만 실외활동을 극히 싫어하는지라 과연 앞으로 어떻게 될지?

더위에 약해 일단 여름이 오면 정말 아무것도 못할듯 하고 좀 시간이 지나봐야 할 듯 합니다. 

728x90
728x90

Openweathermap에서 날씨를 받아와 사용하려 했는데 데이터 변환 과정에서 골치아픈 부분이 있었습니다. 

차후 4.2" 전자잉크 등 보다 화면이 넓은 기기를 사용하기 위해서 당일의 온도변화, 7일치의 날씨변화 등도 있었으면 했고요.

무엇보다 현재 날씨는 알 수 있는데 당일 날씨나 최저, 최고 온도 등 우리가 흔히 쓰는 기준으로 데이터를 얻기가 힘들더군요.

 

 

그리고 이 모든 것을 ChatGPT4.0 에게 맡겼습니다. 

 

 

 

 

 

 

 

 

저는 그냥 이렇게 해줘, 저렇게 해줘, 여기 틀렸잖아

를 반복하다 보니 코드는 손도 안대고 좋은 결과가 나오더군요

 

 

금일 온도 / 최저 / 최고온도 / 체감온도/ 구름 / 풍속 / 강수량 / 강설량 등이 잘 정리되어 출력된 것을 볼 수 있습니다. 

5일간 날씨 데이터도 마찬가지로 정리되어 나오고 있고요

 

 

 

아래는 이 코드입니다.

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

// WiFi 설정
const char* ssid = "Yourssid";
const char* password = "yourPW";

// OpenWeatherMap API 키
String openWeatherMapApiKey = "YourAPI";

// 서울의 도시명과 국가 코드
String city = "Seoul";
String countryCode = "KR";

// 업데이트 주기 설정 (15초)
unsigned long lastTime = 0;
unsigned long timerDelay = 15000; 

void setup() {
  Serial.begin(115200); // 시리얼 모니터 시작
  Serial.println("serial start"); // 디버깅 메시지 추가
  WiFi.begin(ssid, password); // WiFi 연결 시작
  Serial.println("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // 즉시 첫 번째 API 호출을 위해 lastTime 초기화
  lastTime = millis() - timerDelay;
}

void loop() {
  // 타이머가 만료되었을 때 데이터 요청
  if ((millis() - lastTime) > timerDelay) {
    if (WiFi.status() == WL_CONNECTED) {
      // API 요청 URL 구성 - 3시간 간격의 5일 예보 데이터
      String serverPath = "https://api.openweathermap.org/data/2.5/forecast?q=" + city + "," + countryCode + "&appid=" + openWeatherMapApiKey + "&units=metric";
      
      // 데이터 요청 및 수신
      String weatherData = httpGETRequest(serverPath.c_str());
      if (weatherData != "{}") { 
        parseWeatherData(weatherData); // 수신된 데이터 파싱
      }
      lastTime = millis();
    } else {
      Serial.println("WiFi Disconnected");
    }
  }
}

// HTTP GET 요청 함수
String httpGETRequest(const char* serverName) {
  WiFiClientSecure client; 
  client.setInsecure();    // SSL 인증서 검증 무시
  HTTPClient http;
  http.begin(client, serverName); // HTTPS 연결 시작
  Serial.println("Requesting URL: " + String(serverName));

  int httpResponseCode = http.GET();
  
  String payload = "{}";
  if (httpResponseCode == 200) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  } else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
    payload = http.getString(); 
    Serial.println("Error response: " + payload);
  }
  http.end();
  return payload;
}

// 타임스탬프를 한국 표준시(KST)로 변환하는 함수
String convertUnixTimeToKST(long unixTime) {
  unixTime += 9 * 3600; // UTC+9 시간대 보정
  time_t t = unixTime;
  struct tm *tmStruct = localtime(&t);
  char buffer[30];
  strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tmStruct);
  return String(buffer);
}

// 날씨 데이터 파싱 함수
void parseWeatherData(String json) {
  JSONVar myObject = JSON.parse(json);
  if (JSON.typeof(myObject) == "undefined") {
    Serial.println("Parsing failed!");
    return;
  }

  // 오늘 날씨 데이터 파싱 및 출력
  Serial.println("Today's Weather Data:");
  JSONVar list = myObject["list"];

  // 하루 동안의 데이터에서 최저/최고 온도 계산
  float dayMinTemp = 1000;
  float dayMaxTemp = -1000;
  for (int i = 0; i < 8; i++) { // 24시간 내의 3시간 간격 데이터
    JSONVar data = list[i];
    float temp_min = (float)(double)data["main"]["temp_min"];
    float temp_max = (float)(double)data["main"]["temp_max"];
    if (temp_min < dayMinTemp) dayMinTemp = temp_min;
    if (temp_max > dayMaxTemp) dayMaxTemp = temp_max;
  }
  JSONVar todayData = list[0];
  float temp = (float)(double)todayData["main"]["temp"];
  float feels_like = (float)(double)todayData["main"]["feels_like"];
  const char* weather_description = (const char*)(todayData["weather"][0]["description"]);
  float humidity = (float)(double)todayData["main"]["humidity"];
  float clouds = (float)(double)todayData["clouds"]["all"];
  float wind_speed = (float)(double)todayData["wind"]["speed"];
  float rain = todayData.hasOwnProperty("rain") ? (float)(double)todayData["rain"]["3h"] : 0;
  float snow = todayData.hasOwnProperty("snow") ? (float)(double)todayData["snow"]["3h"] : 0;

  Serial.print("Temp: ");
  Serial.println(temp);
  Serial.print("Min Temp: ");
  Serial.println(dayMinTemp);
  Serial.print("Max Temp: ");
  Serial.println(dayMaxTemp);
  Serial.print("Feels Like: ");
  Serial.println(feels_like);
  Serial.print("Humidity: ");
  Serial.println(humidity);
  Serial.print("Clouds: ");
  Serial.println(clouds);
  Serial.print("Weather: ");
  Serial.println(weather_description);
  Serial.print("Wind Speed: ");
  Serial.println(wind_speed);
  Serial.print("Rain Volume (3h): ");
  Serial.println(rain);
  Serial.print("Snow Volume (3h): ");
  Serial.println(snow);
  Serial.println("-------");

  // 5일간 날씨 데이터 파싱 및 출력
  Serial.println("5 Days Weather Data:");
  for (int day = 0; day < 5; day++) {
    float minTemp = 1000;
    float maxTemp = -1000;
    float avgHumidity = 0;
    float avgClouds = 0;
    float avgWindSpeed = 0;
    float totalRain = 0;
    float totalSnow = 0;
    int count = 0;
    String weatherDescriptions = "";

    for (int i = day * 8; i < (day + 1) * 8 && i < list.length(); i++) {
      JSONVar dayData = list[i];
      float temp_min = (float)(double)dayData["main"]["temp_min"];
      float temp_max = (float)(double)dayData["main"]["temp_max"];
      float humidity = (float)(double)dayData["main"]["humidity"];
      float clouds = (float)(double)dayData["clouds"]["all"];
      float wind_speed = (float)(double)dayData["wind"]["speed"];
      float rain = dayData.hasOwnProperty("rain") ? (float)(double)dayData["rain"]["3h"] : 0;
      float snow = dayData.hasOwnProperty("snow") ? (float)(double)dayData["snow"]["3h"] : 0;
      const char* weather_description = (const char*)(dayData["weather"][0]["description"]);

      if (temp_min < minTemp) minTemp = temp_min;
      if (temp_max > maxTemp) maxTemp = temp_max;
      avgHumidity += humidity;
      avgClouds += clouds;
      avgWindSpeed += wind_speed;
      totalRain += rain;
      totalSnow += snow;
      weatherDescriptions = String(weather_description);
      count++;
    }
    avgHumidity /= count;
    avgClouds /= count;
    avgWindSpeed /= count;

    long date = (long)list[day * 8]["dt"];
    Serial.print("Date: ");
    Serial.print(convertUnixTimeToKST(date));
    Serial.print(", Min Temp: ");
    Serial.print(minTemp);
    Serial.print(", Max Temp: ");
    Serial.print(maxTemp);
    Serial.print(", Humidity: ");
    Serial.print(avgHumidity);
    Serial.print(", Clouds: ");
    Serial.print(avgClouds);
    Serial.print(", Wind Speed: ");
    Serial.print(avgWindSpeed);
    Serial.print(", Rain Volume (3h): ");
    Serial.print(totalRain);
    Serial.print(", Snow Volume (3h): ");
    Serial.print(totalSnow);
    Serial.print(", Weather: ");
    Serial.println(weatherDescriptions);
    Serial.println("-------");
  }
}

 

 

그렇지만 이 모든 걸 갈아엎게 되는데.. 다음 포스팅에 이어서 쓰겠습니다.

728x90
728x90

검색해 보면 날씨정보를 받아오는 방법은 여러 가지입니다.

기상청이나 여타 날씨관련 사이트 등에서도 가능하지만 여러 모로 알아본 결과 openweathermap 이 편리할 것 같더군요




1. 오픈웨더맵 가입 - api 를 생성합니다.

 

 

이후 

http://api.openweathermap.org/data/2.5/weather?q=yourCityName,yourCountryCode&APPID=yourUniqueAPIkey

위 텍스트에서 yourCityName / yourCountryCode / yourUniqueAPIkey를 수정해야 하는데요.

 

 

 

 

서울을 예로 들면

검색하면 이렇게 나오는데 yourCityName 은 Seoul, yourCountryCode 은 KR 을 넣으면 됩니다

그리고 마지막 yourUniqueAPIkey 를 처음 발급받은 API 를 복사해서 수정하면 전체 주소가 완성됩니다.

 

 

 

 

 

 

그 주소를 인터넷 창에 입력해보면 다음과 같이 날씨 데이터가 표시되는 것을 알 수 있습니다

 

 

 

이제 이 API 주소를 이용해 ESP32C3 에서 날씨 데이터를 받아와 보겠습니다.

맨 먼저 날씨 데이터가 JSON 형식으로 나오기 때문에 이를 처리할 Arduino_JSON 라이브러리를 설치해 줬습니다.

 

 

 

 

 

 

이번에는 초기 코드를 99% 이상 ChapGPT 4.0에게 맡겼습니다. 

예전보다 훨씬 뛰어나져서 원하는 대로 코드를 깔끔하게 짜 주네요.

저는 세부 사항 몇가지를 조정하고 두세번 다시 물어보는 정도로 코드를 완성할 수 있었습니다. 

 

 

 

전체 코드는 아래와 같습니다.

#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

const char* ssid = "YourWifiID";
const char* password = "YourWifiPassword";

// Your Domain name with URL path or IP address with path
String openWeatherMapApiKey = "YourAPI";

// Replace with your country code and city
String city = "Seoul";
String countryCode = "KR";

// Timer set to 15 seconds for demonstration
unsigned long lastTime = 0;
unsigned long timerDelay = 15000;

String jsonBuffer;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println("Timer set to 15 seconds (timerDelay variable), it will take 15 seconds before publishing the first reading.");
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    if (WiFi.status() == WL_CONNECTED) {
      String serverPath = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&APPID=" + openWeatherMapApiKey;
      jsonBuffer = httpGETRequest(serverPath.c_str());
      JSONVar myObject = JSON.parse(jsonBuffer);

      if (JSON.typeof(myObject) == "undefined") {
        Serial.println("Parsing input failed!");
        return;
      }

      Serial.print("Latitude: ");
      Serial.println(myObject["coord"]["lat"]);
      Serial.print("Longitude: ");
      Serial.println(myObject["coord"]["lon"]);
      
      Serial.println("Weather Details:");
      for (int i = 0; i < myObject["weather"].length(); i++) {
        Serial.print("  Weather ID: ");
        Serial.println(myObject["weather"][i]["id"]);
        Serial.print("  Main: ");
        Serial.println(myObject["weather"][i]["main"]);
        Serial.print("  Description: ");
        Serial.println(myObject["weather"][i]["description"]);
        Serial.print("  Icon: ");
        Serial.println(myObject["weather"][i]["icon"]);
      }

      Serial.print("Temperature: ");
      Serial.println(myObject["main"]["temp"]);
      Serial.print("Feels Like: ");
      Serial.println(myObject["main"]["feels_like"]);
      Serial.print("Minimum Temperature: ");
      Serial.println(myObject["main"]["temp_min"]);
      Serial.print("Maximum Temperature: ");
      Serial.println(myObject["main"]["temp_max"]);
      Serial.print("Pressure: ");
      Serial.println(myObject["main"]["pressure"]);
      Serial.print("Humidity: ");
      Serial.println(myObject["main"]["humidity"]);

      Serial.print("Wind Speed: ");
      Serial.println(myObject["wind"]["speed"]);
      Serial.print("Wind Direction (Degrees): ");
      Serial.println(myObject["wind"]["deg"]);
      if (myObject["wind"].hasOwnProperty("gust")) {
        Serial.print("Wind Gust: ");
        Serial.println(myObject["wind"]["gust"]);
      }
      
      if (myObject.hasOwnProperty("rain")) {
        Serial.print("Rain Volume for last hour: ");
        Serial.println(myObject["rain"]["1h"]);
      }
      
      if (myObject.hasOwnProperty("snow")) {
        Serial.print("Snow Volume for last hour: ");
        Serial.println(myObject["snow"]["1h"]);
      }

      Serial.print("Visibility: ");
      Serial.println(myObject["visibility"]);
      
      Serial.print("Cloudiness (%): ");
      Serial.println(myObject["clouds"]["all"]);

      lastTime = millis();
    } else {
      Serial.println("WiFi Disconnected");
    }
  }
}

String httpGETRequest(const char* serverName) {
  WiFiClient client;
  HTTPClient http;
  http.begin(client, serverName);
  int httpResponseCode = http.GET();
  String payload = "{}"; 

  if (httpResponseCode > 0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  } else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  http.end();
  return payload;
}

 

 

 

 

 

아래가 출력 결과입니다.

완벽합니다.

 

 

 

 

 

여담이지만 재미있던 것은 제가 출력 반복 간격을 늦추려고 10000(10초)를 15000(15초)로 변경했더니 

바로 다음 질답에서 시리얼 출력의 'Timer set to 10 seconds...' 부분을 'Timer set to 15 seconds...' 로 바꾸더군요

이런 센스(?)까지 발휘하는 모습에 다소 놀랐습니다. 

 

 

728x90
728x90

https://ko.aliexpress.com/item/1005006722945827.html

 

14188.0₩ 20% OFF|BIGTREETECH 팬더 럭스 LED 라이트 바 키트, 마그네틱 설치, Bambu Lab P1 X1 3D 프린터용 알

Smarter Shopping, Better Living! Aliexpress.com

ko.aliexpress.com

 

 

LED 바 추가하려고 알아보니 Bigtreetech 사에서 최근에 나온 물건이 있더군요.

가격이 좀 비쌌지만 사진상으로 봤을 때 괜찮아 보여 구매해 봤습니다.

오늘 도착해서 작업해 보니 리뷰를 쓸 만한 물건인 것 같아 리뷰를 올려봅니다.

 

 

 

 

 

포장은 지관에 엄청 깔끔하게 되어 손상없이 잘 도착했습니다.

 

 

 

 

 

 

 

하지만 어댑터 보드가 들어있는 지퍼백을 저질 양면테잎으로 붙여놔서 자국이 남네요.

포장은 잘해놓고 이게 뭔지.. 라이터 기름으로 깨끗이 지워냈습니다.

 

 

 

 

 

 

QR코드로 인터넷 메뉴얼을 볼 수 있게 되어 있는데, 프린터 전체 크기 도면을 쓰면서 깨알만한 커넥터 설명을 써 놓으니 뭐 제대로 보이지도 않고 해서 알아보기가 좀 힘들더군요.

그냥 밑에 사진만 보셔도 이해가 될 겁니다.

 

 

 

 

 

 

 

 

 

제품은 요렇게 생겼습니다.

 

 

 

 

 

 

 

 

 

알루미늄 프레임에 자석이 들어있어서 프린터의 전면 상부에 그대로 붙습니다.

양면테잎도 쓰고싶으면 쓰라고 추가로 들어있는데, 자성이 충분해서 안 써도 될 것 같습니다.

 

 

 

 

 

 

 

 

 

사용법은 간단합니다. 메인보드에서 LED 케이블을 뽑고 그 자리에 패키지에 들어있던 케이블을 꽂습니다.

그러면

1. BTT LED 케이블

2. 원래 붙어있는 LED 케이블

3. 메인보드에 새로 끼운 LED 케이블

이렇게 3개의 케이블이 되는데 이걸 전부 어댑터 보드에 꽂으면 병렬로 연결됩니다.

 

 

 

 

 

 

 

 

 

그러면 이렇게 불이 들어오죠.

 

 

 

 

 

 

 

 

 

 

P1S도 똑같이 작업하면 됩니다. 다만 X1C 와는 커넥터 모양이 반대로 되어 있어서 케이블만 뒤집어 끼우면 되고요.

추가로 패브릭 테이프도 약간 들어있어 원하신다면 깔끔하게 케이블 정리를 할 수 있습니다.

작업이 굉장히 빠르고 편했고 어댑터 보드가 있어 기존 LED까지 그대로 켜진다는 것이 매우 마음에 들었습니다.

가격이 좀 비싼 것을 감안해도 상당히 만족스러운 물건이었습니다.

728x90

'Review' 카테고리의 다른 글

엘가토 스트림덱  (0) 2024.11.20
뱀부랩용 Panda Revo 핫엔드 구매기  (0) 2024.06.27
키크론 K10 pro 구매.  (0) 2023.06.28
FNIRSI-FNB58 USB 테스터 리뷰  (0) 2023.01.11
폴리튠 클립 튜너 간단리뷰.  (0) 2022.12.25
728x90

 

 

 

 

 

 

1. 설마 알리에서 이것도 팔까 하여 찾아봤더니 있었음. 

2. 이번 수리의 최대 난관은 정확한 부품명을 알아내는 것이었음. 

3. 부품교환 자체는 5분도 안걸렸지만 부품 배송에 40일 걸림. 

 

728x90
728x90

 

 

타오바오에서 너무 많이 사는 바람에 혼자서는 평생 쓰고도 남을 만큼의 전자잉크가 생겨서 사용처를 고민중이었습니다. 

그러다가 마음에 드는 프로젝트를 발견했죠.

 

 

 

 

 

 

 

전기도 많이 먹지 않고, 리프레쉬도 자주 필요 없는 이런 날씨정보 디스플레이 용으로 좋겠더군요.

 

 

 

 

 

 

원래는 전용 드라이버 보드를 제작해서 컨트롤러를 대체하려고 했지만 실패하고..

디버깅 중에 어차피 비용도 비슷하게 들 것 같아 그냥 편한 쪽으로 일단 진행하기로 했습니다. 

 

 

 

 

 

 

 

 

컨트롤러는 ESP32C3 보드를 사용할 예정입니다.

 

 

 

 

 

가격은 무려 2천원대에 블루투스, 와이파이도 되면서 ESP32의 성능을 가져 성능도 부족할 게 없고요.

보다시피 엄청 아담한 사이즈라 사용하기에도 좋습니다. 

728x90
728x90

LoRa 통신에 알아보던 중 Meshtastic 이란 프로젝트에 대해 알게 되었습니다. 

 

LoRa 장비를 이용해서 메쉬 네트워크를 구성하여 소량의 데이터를 송수신할 수 있는 오픈소스 프로젝트입니다. 

농장 같은 곳에서 센서 네트워크용으로 쓰이기 괜찮아 보이네? 하고 생각했는데요.

알고보니 통신이 미흡한 격오지에서 비상 네트워크 용으로 쓰이며, 실제로 우크라이나 전장에서도 일부 사용된다더군요.

 

흥미가 가서 장비를 구매하려고 했는데요.

알고 보니 국내에서는 전파법상 전파인증 면제는 개인당 1개씩만 가능한 문제가 있었습니다. 

물론 아두이노 같은 장비들은 수십개씩 구매하기도 하지만 이 기기는 전파를 송수신하는 문제로 약간 예민하더군요.

메쉬 네크워크를 구성하려면 혼자서는 불가능한거죠.

 

그래서 살짝 고민을 했는데요

 

 

 

 

 

그렇다면 다른 기기를 여러대 사면 되잖아?

 

개인 구매시 전파인증 면제는 1기기에 대해서만 가능한데, 이 1기기는 동일제품에 대해 해당됩니다. 

즉 다른 모델이나 다른 제품에는 해당하지 않죠.

 

이렇게 Meshtastic 을 사용할 수 있는 LoRa 기기 4종류를 1대씩 구매하면 모두 합법적으로 사용이 가능하단 얘기죠.

 

 

 

위 사진대로 구매하진 않았고, 일단 제일 저렴한 Heltec의 LoRa32-v3 기기와

 

https://heltec.org/project/wifi-lora-32-v3/

 

https://heltec.org/project/wifi-lora-32-v3/

 

heltec.org

이 기기의 위키

https://docs.heltec.org/en/node/esp32/wifi_lora_32/index.html

 

WiFi LoRa 32 — esp32 latest documentation

WiFi LoRa 32 [简体中文] WiFi LoRa 32 is a classic IoT dev-board designed & produced by HeltecAutomation(TM), it’s a highly integrated product based on ESP32-S3 + SX1262, it has Wi-Fi, BLE, LoRa functions, also Li-Po battery management system, 0.96”

docs.heltec.org

 

 

 

 

두번째로 Lilygo의 LoRa32 V2.1_1.6 버전을 구매했습니다. 

https://www.lilygo.cc/products/lora3

 

LoRa32 V2.1_1.6

LILYGO Paxcounter Disaster-Radio LoRa V2.1_1.6.1 ESP32 433/868/915MHZ 0.96 Inch OLED SD Card Slot Bluetooth WIFI Module Metering Passenger Flows Main features: Digital RSSI function Automatic frequency correction Automatic gain control Fast wake-up and fr

www.lilygo.cc

이런 기기 구매시 버전만 달라도 다른 기기로 취급되기 때문에 모양이 같아 보여도 다른 버전이면 사용 가능합니다. 

 

물론 국내 LoRa 통신주파수인 920~923Mhz 를 쓰는 기기를 구매해야 합니다. 

다른 주파수를 구매하면 쓸 수는 있는데 불법이에요.

일부 제품은 915Mhz로 표시하고 있는데 통신칩을 살펴봐야 하지만 보통 주파수가 860 이상인 경우는 호환되는 것 같더군요. 제가 정확히 확인해 보진 않아서 보장할 순 없습니다. 

 

 

 

그러면 이제 펌웨어를 업로드 해야 하는데요

웹페이지에서 바로 플래쉬 가능한 웹 플래셔가 있더군요.

https://flasher.meshtastic.org/

 

https://flasher.meshtastic.org/

 

flasher.meshtastic.org

 

 

 

기기를 USB에 꽂고

이 사이트에서 기기를 선택한 후 

 

 

 

 

설치를 선택하고 USB포트 선택.

 

 

 

그리고 flash를 누르면 바로 해당 기기에 맞는 펌웨어가 업로드 됩니다. 

매우 편리하네요

 

 

728x90
728x90

얼마전부터 굉장히 이상한 에러가 발생해 몇달간 골머리를 썩게 한 일이 있었는데요

 

 

 

 

ESP32C3 보드를 이용해 프로젝트를 하려고 하는데 컴파일이 전혀 되지 않는 문제가 생겼습니다.

요상한 컴파일 에러가 생기는데, 에러 메세지가 부정확하고 아무리 구글링해도 비슷한 사례를 찾기가 힘듭니다.

 

 

 

 

 

문제를 하나하나 짚어보려고 간단한 예제를 사용해 봤습니다.

blink 예제는 문제없이 컴파일이 됩니다.

하지만 wifi 예제는 안됩니다. 

그렇다면 wifi 라이브러리가 문제인가? 하고 찾아봤더니 문제가 없습니다. 

보드 매니저도 문제가 없습니다. 

 

에러 중에 가장 골치아픈 에러가 간헐적으로 발생하는 에러인데

문제는 간헐적으로 성공하는 경우가 있었다는 것입니다. 

 

열번에 한두번 정도는 컴파일에 성공합니다. 어처구니가 없지요

IDE 다운그레이드도 해보고 노트북에서도 컴파일해보고 데스크탑에서도 해보고 아예 노트북을 포맷도 해봤습니다만 같은 상황입니다. 

 

두어달 정도를 아두이노를 써보지 못하다가 오늘 다시 생각이 나서 컴파일 해보니 여전히 에러가 납니다. 

그러다가 AI에게 다시 물어볼 생각이 들었지요.

사실 초기에도 질문을 했었는데 그때는 해결이 되지 않았지만 그 사이 데이터베이스가 좀 더 쌓이거나 똑똑해져서 제 문제를 해결해 줬으면 좋겠다는 얄팍한 생각이 들었습니다. 

 

 

 

 

 

 

결과는!

해결!!!!!!

 

 

 

 

 

제가 각종 프로젝트를 저장하는 폴더는 MyProject&Documents 폴더인데

이 폴더명에서 &이 문제가 됐더군요.

 

원인을 찾기 힘들었던 게 그동안 전혀 문제가 없었고 잘 사용하다가 최근에서야 ESP32C3 보드를 사용하면서 문제가 생겼기 때문입니다. 

거기다 드물게 컴파일에 성공하기도 하는 이상한 케이스까지 겹쳐서 더 혼란스러웠네요

 

 

 

 

 

 

폴더명 고치고 나니 잘 동작합니다. 

 

이것 때문에 막힌 프로젝트들이 좀 있었는데 다시 재가동에 들어가야 겠습니다.

 

 

 

 

 

728x90

'주인장 잡담' 카테고리의 다른 글

탐조일지 #1 - 동네탐조  (0) 2024.06.06
탐조책방 방문기  (0) 2024.05.25
새 차 고르기 #2  (0) 2024.03.20
새 차 고르기 #1  (0) 2024.03.17
아마존의 영문 책을 빠르게 번역해서 보기.  (0) 2024.02.14
728x90

https://www.youtube.com/watch?v=x99R78fkSg0%EF%BB%BF

위 동영상의 내용을 정리한 것입니다. 

 

 

Meshstatic 안드로이드 앱의 장치 설정(Radio Configuration) 메뉴

 

User

Node ID는 변경 불가능. 참조용임.
긴 이름은 39자까지 설정 가능 짧은 이름은 4자 이하
짧은 이름은 노드 목록에서 버블로 표시된다

그 아래 하드웨어 모델 표시되고
다음으로 아마추어 무선용으로 사용시 토글하는 스위치가 있다. 
아마추어 무선 사용시 암호화는 FCC 규정에 위배되므로 무선 구성 페이지에서 암호화가 비활성됨.



Channels

채널과 주파수를 혼동하지 말 것.  
채널은 채팅방이라고 생각하면 편함. 
채널 구성 페이지는 채팅방을 만들고 암호화를 활성화하거나 MQTT를 이용해 인터넷과 연결할 수 있다. 
번호는 0-7까지 최대 8개 생성 가능

LongFast 기본채널
다른 동영상으로 추가설명. 

채널이 가질 수 있는 세 가지 상태.
Primary
Primary 채널은 1개만 가능. GPS 위치 포함 원격 모니터링은 이 채널을 통해 전송됨. 
공개 채널에서 위치 숨기는 법은 추가동영상 볼 것. 

Secondary 
추가 채널은 보조 채널이며 자체 암호화 키도 가질 수 있음

Disabled
채널 닫힘. 사용할 수 없음. 

채널을 생성하면 사전공유키가  자동 생성됨. 새로고침 눌러 변경 가능
업링크 /다운링크는 mqtt(인터넷 접속)용.
다운링크:  mqtt에서 메시로 메시지가 전달됨 
업링크: 메시에서 mqtt로 메시지가 전달됨


Device

Role
Client- 기본세팅. 다른 클라이언트와 통신함
Client_Mute  - 클라이언트지만 메쉬에 재방송하거나 기여하지 않음. 
사용예)실외에 있는 클라이언트에게 블루투스로 연결하기 힘들 경우 일차적 연결이 필요할때
센서 노드가 많이 있는데 메쉬에 연결할 필요는 없고 전파 환경을 깨끗하게 유지하고 싶을 때
Router - 높은 고도, 핵심 위치에 놓은 장치에 설정. 광범위 도달. 
패킷은 라우터 통과를 선호함. 배터리 소모 증가.

자동으로 블루투스/와이파이/스크린은 절전모드가 됨

Router_Client- 라우터와 같지만 블루투스/와이파이/스크린이 살아있으며 여전히 클라이언트로 사용 가능

Repeater- 라우터와 유사하게 패킷은 리피터 통과를 선호하게 됨 
라우터와 다른 점은 노드 정보와 디바이스 telemetry 등의 정보를 방송하지 않음. 
그러므로 리피터는 노드 정보가 뜨지 않으며 배터리 레벨이나 센서 정보가 표시되지 않게 됨
리피터에는 몇가지 추가 구성 메뉴가 있는데 
Rebroadcat mode에서
all  - 당신의 메쉬 뿐 아니라 다른 메쉬의 패킷도 재전송함.다른 암호화 메세지까지 모두.
all skip decoding - all과 비슷하지만 디코딩을 수행하지 않음
local only - 당신의 공개키를 갖고있는 트래픽만 재전송함. 
known_only - local only와 비슷하지만 공개키뿐 아니라 노드 데이터베이스에 있는 노드의 트래픽만 재전송함. 

Tracker
GPS 추적장치에 유용함. GPS 장치가 위치 업데이트될때까지 절전 모드로 전환되고 위치 업데이트후 다시 절전되어 배터리를 절약함

Sensor
센서 데이터 전송에 유용함
패킷에 우선순위가 있으며 5분마다 전송됨
자동으로 슬립 모드로 전환되었다가 센서 데이터 전송할 때마다 깨어남


TAK
meshtastic atak 플러그인과 함께 사용되는 장치
안드로이드 팀 인식 키트를 의미함
미군에 의해 공공 안전 및 민간 사용을 위해 공개됨

Client_Hidden
RF 추적을 회피하기 위해 루틴 전송을 끄고 신호 노출을 줄임
메세지 전송시에만 사용됨
배터리 전원 절약 가능하고 SOS 비컨 등 추적장치로 사용하는 것도 가능
(신호 전송시에만 비퍼를 울린다거나)

나머지 옵션
시리얼 출력 
디버그 로그
핀 버튼 재정의 
핀 버저 재정의
GPIO pin 설정

nodeinfo broadcast interval
말그대로 노드 정보 발신 간격

double tap as buttom press
가속도계가 있는 장치 사용시 더블 탭으로 버튼 누르는 기능. 


managed mode
클라이언트 응용 프로그램을 통해 무선 구성을 변경하는게 불가능해지고 관리 채널을 통한 원격 관리만 가능해짐

disable triple click
T빔과 같은 장치는 삼중 클릭 버튼을 사용하여 GPS를 빠르게 끌 수 있는데 이런 기능을 비활성화하는 것. 



Position
포지션과 다른 기본 구성은 primary 채널을 통해 전송됨
secondary 채널을 구성하더라도 위치정보 등은 primary채널을 통해 계속 전송됨

smarty posiotion 활성시 위치 변경시 자동으로 위치정보를 전송함. 

고정포지션 활성시에는 위경도 정보등 수동입력

fix attempt duration
GPS 정보를 얻는 시간


position flag
altitude - 해수면 
altitude msl - Mean Sea Level 평균 해수면 레벨
geoidal seperation - 타원체 높이와 직교 높이 사이의 차이 값.. 어려우니 패스
dop - dilution of precision 정밀도 희석?
HVDOP - 수직 dop와 스평 dop 값을 분리해서 전송한다
seq_no 해당 시간에 장치가 수신하는 위성 수를 전송
타임스탬프


Power
장치 역할(client 등)을 설정하면 파워 세팅도 자동으로 변경되므로 일반적으로는 손댈 필요 없음


Network
wifi를 켜면 블루투스는 꺼짐. 
ntp server - 시간정보 
rsyslog server 로그 저장



Display 
carousel - 자동으로 화면 순환


728x90
728x90

https://www.youtube.com/shorts/EjxgVUWwsXQ

몇가지 치수를 조정하고 난 뒤 어느정도 잘 돌아가기 시작합니다.

하지만 정지 시 포크가 반대로 돌아간다던가 하는 문제가 생기더군요.

가드 핀의 존재 이유를 깨달았습니다. 

 

 

 

 

 

 

가드 핀 제작해서 테스트. 

패싱 홀(passing crescent) 의 사이즈 조정을 위해 사이즈별로 출력해봄. 

 

 

홀 사이즈가 문제가 아니라 바늘이 그냥 아래로 통과해 버리는 경우가 발생하여 높이를 조정해 재설계.

 

 

 

 

 

 

 

다만 이 과정에서 같은 설계로 출력한 물건들이 잘 돌아가지 않는 경우가 많이 발생합니다.

주로 검은색 출력물들이 문제가 많은데 돌려보면 약간씩 돌아가는 느낌이 다릅니다. 

색소 등의 문제로 마찰력이 다른 게 아닌가 싶어서 다른 필라멘트를 써야 할 듯. 

 

계속 수정중입니다.

 

728x90

'Making > 탈진기 설계와 제작' 카테고리의 다른 글

탈진기 수정 마무리와 공구 제작.  (0) 2024.07.02
새 탈진기 설계와 조정.  (0) 2024.04.04
탈진기 첫 테스트.  (0) 2024.03.01
포크와 롤러 설계  (0) 2024.02.25
팔레트 설계  (0) 2024.02.25
728x90

 

 

기존 책에 있던 내용도 나쁘진 않았지만, 여전히 이해가 안가는 점들이 있어 다른 책도 구매했습니다. 

영어라 여전히 독해가 쉽진 않지만 그래도 지난번 경험을 바탕으로 다시 한번 훑어보니 조금 더 이해가 가는 부분이 있네요.

이번 책은 더 최근에 나온 것이라 인쇄도 깔끔하고 설명도 좀 더 간결해서 좋았습니다. 

그래서 새 책의 내용을 기반으로 재설계를 했습니다. 

 

예전 계획은 각도 기반으로 설계를 해서 출력시 사이즈를 마음대로 변경하는 것이었습니다. 

하지만 0.2mm 노즐을 사용해도 출력물의 한계란 것이 있어 어차피 아주 작은 사이즈는 불가능하더군요.

그래서 최소값으로 이스케이프 휠을 30mm 지름 정도로 정했습니다. 

 

 

 

 

 

 

 

책의 설계대로 출력해 보면 팰릿 포크와 이스케이프 휠끼리 잠기는 각도가 영 맞지 않습니다. 

재질이나 크기의 차이 때문이 아닐까 하는데, 일단은 조금씩 조정해 가며 직접 교정하는 수 밖에 없겠더군요.

 

 

 

 

 

 

 

조정한 각도는 책에 있는 각도와 거의 15도 차이가 납니다. 

 

 

 

 

 

 

 

 

팰릿 포크의 길이를 길게 하면 밸런스 휠 스프링을 대신해서 반동이 생기지 않을까 하고 만들어 봤는데, 잘 안 되더군요.

 

 

 

 

 

 

 

 

기왕 길게 제작한 것을 이용해 펠릿 포크와 이스케이프 휠이 적당한 잠금이 되었을 때 펠릿 포크의 회전각이 얼마나 되는지 알고 싶어서 측정해 봤습니다. 

피타고라스 정리를 이용해 변의 길이를 알아내고 삼각함수를 이용해 각도를 알아낼 수 있죠.

 

 

 

 

 

 

답은 16.43도.

이제는 공학용 계산기도 없고, 어떻게 계산하는지도 가물가물해서 인공지능의 힘을 빌렸습니다. 

 

 

 

 

조정이 끝나면 추가로 밸런스 휠과 밸런스 스프링을 추가할 예정입니다. 

 

728x90

'Making > 탈진기 설계와 제작' 카테고리의 다른 글

탈진기 수정 마무리와 공구 제작.  (0) 2024.07.02
두번째 설계한 탈진기 테스트  (0) 2024.04.16
탈진기 첫 테스트.  (0) 2024.03.01
포크와 롤러 설계  (0) 2024.02.25
팔레트 설계  (0) 2024.02.25
728x90

몇년 전부터 쓰던 소형 선풍기가 있었는데 오래 쓰다 보니 자꾸 목이 꺾여서 새로 들였습니다. 

타오바오 떨이판매자에게 7000원에 저렴하게 구매했습니다. 

 

 

 

 

 

다 좋은데 지속시간이 짧아서 열어보니 배터리가 딸랑 하나

 

 

 

 

 

배터리 4개로 업그레이드해줍니다. 

원래 Micro usb 충전인데 USB-c 포트도 병렬로 추가해 충전 편의성을 높였습니다. 

 

 

 

 

 

충전에만 하루 꼬박 걸리네요. 사용시간은 대폭 늘어나서 만족합니다. 

728x90

'D.I.Y.' 카테고리의 다른 글

SSD1306 0.9" OLED 드라이브 테스트.  (0) 2024.06.01
쓰레기통 수리.  (0) 2024.05.08
ESP32-C3 super mini 보드 사용해 보기.  (0) 2024.03.22
CAS 온습도계 수리.  (2) 2024.03.21
다목적 강아지 배변봉투 케이스  (0) 2024.03.21
728x90

조금이라도 작은 보드 만들겠다고 Attiny에 프로그램 올리느라 힘들었던 게 얼마전인것 같은데요. 

이제는 그보다 훨씬 클럭도 빠르고 메모리도 넘치는 보드가 그만한 사이즈로 나오는 세상입니다. 

 

 

 

 

 

전자잉크 프로젝트에 올리려고 보드를 테스트하는 중입니다. 

보드 매니저에서 esp32를 검색하면 나오는 Espressif의 esp32를 설치하고, 

이후로는 ESP32C3 dev board로 사용하면 됩니다. 

 

 

 

 

 

일단 Blink 업로드를 해 보았습니다. 

LED 핀 번호는 8입니다. 

이상없이 업로드가 되길래 다른 코드를 테스트해보았다가 업로드가 되지 않아 혼란스러웠는데요.

 

 

 

 

 

 

업로드를 할 때는 전원이 들어올 떼 boot 스위치가 눌러진 상태여야 합니다. 

Reset 버튼을 누른 채로 boot 버튼을 동시에 누르고 reset 버튼을 뗀 뒤 boot 버튼을 떼서 boot 모드로 만든 후 업로드를 해야 하더군요.

업로드 후에는 reset 을 한번 눌러 하드 리셋을 하면 프로그램이 실행됩니다. 

그리고 5V 핀을 이용해 전원을 따로 공급시에는 프로그램 업로드가 안된다고 하니 별도의 보드를 제작 시에는 참고해야 할 것 같습니다. 

 

 

 

 

 시리얼 출력을 하려면 보드 옵션에서 USB CDC On Boot 를 Enable 해야 합니다. 

 

 

 

 

 

 

Blink 코드를 업로드하고 시리얼 출력을 하면 위와 같이 잘 되는 걸 볼 수 있는데요.

 

 

 

 

 

 

이번에는 Fade 코드에 똑같이 Serial.print를 넣어보면 LED는 페이드 되며 정상적으로 실행되지만 시리얼 출력은 되지 않는 걸 볼 수 있습니다. 

 

 

 

 

 

https://www.reddit.com/r/esp32/comments/16qaf8u/trouble_reading_serial_output_on_my_esp32c3/

 

From the esp32 community on Reddit: Trouble Reading Serial Output on my esp32-C3: Seeking Help!

Explore this post and more from the esp32 community

www.reddit.com

이게 대체 뭔가 했는데 검색해보니 비슷한 케이스가 많습니다. 

특정 조건 하에서 시리얼 출력이 안 되는 것 같습니다. 

시리얼 출력을 안정적으로 얻고 싶으면 별도로 하드웨어시리얼 설정을 하고 연결을 해야 할 것 같네요.

 

 

 

 

 

 

 

Wifi scan 코드를 테스트해봤습니다. 잘 되고 시리얼 출력도 잘 나오는군요.

 

 

 

 

728x90

'D.I.Y.' 카테고리의 다른 글

쓰레기통 수리.  (0) 2024.05.08
책상용 선풍기 배터리 업그레이드.  (0) 2024.03.30
CAS 온습도계 수리.  (2) 2024.03.21
다목적 강아지 배변봉투 케이스  (0) 2024.03.21
N20모터용 기어비 / RPM 자동 계산장치  (0) 2024.03.10
728x90

욕실에서 쓰던 온습도계가 화면이 꺼져 배터리를 교환해 봤으나 여전히 들어오지 않더군요.

 

 

 

 

 

분해해 봤더니 좌측 배선 중간에 있는 via 홀에 부식이 발견되었습니다. 

 

 

 

 

 

 

 

가까이서 보면 이런 모습입니다.

아마도 via 홀 내부에 솔더마스크가 완전히 덮이지 않고 노출되었던 것 같습니다. 

그래서 욕실 중 습기나 물기에 의해 녹이 슬다가 아예 끊어진 듯 합니다. 

 

 

 

뒷면을 보니 물기가 약간 들어간 흔적이 있더군요.

그래도 다른 곳은 부식되지 않고 말짱합니다. 

 

 

 

 

 

 

 

수리를 합니다. 

 

 

 

 

 

 

 

 

일단 배터리를 끼워보니 잘 동작합니다.

다른 곳에는 문제가 없나 보네요.

 

 

 

 

 

 

 

 납땜하느라 노출된 부분에는 실리콘으로 마감했습니다. 

 

 

 

 

 

 

 

 

 

전부 조립하니 잘 나옵니다. 

비교적 간단하게 수리가 되었군요.

728x90
728x90

이런 제품을 쓰고 있습니다. 

뚜껑이 쉽게 열리고, 그럴 때 비닐봉투 롤이 통채로 빠지기도 하고 관리가 불편합니다. 

 

 

 

 

그래서 시중의 다른 제품을 참고로 설계했습니다. 

시제품을 출력해서 테스트해보니 비닐을 빡빡하게 잘 잡고 있으면서도 빠지지 않고 좋더군요.

 

 

 

 

 

뚜껑에는 작은 LED 전구를 넣습니다. 

야간 산책시 낙엽이나 풀이 우거진 곳에 강아지가 배변을 하면 찾기가 매우 힘듭니다. 

그럴 때 핸드폰의 플래쉬를 일일이 켜서 쓰는데 배변봉투 자체에 플래쉬 기능이 있으면 좋겠지요.

 

 

 

 

 

 

 

 

 

플라스틱 고리는 강도가 약할 것 같아 금속 봉을 구부려 넣었습니다. 

 

 

 

 

 

 

 

 

 

바닥면에는 아파트 열쇠 RFID 를 복사해서 붙여 넣었습니다. 

 

이로서 이 물건은 배변봉투 케이스 겸 LED 플래쉬 겸 아파트 열쇠가 되는거죠.

 

 

 

 

 

 

며칠 써 보니 쓸만합니다. 

728x90
728x90

새 차를 고르기로 생각을 하고 알아보니 정말 고려할 부분이 많더군요.

 

-차를 고르는 것은 인생을 되돌아 보는 일

차를 고르는 일은 단순히 사양을 비교하고 예산을 맞추는 것 이상이었습니다.. 

개인의 취향, 생활 패턴, 미래에 대한 예측까지 고려되어야 하죠.

차에 대한 지식이나 특별한 선호가 없는 상태에서 결정하려니 정말 혼란의 도가니더군요.

 

경차부터 SUV까지 다양한 카탈로그를 탐색했지만, 결정을 내리기는 쉽지 않았습니다. 

 

레이도 괜찮고... 소나타도 괜찮고.... 그랜저는 비싸고... suv는 편하겠고....

를 도돌이표처럼 반복하며 한달을 보낸 듯 하네요

 

예산은 충분했고 그 예산에서 제일 비싼 차를 고르면 편했을 수도 있지만 경차건 대형차건 상관없는 무취향의 운전자가 차량을 고르려니 그것도 쉽지 않더군요.

 

-파워트레인 
결국 파워트레인부터 결정하기로 했습니다

휘발유, 디젤, LPG, 하이브리드, 전기 중에서 말이죠.

주로 시내 주행을 하고, 큰 짐이나 승객을 자주 태우지 않는 운전 환경을 생각해서 디젤과 LPG는 제외하기로 했습니다.


연비 문제를 좀 심각하게 고려했는데요. 

제가 쓰던 토스카 차량의 연비가 좋지 않아(8.4km/L) 주유비 부담이 컸기 때문입니다.

그래서 연비가 좋은 하이브리드 차량을 고려하기 시작했습니다.

하이브리드 차량을 보다 보니 기왕 전기를 사용하고 주로 아파트에 주차하기 때문에 전기차를 선택하는 것도 나쁘지 않아 보였습니다.

비록 차량 가격이 높지만, 보조금을 통해 어느 정도 비용이 상쇄될 수 있다는 것을 알게 되었습니다.

우습게도 이때 전기차 보조금이 2가지(국가보조+지방보조)가 합쳐서 나온다는 것도 처음 알았고요.

보조금이 휘발유 차량의 가격차이를 상쇄할 정도라는 것도 이때 알았습니다. 

그래서 전기차를 고르는 데 망설임이 없어졌습니다. 

 

-최종 승자는?

최종 후보로는 레이, EV6, 아이오닉 6가 남았습니다.

여기서 정말 결정을 못 하겠더군요. 

그래 아이오닉으로 하자 했다가 며칠 지나서 아냐 EV6가 낫겠어 하다가 그냥 뭐하러 비싼차 타 레이가 낫지 하는 식으로 다시 도돌이표로 돌아갔습니다. 

 

타 보는게 제일 좋을 것 같아 쏘카 렌트를 통해 EV6와 아이오닉 6을 시승해 봤습니다. 

(레이는 안전상의 문제를 걱정하는 가족들 때문에 제외)

쏘카 회원가입 혜택 때문에 저렴하게 렌트가 가능하더군요.

 

둘 다 타 보니 아이오닉 6가 취향에 더 맞다는 결론을 내렸습니다.

EV6도 나쁘지 않았지만, 짐을 싣거나 캠핑을 즐기는 사람에게 더 적합한 특징이 많았습니다.

EV6의 장점은 저의 일상 생활과는 크게 관련이 없었습니다.

 

결론은 아이오닉 6.

 

현재는 계약을 넣은 상태이고 출고를 기다리고 있습니다. 

 

 

 

 

-ps.나를 혼란케 한 유튜브 리뷰어들. 
유튜브 리뷰와 시승기를 수없이 살펴보면서 깨달은 것이 있습니다. 

대부분의 리뷰어는 진짜 차량 소유자가 아니며, 사소한 단점을 과장하여 헤드라인을 만드는 경우가 많다는 것입니다. 

 

택시를 타고 전기차인 경우 기사님께 직접 물어봤습니다.

대부분이 대만족하신다고 좋아하셨습니다.

다시는 휘발유 차량으로 돌아가고 싶지 않다고 모든 기사님들이 말씀하시더군요.

728x90
728x90

남자라고 하면 왠지 차를 좋아할 것 같고, 매일 뭔가 기계를 만지고 하는 저도 당연히 그런 취향이 있을 것 같죠.

하지만 저는 놀랍게도 차에 대해 아무런 감정이 없습니다. 

그냥 이동수단의 하나일 뿐이고 내가 원하는 목적지까지 빠르게 나를 데려다 줄 수만 있으면 되는거죠.

딱히 취향도 없고 지식도 없습니다.

그래도 어느덧 운전을 꾸역 꾸역 하다 보니 이제 3번째 차량이 필요하게 되었네요.

 

 

 

 

처음으로 운전하고 다니던 차는 아버지가 쓰시던 크레도스였습니다. 

가족차량이라 제 차라기 보다는 좌석변경(?)인 식으로 몰고 다녔습니다.

제가 10여년 쓰다가 차령 19년째에 21만 km를 찍고 폐차했죠.

 

그때가 2012년인가 그랬는데 경제 사정이 좋지 않을 때라 급하게 중고로 2009년식 토스카를 구매했고요.

아버지가 몰던 크레도스는 관리가 정말 안돼있어서 냉각수문제로 엔진헤드까지 교체한 적이 있는 문제차량이었는데요.

갑자기 6기통으로 바꾸니 '액셀을 밟으면 가속이 잘 돼!' 하고 신기해했던 기억이 있네요..

그 토스카를 지금까지 몰고 있었습니다. 

지금 17만 km를 넘은데다 연비도 안좋고 잔고장이 있지만 운행에 문제를 주는 고장들은 아니어서 그냥 타고 있었습니다. 

올해 하반기쯤 차를 교체해야 하지 않을까... 하던 중

 

차문을 여는데 운전석 문 손잡이의 고정쇠가 또각 하고 부러지더라고요.

 

그 사소한(?) 고장이 '아 이제 진짜 차를 바꿔야겠다' 마음을 먹게 됐습니다. 

728x90
728x90

 

여러가지 프로젝트용으로 이런 모터를 많이 사용합니다. 

N20 모터라고 하는데 감속비도 여러 가지라서 다용도로 쓰기 편합니다. 

 

다만 문제는 위에 보듯 기어비가 명시되어 있지 않고 RPM 만으로만 표시되어 있습니다.

 

 

 

 

일부 셀러는 기어비를 써놓기도 하는데 안 그런 경우가 많습니다. 

모터가 이렇게 조금 쌓이다 보니 분류와 정리가 골치아프게 되었습니다. 

 

 

 

 

사진에 보듯 기어비가 아주 다르지 않은 이상은 형태와 사이즈는 거의 같고 내부 기어의 크기와 배치가 다릅니다. 

감속비가 크게 차이나지 않는 기어박스끼리는 서로 바꿔가며 쓸 수 있습니다. 

 

 

 

 

 

 

엔코더가 달린 모터를 이용해서 기어비를 알아낼 장치를 만들었습니다. 

모터가 회전하면서 엔코더로 모터축의 회전수를 체크하고 기어박스의 회전수는 리밋 센서로 체크합니다. 

모터축의 회전수를 기어박스의 회전수로 나누면 기어박스의 감속비를 알 수 있습니다. 

하는 김에 RPM도 같이 계산하도록 했습니다. 

 

 

 

 

 

 

 

 

 

간단한 계산만 하면 되는지라 금방 될 줄 알았는데 한동안 코딩을 안 했더니 진도가 영 안 나가더군요.

AI의 도움을 받아 기본 뼈대를 짜고 조금씩 수정하며 완성했습니다. 

 

 

 

 

 

 

 

분류 자체는 금방 되더군요.

감속비 별로 쓰기좋게 분류했습니다. 

728x90

+ Recent posts