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

 

배터리 만충후 이틀이 지나 설치하게 되었습니다. 

배터리 용량은 7500mAh 정도. 설치일은 10/27 오후 3시 30분. 

 

 

 

 

 

 

설치 위치는 서초 인근이고요. 

설치 후 이동하며 테스트를 해 봤습니다. 

대략 1.5km 정도까진 건물 음영에 따라 가끔 끊기지만 통신은 원활한 느낌.

2km 에서는 가끔 운좋으면 연결이 되는군요. 

 

평지 도심 기준이라 거리상으로는 나쁘지 않은 것 같습니다. 

어디 건물 옥상에 올려두면 참 좋을텐데 기술에 관심많은 건물주님 보시면 연락주세요 :)

 

 

--------------------------------추가---------------------------------

하루만에 연결이 끊겨서 조만간 다시 확인하러 가야 할 것 같습니다. ㅜㅜ

728x90
728x90

3달 하고도 보름만의 meshstatic 포스팅이네요

 

원래는 사실 6월 말에 기기를 설치하고 테스트를 해 보려 했습니다. 

 

그런데.. 설치하자 마자 기기가 먹통이 되었네요?

이미 더위에 접어들어 땀을 줄줄 흘리면서 한시간 동안 고생했는데 저걸 다시 떼낼 엄두가 안 나더라고요

그래서 날이 시원해지면 다시 작업해야 겠다 하고 미뤘습니다. 

 

그런데 날이 시원해지기까지 3달이 넘어갈 줄은 몰랐죠

 

 

 

 

 

 

 

 

 

원래는 걸어서 20분 정도의 거리인데 이번에는 복구한 전동 킥보드로 쓩 하고 다녀왔습니다. 

 

 

 

 

 

 

 

 

겉의 먼지를 제외하면 내부는 깨끗하고 문제가 없었습니다. 

 

 

 

 

 

 

배터리도 별 문제 없군요.

 

 

 

 

 

 

 

 

고장 원인을 찾아보니 어이없게도 전원 스위치의 불량이었네요.

몇년씩 묵은 오래 된 스위치다 보니 내부 접점이 산화된 것 같습니다. 

스위치를 제거하고 납땜으로 연결해보니 문제없이 잘 켜집니다. 

이제 다시 조립해서 도로 설치하면 본격적으로 테스트를 할 수 있을 것 같습니다. 

 

728x90
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

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

아무래도 제 개인의 코딩 능력을 많이 벗어난 데이터셋 정리 등이 필요하다 보니 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

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

 

 

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

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

 

 

 

 

 

 

 

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

 

 

 

 

 

 

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

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

 

 

 

 

 

 

 

 

컨트롤러는 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

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

 

https://youtu.be/3dY9H8E4f8o?si=RmyZZ0ADNQICMg_b&t=18

 

간신히 돌아가다 말다 합니다.

여기까지도 한참 걸렸는데 여전히 수정할 부분이 많네요. 

스프링의 장력 조절과 무게추 조정, 공차 수정과 설계 수정 등등등..

수직잡고 구멍뚫는것도 꽤나 어려워서 미니어처 베어링도 새로 구매했습니다.

도착하면 두번째 버전을 새로 만들어볼 계획입니다.

 

 

 

 

 

 

노즐을 0.2mm 로 교체했습니다.

 

 

 

 

 

 

 

계속 수정과 테스트 반복.

 

 

 

 

 

설계를 어느정도 잡은 후 출력물

 

 

 

 

 

 

드릴도 0.1mm 단위로 새로 샀습니다. 

 

 

 

 

 

 

핸드 핀바이스로 뚫으니 수직 잡기가 어렵더군요.

 

 

 

 

 

 

 

 

 

소형 드릴링머신도 하나 샀습니다.

좀 더 작은게 있으면 좋겠는데 못찾겠더군요.

 

 

 

 

 

 

 

 

 

괜히 한번 금색 마카펜으로 칠해봤습니다.

 

금방 될 줄 알았는데 시간을 오래 잡고 진행해야 할 것 같습니다.

728x90

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

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

책에서는 갑자기 170mm 간격으로 점 D를 배치하라고 하는데 왜 그 수치가 나오는지에 대한 설명이 없습니다. 

앞뒤내용을 열심히 살펴보고 비례에 맞춰 적당한 간격을 설정해 주었습니다. 

 

4.5도와 13.5도를 이루는 삼각형은 변의 길이가 1:3 인데 이 비율을 맞춰 적당히 그려주었습니다. 

이 부분의 세세한 수치는 변화될 수 있을 것 같습니다. 

 

삼각형의 왼쪽 점이 롤러 쥬얼의 중심점이 됩니다. 

 

 

 

 

롤러 쥬얼의 지름은 점 B와 점 D의 거리 를 21로 나눈 값입니다. 

 

 

 

 

 

 

 

 

롤러 쥬얼의 바깥쪽을 이루는 원의 지름은.. 책에서 지정한 수치는 있지만 왜 그렇게 되는지에 대한 설명은 없군요.

그냥 보기에 적당한 사이즈로 안쪽 원의 1.05배가 되는 크기로 그렸습니다. 

 

 

 

 

 

 

포크 슬롯의 측면이 될 선을 그려줍니다. 

롤러 쥬얼의 중심선과 평행이 되면서 롤러 주얼에 접하는 선(19, 20)을 양쪽으로 그려줍니다. 

그리고 그 선과 수직의 선(21)을 적당한 간격으로 그려줍니다. 이 선은 포크 슬롯의 바닥이 됩니다. 

 

 

 

 

 

 

 

포크 슬롯의 바닥과 롤러 쥬얼 원과의 간격은 롤러 쥬얼의 1/3으로 정했습니다. 

 

 

 

 

 

 

 

 

선 18과 선22의 교차점을 중심으로 롤러 주얼 지름의 3배가 되는 원을 긋습니다. 

 

 

 

 

 

 

 

 

 

 

 

빨간색으로 그어진 부분은 포크 혼의 왼쪽 부분이 됩니다. 

반대쪽 선을 긋기 위해 점 C를 중심으로 점 D를 통과하는 호를 긋습니다. 

 

 

 

 

 

 

 

 

반대쪽 호를 그리기 위해 선 12을 연장하여 위에서 그린 호와 교차되는 점을 중심으로 점 D를 통과하는 작은 원을 그립니다. 

그러면 그 원과 호가 교차하는 좌측 점(붉은색)을 그릴 수 있습니다. 

 

 

 

 

 

 

이제 이 점을 중심으로 원 18과 같은 지름의 원을 그립니다. 이 원의 일부가 오른쪽 포크 혼이 됩니다. 

 

 

 

 

 

 

불필요한 선들을 한번 정리합니다.

 

 

 

 

 

 

안전 롤러를 그립니다. 점D를 중심으로 원 15의 1/3 지름으로 그려줍니다. 

이를 원 25라 합니다. 

 

 

 

 

 

 

 

 

안전 롤러와 점D 와 쥬얼 롤러를 잇는 선의 교차점(붉은색)을 중심으로 통과 구멍을 그립니다. 

지름은 쥬얼 롤러의 1.3배로 했습니다. 

 

 

 

 

 

 

 

선 12와 원 25의 교차점(붉은색)을 찾습니다.

 

 

 

 

 

 

 

 

이 점에서 시작하고 선 12와 25도 각도가 되는 화살표를 그립니다.

이것이 가드 핀이 됩니다. 

 

 

 

여기까지 했다면 기본적인 설계는 모두 끝났습니다. 

 

728x90

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

두번째 설계한 탈진기 테스트  (0) 2024.04.16
새 탈진기 설계와 조정.  (0) 2024.04.04
탈진기 첫 테스트.  (0) 2024.03.01
팔레트 설계  (0) 2024.02.25
이스케이프 휠 설계  (2) 2024.02.25
728x90

앞서 그린 이스케이프 휠의 스케치를 그대로 사용합니다. 

 

 

 

 

첫번째 스케치에서 사용했던 원과 선들을 전사해서 세번째 스케치를 그렸습니다. 

이제 글자의 색으로 선과 점, 원을 구분하지 않습니다. 별로 도움되지 않더군요.

                                                                

 

 

 

 

 

 

 

 

원 Q, 원 J가 교차하는 점을 통과하는 선 1을 그리고

원 G, 원 P가 교차하는 점을 통과하는 선 2를 그립니다. 

 

 

 

 

 

C에서 출발하여 같은 점을 통과하는 선 3,4를 그립니다.

 

 

 

 

 

선 4에서 4도 위로 선5를 그립니다. 

원 Q와 선 5의 교차점과 원G와 선 4의 교차점을 선으로 잇습니다.

 

이 선이 배출 스톤의 임펄스면이 됩니다. 

 

 

 

 

 

 

 

선 L과 원 G의 교차점과 선 M과 원 Q의 교차점을 선으로 잇습니다. 

이 선이 진입 스톤의 임펄스면이 됩니다. 

 

 

 

 

 

임펄스면의 뒤쪽 선을 시작으로 선 L과 수직하는 선을 긋습니다.

 

 

 

 

 

 

 

이 직각선에서 14도를 이루는 선을 긋고 스톤을 이루는 선을 마무리합니다. 

14도는 스톤의 잠금각입니다. 

 

 

 

 

 

마찬가지로 반대쪽에서도 직각을 이루는 선을 그리고 14도를 이루는 선으로 스톤을 그립니다. 

 

 

 

 

728x90

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

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

개인기록용.
https://www.amazon.com/gp/product/B0CL19RG2P/ref=ppx_yo_dt_b_d_asin_title_o01?ie=UTF8&psc=1

위 책의 내용을 참조로 함.

 

 

 

 

 

 

직선은 파란색, 점은 빨간색으로 표기

 

점 B를 중심으로 하는 선 AA를 그리고, 위쪽 점 C를 찍습니다

B를 중심으로 시계 반대 방향으로 30도를 지나는 선을 그리고 끝점을 E로 정합니다.

다시 E에서 3도를 지나는 선을 그리고 끝점을 F로 정합니다.

 

30도인 이유는 책의 SEC 432-433에 설명되어 있습니다

3도인 이유는 SEC 434에 설명되어 있습니다. 

 

 

 

 

 

 

점C를 중심으로 선 FB에 접하는 원 G를 그립니다. 

C에서 원 G와 선 F의 교차점에 선 H를 그립니다. 

이 선은 자동적으로 선 F와 직각을 이룹니다. 

B를 중심으로 이 교차점을 통과하는 원 J를 그립니다. 

 

 

 

 

점 F에서 좌측으로 4.5도(SEC.432)에 선 K를 그립니다. 

이제 잠금의 양을 결정할 것인데, 안전과 일관되게 가능한 한 가벼워야 하며 3/4도(0.75도) 정도가 적당합니다.

선 H의 아래로 0.75도에 선 L을 그립니다. 

이 선이 F선과 교차하는 지점(사진상의 붉은 점)이 팔레트 스톤의 잠금 모서리를 표시합니다.

 

 

 

 

 

선 L 보다 5도 아래에 M선을 그리고 H 선보다 3.5도 위에 N 선을 그립니다. 

선 F 보다 6도 오른쪽으로 선 O를 그립니다. 

점 B를 중심으로 선 N과 선 O를 교차하는 점을 통과하는 원 P를 그립니다. 

 

 

 

 

 

 

치아의 임펄스 면(붉은색 선)은 원 P와 선 K의 교차점에서 선 H와 선 F의 교차점까지 선을 그려서 형성합니다. 

이 선이 치아의 임펄스 면이 됩니다.

 

 

 

 

 

 

편의를 위해 스케치를 마무리하고 새 스케치를 그립니다.

 

 

 

 

 

 

 

앞서 그린 임펄스 면을 형성한 선을 새 스케치에 따라 그립니다. 

 

 

 

 

 

중심점 B를 중심으로 스케치 패턴을 15회 반복합니다.

 

 

 

 

임펄스 면을 이은 선과 직선이 되는 선을 몇개 그리고 그 선의 내접원 S를 그립니다.

 

 

 

 

 

임펄스 면의 오른쪽 점에서 시작하고 선 FB 와 28도 각도를 이루는 선을 긋습니다. 

휠 톱니의 잠금 각도입니다. 

 

 

 

 

 

 

휠 외부 테두리를 그립니다. 휠 지름의 80% 수준으로 잡았습니다. 

 

 

 

 

 

앞서 그린 선을 원형 패턴하여 복사합니다. 

 

 

 

 

 

 

첫번째 스케치에서 그렸던 원 J 와 원 P 의 중간에 원 W를 그립니다. 

 

 

 

 

 

 

점 B에서 출발해서 임펄스 면의 뒤쪽을 통과하는 방사선을 긋습니다. 

원  W 의 바깥쪽으로 그어진 선 부분(빨간색)이 치아의 발가락 부분이 됩니다. 

이 선도 점 B를 중심으로 패턴합니다. 

 

 

 

 

 

 

앞서 그어진 선에서 연장되는 선을 긋습니다. 

 

 

 

 

 

 

 

이 선을 원형 패턴합니다.

 

 

 

 

내접원을 그립니다. 원 V 라 합니다. 

 

 

 

 

 

 

 

이스케이프 휠 지름의 1.3배인 원을 그리고 원 DD 라 합니다. 

이스케이프 지름의 0.95배인 원을 그리고  원 Y 라 합니다. 

 

 

 

 

 

 

 

톱니의 아래쪽 모서리에서 원 V에 접하는 선을 긋습니다. 이 선이 톱니의 아래쪽을 만드는 선이 됩니다. 

 

 

 

 

 

원 Y와의 교차점을 중심으로 , 원DD와 휠 림 바깥쪽의 차이만큼의 거리(그림에서 7.5mm)를 반지름으로 하는 호를 긋고 원 DD와의 교차점을 표시합니다. 

 

 

 

 

7.5mm 를 설명하는 거리

 

 

 

 

 

위의 교차점에서 같은 거리(7.5mm)를 반지름으로 하는 호를 톱니의 뒤쪽에서 휠의 바깥쪽을 접하도록 그립니다. 

 

 

 

 

선을 정리하고 패턴하여 마무리합니다. 

 

 

 

 

 

728x90

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

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

태엽으로 돌아가는 작은 기구를 유튜브에서 보게 되었습니다. 

https://www.youtube.com/watch?v=NiyUUhnBaiI&t=589s

 

그 아이디어에 반해서 한번 만들어 보고 싶어졌습니다. 

태엽 구동에 관한 자료를 보고 있자니 속도 제어를 위한 기구가 필요하더군요.

여러 방법이 있지만 '탈진기' 라고 불리는 흔히 기계식 시계에 들어가는 구조를 써보고 싶었습니다. 

 

 

 

 

 

 

시계에 들어가는 탈진기의 종류는 여러 가지가 있지만 최근의 시계에는 거의 스위스식 레버 탈진기가 들어갑니다. 

이 설계를 바탕으로 제조사마다 조금씩 업그레이드시킨 다른 설계가 들어가기도 합니다. 

 

 

문제는 이 설계에 관한 자료를 찾기가 거의 불가능에 가까웠단 것입니다. 

기본적으로 이런 기계설계에 관한 이론은 인터넷이 발명되기 수십 년 전에 대부분 완성되어 있습니다.

그렇다 보니 기본적으로는 인터넷에 올라와 있지 않습니다. 

그래도 사람들이 많이 찾는 자료라면 정리된 자료가 인터넷에 올라올 수 있습니다만 이건 그런 자료도 아니죠.

 

 

 

 

 

 

그나마 찾은 자료는 이런 식이었습니다. 1884년에 출간된 책의 스캔본.

 

 

 

 

 

꽤 괜찮은 자료가 있는, 유일하게 인터넷에서 찾을 수 있었던 사이트.

https://www.abbeyclock.com/TToc.htm

 

Book: Clock and Watch Escapement Mechanics

 

www.abbeyclock.com

3D 프린터로 탈진기를 제작한 사람들은 이 사이트를 참조한 경우가 많더군요.

 

 

그럭저럭 괜찮았지만 이론적 배경을 중심으로 설명하는 자세한 내용이 없고 그냥 수치를 정해놓은 경우가 많아 좀 아쉬웠습니다. 

 

 

 

그래서 아마존을 뒤지기 시작했습니다. 

 

 

오래된 자료들이라 당연히 전자책도 아닙니다.

책 내용을 알 수 없어 대충 목차와 리뷰만 보고 구입할 수 밖에 없었습니다. 

책값도 비싸지만 배송비도 비싸서 타격이 컸습니다.

 

 

 

 

 

 

 

복불복이긴 했지만 2권은 실패.. 내용이 있긴 한데 엄청 자세하진 않습니다. 

한권은 설계보다는 수리와 정비에 관한 내용이 더 많았고요.

 

 

 

 

 

제일 괜찮았던 건 이 책입니다. 

시계학교의 학생들을 위한 교본이라 이론적 배경부터 설계에 관한 내용이 자세히 들어 있습니다.

하지만 전자책 버전이긴 한데 스캔본이라 보기가 매우 불편합니다. 

 

 

그래서 지난번 포스팅 https://pashiran.tistory.com/1336

 

아마존의 영문 책을 빠르게 번역해서 보기.

https://www.amazon.com/b/ref=sxts_snpl_2_1_8ff1fd52-a1ba-4875-b6ef-624553f0f5b8?node=16571048011&pf_rd_p=8ff1fd52-a1ba-4875-b6ef-624553f0f5b8&pf_rd_r=WFHA2CTYGS2R73CZGNAD&pd_rd_wg=uIFOZ&pd_rd_w=4pJu7&content-id=amzn1.sym.8ff1fd52-a1ba-4875-b6ef-624553f0f5b

pashiran.tistory.com

에 있던 내용내로 DRM을 해제해서 PDF로 변환한 뒤 출력해서 사용했습니다. 

 

 

 

 

 

 

 

 

영문 그대로 읽는 건 불가능하진 않지만 내용이 많아서 번역기를 사용했습니다. 

요즘은 이미지 인식 OCR 과 AI 번역 툴이 매우 훌륭해져서 좋네요.

OCR은 일일이 스크린샷을 떠서 ChatGPT에 OCR 인식을 시켰고 deepL 번역기를 사용했습니다. 

 

728x90
728x90

이제 완성도를 높이기 위한 작업중입니다. 

시제품에서 완제품 단계로 넘어간다고나 할까요. 

 

OLED 모듈이 튀어나와 있기 때문에 설계시 걸리는 부분이 있는데요. 

이걸 어떻게 할 수 없을까 하고 검색하다 보니 드라이버 회로가 보이더군요.

 

 

 

생각보다 간단한 구성회로에 온보드로 넣기로 합니다. 

 

 

 

 

 

 

기존 회로는 부품이 전부 전면 배치였기 때문에 일부를 뒷면으로 옮기고 잘 정리하니 기존 PCB 사이즈에서 전부 집어넣을 수 있었습니다. 

 

 

 

PCB와 부품들 주문하고 기다리는 중입니다. 

도착하면 납땜하고 테스트하고 다시 3D 설계 수정하고 프로그램 마무리할 계획이고요

메이커페어 나가느라 서둘러 급하게 마감했던 물건들 처리하는데만 몇달은 걸리겠네요

 

 

 

 

728x90
728x90

https://jlcpcb.com/KOR

 

SMT PCB어셈블리 3D프린팅 - JLCPCB

JLCPCB, 더 빠른 PCB & SMT 어셈블리를 위한 것이다 모든 단계에서 시간과 비용 절감한다. 클릭하시면 동영상을 볼 수 있습니다.

jlcpcb.com

이 포스팅은 JLCPCB의 협조로 제작되었습니다. 

 

 

 

자석식 커넥터로 테스트한 모델이 잘 구현되었기에 본격적으로 PCB를 제작하기로 했습니다. 

EASYEDA 에서 PCB를 설계했습니다. 

 

 

부품 배치 시 CAD 프로그램처럼 편리하지는 않기 때문에 부품의 위치나 간격 등은 손으로 계산해서 입력해야 합니다. 

즉 XY 좌표 (50,0) 에 있는 부품을 60도 회전시켜 배치하고 싶으면 삼각함수를 써서 계산해야 합니다. 

하지만 CAD 프로그램에서 수치를 입력하고 그냥 결과를 따면 훨씬 편하죠. 

EASYEDA에서도 같은 작업을 할 수 있는 플러그인이 있을 것도 같긴 한데 저는 그냥 손에 잡히는 솔리드웍스를 썼습니다.

 

 

 

 

https://jlcpcb.com/KOR

 

SMT PCB어셈블리 3D프린팅 - JLCPCB

JLCPCB, 더 빠른 PCB & SMT 어셈블리를 위한 것이다 모든 단계에서 시간과 비용 절감한다. 클릭하시면 동영상을 볼 수 있습니다.

jlcpcb.com

이번에도 JLCPCB에 주문을 넣었습니다. 

 

 

다만 이렇게 생성된 거버 파일을 올려보면 미리보기에서 이상한 결과가 나옵니다. 

 

 

 

 

 

 

다시 확인해봤지만 뷰어의 문제인 것 같아 일단 제작은 하되 생산전에 컨펌해달라는 옵션을 넣었습니다. 

 

 

 

 

 

 

 

마찰이 계속되며 접점을 오래 유지해야 하므로 ENIG(electroless nickel immersion gold) 옵션을 넣었습니다. 

금도금이죠. 가격은 좀 많이 올라갑니다. 

 

 

 

 

 

 

 

주문 후 추가비용 결재와 관련해서 메일이 왔습니다.

위에 미리보기에서 이상하게 나온다고 했는데 엔지니어가 다 잘 맞게 수정했고 그에 따라 추가비용이 발생했으니 결재해야 한다는 내용이었습니다. 결재 후 컨펌하고 곧바로 제작이 시작되었습니다. 

 

 

 

 

 

 

똑같아 보이지만 앞뒷면입니다.

 

 

 

 

 

 

원래 배터리 접촉 용도로 쓰는 4핀 커넥터를 사용했습니다. 

 

 

 

 

 

 

 

 

접촉 후 저항 측정해보니 0.3옴 정도 나오는군요. 

접촉유지는 상당히 괜찮아서 구지 심하게 누르지 않아도 괜찮을 것 같네요

 

728x90

'Making > USB 오토릴' 카테고리의 다른 글

USB 오토릴 #1 - 구상.  (1) 2023.01.01
728x90

튜닝만 하면 마무리되는 물건이지만, 메이커페어에 들고나갈 생각을 하니 좀 더 손보고 싶어지더군요

달려있던 모터 하나가 축이 휘어져서 밸런스 돌릴때마다 이상하게 비틀거리기도 했고 자이로 휠도 바꾸고 싶어져서 

손보던 김에 전면 재설계에 들어갔습니다. 

 

 

 

원본의 조립방식을 바꿔본다고 손댔던 지난번 설계는 정작 조립해보니 별로 낫지도 않더군요. 

이번에는 모서리에서 45도 각도로 태핑나사로 조립하는 방식입니다. 훨씬 깔끔하고 편하군요.

 

 

 

 

 

 

 

모서리가 칼같이 잘 맞아들어갑니다. 

 

 

 

 

 

하는김에 PCB도 설계.

원래 EagleCad를 썼지만 Fusion360에 통합되고 나서는 업데이트도 잘 안되고 쓰기가 영 불편하더군요

그래서 EasyEDA로 바꿔봤습니다. 

JLCPCB / LCSC 회사의 소프트웨어인데 프로그램 자체는 이글보다 낫진 않습니다. 

하지만 일반적인 양면 PCB 설계하기엔 충분하고요.

무엇보다 LCSC에서 공급하는 부품을 전부 그대로 사용할 수 있어 라이브러리 면에서 대적할 자가 없네요. 

 

설계를 마치면 JLCPCB에서 주문하면서 LCSC에서 부품주문도 동시에 할 수 있는 시스템이라

몇만원에 납땜까지 완성된 PCB를 그대로 받아 볼 수 있습니다. 

조만간 다른 프로젝트 PCB 주문할때 같이 하려고 일단은 묵혀 두는 중입니다. 

 

 

------------------------------------추가--------------------------------------------------------
이번에 PCB주문하면서 부품주문도 같이 하려했더니 안되더군요. 
검색해보니 세금신고관련 문제로 합배송이 안되게 바뀌었다네요. 

 

728x90
728x90

메이커페어에 참가신청도 했겠다 이제 열심히 완성시키려고 하는 중입니다. 

그런데 이상하게 자꾸 아두이노 스케치 업로드가 안됩니다.

 

윈도우 11로 올린 지 얼마 되지 않았는데 이것때문인지 아니면 드라이버 문제인지 모르겠더군요.

드라이버를 계속 다시 재설치해보고 최신 드라이버 설치도 해보고 아두이노 나노와 프로 미니를 번갈아 가며 테스트해봤습니다. 

시리얼 칩 중 중국산 CH340은 드라이버 문제가 간간이 발생하기에 일부러 최신버전과 구버전도 다 테스트해봤습니다. 

그런데도 여전히 문제를 찾기 힘들어 시간내서 다시 Win10으로 다운그레이드도 했습니다. 

 

그래도 여전히 안됩니다.

 

 

 

 

 

컴퓨터를 포맷까지 했는데 안되길래 이제 아예 노트북을 써야 하나 고민하던 중에

혹시나 하고 시리얼 모니터를 꺼봤습니다. 

그랬더니 잘 되네요.....

 

 

Arduino IDE 1.8.0 이전 버전들은 시리얼 모니터와 상관없이 프로그램 업로드가 됐는데

오히려 최신 버전인 2.1.0에서 이런 황당한 문제가 있었네요.

덕분에 이틀간 시간만 날렸습니다. 

 

 

 

 

그리고 나서도 엔코더 로터리가 작동이 이상해서 체크해봤더니 B상(하늘색)이 안들어옵니다. 

 

 

 

 

 

회로를 점검해봤더니 메인보드와 스위치 보드에 둘다 풀업저항이 달려있었네요. 

이건 큰 문제는 아닌데 일단 한쪽을 제거했습니다. 

그리고 두번째로는 스위치 보드의 풀업저항이 연결이 안되어있었습니다. 

굉장히 오래전에 만든 회로인데 만들때 실수해놓고도 모르고 그냥 갖고 있었네요

 

 

 

 

 

 

하여간 납땜해서 풀업 연결하고 확인하니 제대로 작동하는군요

 

 

 

 

 

테스트 코드에도 문제없이 값을 출력합니다. 

728x90
728x90

어느날 집에 있는 지퍼백을 쓰는데 크기가 애매하게 커서 한쪽을 접착하고 잘라냈으면 좋겠더군요.

이럴 때 쓰는 물건이 비닐 실링기죠. 

 

 

이런 소형 실링기를 써 보신 분은 알겠지만 이 물건은 쓰레기입니다. 

 

 

 

 

 

 

이런 실링기는 성능도 좋고 비닐이 잘 접착되지만 덩치가 크고 접합하고자 하는 비닐이 기계보다 크면 쓰기가 애매하죠

 

 

 

 

차라리 열선을 바퀴처럼 둥글게 말아 굴리면서 쓰면 아무리 긴 비닐도 접착이 가능하지 않을까? 하는 생각이 들었습니다.

 

프로토타입을 만들어봤습니다. 

2T 내열 실리콘판과 0.1T 2mm 니크롬 리본입니다. 

 

 

 

 

 

 

니크롬 리본은 살짝 엇갈리게 배치해서 위와 같이 내부로 들어갑니다. 

 

 

 

 

 

 

 

 

 

 

내열성이 있는 PTFE 테이프로 위를 감싸줍니다. 

실제 실링기도 이런 구조로 되어 있습니다. 

 

 

 

 

 

 

니크롬선은 납땜이 되지 않기 때문에 스팟 용접이나 클램프로 연결해줘야 합니다. 

 

 

 

 

 

 

 

 

7~80도 쯤에서 비닐이 녹는 것 같아서 그정도 온도로 세팅해 봤더니 접합이 안 되더군요

 

 

 

 

 

 

 

 

110~120도 정도로 만들어 보니 접합이 잘 됩니다. 

 

 

 

프로토타입으로 성공 가능성을 체크해 봤으니 설계를 구체화해봐야겠습니다. 

 

728x90
728x90

https://youtu.be/tIuX01ikdrY

 

 

전원을 켜고 손으로 중심을 잡은 채로 유지하면 3축 순서대로 삐-삐-삐 소리가 3번 납니다.

이후 '삐삐' 소리가 나면 작동이 시작되고 손을 떼면 모터가 자동으로 움직이며 자세를 잡습니다. 

뾰족한 꼭지점을 대고 설 수 있지만 아직 완성이 되지 않은 관계로 그렇게 설 수는 없습니다.

부팅시 영상처럼 모서리를 대고 1축만 사용하면 자동으로 1축만 이용해서 자세를 잡도록 되어 있습니다. 

 

 

 

 

처음 조립시에는 거의 서질 못해서 현재는 각 휠의 무게를 늘려 놓은 상태입니다. 

18650* 3개로 조립을 했는데 전압도 좀 부족한 것 같아 전선을 연결해 15~16V 정도로 테스트했더니 그나마 위의 영상처럼 서기 시작했습니다.

튜닝을 좀 해야 하는데 생각같아서는 설계를 처음부터 다시 좀 다듬을까 싶기도 해서 약간 고민이네요. 

728x90
728x90

하드웨어 테스트는 끝났으니 이제 소프트웨어를 시작해 봅니다. 

조립하고 USB 케이블을 연결했습니다

 

 

 

 

 

 

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

제작자가 이 동영상 8:29 부터 코드에 대해 설명하고 있습니다

 

 

 

**맨 아래 [변경사항]을 확인하고 읽어주세요. **

동영상의 코드 설명은 여기에 있는 코드와 다른 부분이 있습니다.

 

 

보드 세팅은 ESP32 Dev Module로 하면 됩니다

 

 

 

 

 

1. 전압 세팅

 

처음은 전압 세팅을 조정하라는군요.

funtions.ino의 129번 라인의 Serial.print의 주석을 지워줍니다. 

 

 

 

 

 

 

그리고 코드를 업로드후 시리얼 모니터에서 115200보드레이트로 설정하면 전압 측정결과가 나옵니다. 

 

 

 

 

 

 

 

실제 측정결과는 11.68v 인데 15.45v 정도가 나왔으므로 오차가 심하군요.

 

 

기본값은 ESP32_cube.ino의 105번 라인에

battVoltage((double)analogRead(VBAT) / 207)

이렇게 207로 되어 있으므로 보정해 줘야 합니다. 

 

 

analogRead / 207 = 15.45 (시리얼 출력값)

analogRead / X = 11.68 (실제 출력값)

 

즉 analogRead = 15.45*207

15.45*207 / 11.68 = X 가 되겠네요

계산하면 X = 274 가 됩니다. 

 

이렇게 해도 낮은 전압에선 오차가 또 나게 되는데 저는 낮은 전압 기준으로 맞췄습니다. 

그래서 263 을 집어넣었습니다. 

 

 

 

 

 

2. 가속도계 튜닝

 

 

시작부터 제작자 설명과 다른 부분이 약간 있습니다. 

제가 받은 코드에는 SerialBT.print로 시작되는 두 줄 중에서 위쪽의 robot_angleX 를 출력하는 부분이 없더군요,.

해당 부분 코드를 작성해 주었습니다. 

그리고 아래쪽에도 주석을 추가합니다.

 

 

 

 

추가로 비프음이 그치지 않아 확인해 보니 BUZZER 의 HIGH/LOW가 반대로 되어 있어서 전부 고쳐주었습니다. 

 

 

 

 

 

 

동영상에서는 코드의 일부 주석을 제거 후 업로드 후 블루투스로 연결하라고 합니다

 

 

 

 

 

 

블루투스를 검색해 보면 ESP32-Cube-blue가 뜹니다.

 

 

 

 

 

블루투스를 추가하고 시리얼 포트를 보면 원래 연결되었던 COM16 외에도

COM17과 COM18이 추가된 것을 볼 수 있습니다. 

 

 

 

 

 

 

 

처음에는 꼭지점으로 균형을 잡도록 세워주고, 이때 터미널의 센서값을 확인했습니다.

근데 이러면 안 되더군요

무게중심을 잡은 채로의 센서값을 체크해야 합니다.

그냥 45도로 세워놓는다고 무게중심이 완벽하게 잡히진 않습니다.

때문에 손으로 세밀하게 잡고 움직이지 않도록 주의하면서 센서값을 체크합니다. 

 

 

 

 

 

 

 

 

 

 

되도록이면 평균값을 구하는 게 좋겠죠?

값을 전부 더한 다음 항목수로 나누면 되겠네요

 

 

 

 

 

 

 

 

 

 

인공지능의 힘을 빌려봅니다. 
자료를 너무 많이 넣으면 해석을 못 한다고 징징대길래 많이 줄였더니 금방 평균값을 알려주네요

하지만 수기로 다시 계산해보니 값이 틀렸더라고요;;

한 10개 이하로 줄였더니 정확하게 계산해 줍니다. 

 

 

 

 

 

동영상 대로ESP32.h에 offset값을 입력하려고 하니 아예 코드 자체가 다른 부분이 또 있네요

동영상을 만든 후 코드를 수정한 것 같은데 우측의 X1, Y1에 offsetX, offsetY를 입력했습니다. 

이후에도 약간식 다른 부분이 있어서 제대로 유튜브 설명을 따라하기 힘들었습니다. 

 

 

 

 

 

 

 

 

[변경사항]

 

코드를 계속 수정해 보다가 그냥 동영상에서 나왔던 코드를 찾기로 합니다. 

기존 커밋을 클릭해서 확인해 봤습니다. 

 

 

 

 

 

 

확인해 보니 2022년 7월 12일 이전 코드인 것 같더군요.

browse를 눌러 예전 소스를 다시 다운받고 이걸 사용하기로 했습니다. 

 

 

 

728x90
728x90

 

다시 한번 말하지만 저는 ESP8266 보드를 사용하는 관계로 
https://www.instructables.com/Get-Started-With-ESP8266-NodeMCU-Lolin-V3/

 

Get Started With ESP8266 (NodeMCU Lolin V3)

Get Started With ESP8266 (NodeMCU Lolin V3): Component Required: ESP8266 (NodeMCU Lolin V3) Micro USB Arduino IDE Internet connection NodeMCU lolin V3 Feature: Open-source Status LED MicroUSB port Interactive and Programmable Low cost ESP8266 with inbuilt

www.instructables.com

이 링크를 참조해 스케치를 업로드 해야 합니다 .

 

 

 

 

일단 핀 번호만 수정한 스케치를 올려 보면 위와 같이 BluetoothSerial.h 가 없다는 에러가 나옵니다. 

 

 

코드를 훑어보니 ESP32.h에서 블루투스시리얼로 기본튜닝을 하게 되어있더군요.

그리고 제가 사용한 ESP3266은 블루투스가 없습니다;;

결국 원본대로 다시 제작하기로 합니다. 

 

국내 판매가가 2배 가까이 비싸서 알리산으로 구매했습니다. 

도착하면 납땜부터 전부 다시 해야겠네요.

이런 뻘짓을 하지 않으려면 코드부터 잘 확인해야 겠습니다.

 

 

 

 

 

새 보드를 만듭니다. 

 

 

 

 

 

 

 

충동적으로 원작자 설계와 다르게 가속도계를 밑으로 넣어버렸는데요. 

확신없이 그냥 저질렀는데 괜찮을 지 모르겠습니다. 

 

 

 

 

 

 

일단은 납땜 완료. 

 

 

 

 

 

 

 

 

제작자는 친절하게도 모터 테스트 스케치를 준비해 뒀습니다.

올려보니 모터가 1개밖에 안 도는군요. 

 

 

 

 

 

제가 납땜 실수한 게 하나 있었고, 케이블 불량이 하나 있었습니다.  

 

 

 

 

 

 

 

수리하고 나니 잘 돌기 시작합니다. 

728x90
728x90

일단 제작자와 다른 보드를 사용했기 때문에 모든 선을 체크해가면서 조심히 납땜합니다. 

 

 

 

 

 

 

이 회로에서 제작자가 설명해 놓지 않은 부분이라 첨언을 하면
회로도에서 피에조 스피커는 '능동형 부저' 타잎입니다. 

전원만 인가하면 소리가 나는 물건이죠. 

스위치 회로로 PNP 트랜지스터를 사용하는데 일반 범용 PNP면 아무거나 가능합니다만

핀 순서가 맞는지 확인하고 납땜해야 합니다. 

제작자는 ECB 형식으로 회로도를 그려 놨습니다만

제가 사용한 2N2907은 EBC 순서라서 그에 맞춰 연결했습니다. 

 

 

 

 

배터리는 제작자가 3S 1P 리튬이온 배터리를 사용했다고 하니 

일반적인 리튬이온 배터리를 3직렬 연결해서 사용하면 됩니다. 

저는 18650 3개를 쓸 생각입니다.

 

 

 

 

 

바꾼 보드에 맞춰 코드도 수정을 해 줍니다. 

미리 잘 메모해두거나 미리미리 수정하지 않으면 나중에 낭패를 보게 됩니다. 

 

 

 

 

 

 

 

배선이 끝나면 배터리 홀더도 납땜해 줍니다. 

배터리 홀더가 배선을 덮어버리기에 차후 수정이 힘들어지므로 테스터로 일일이 연결을 확인해 두었습니다. 

 

 

 

 

 

 

 

 

생각해보니 전원 LED가 있어야 할 것 같아 추가했습니다. 

 

 

 

 

 

 

 

임시로 조립해봤습니다. 

설계할 때 실수했는지 조립하는 볼트 구멍 하나의 간격이 맞지 않아서 갈아내서 맞췄습니다. 

 

 

 

 

 

 

 

모터 커넥터와 간섭이 있어서 출력물도 일부 잘라냈습니다. 

 

 

 

 

 

 

 

실수가 있었네요.

모터 커넥터를 모터 반대쪽으로 납땜했습니다. 

그냥 연결해도 큰 문제는 없습니다. 

 

 

 

 

 

 

 

모터 커넥터 작업을 합니다. 

 

 

 

 

 

 

 

 

 

핀 번호는 왼쪽부터 1번입니다. 

 

 

 

 

 

 

 

 

 

 

 

커넥터를 반대면에 납땜하는 바람에 끼우기는 좀 불편하네요.

 

 

 

 

 

 

 

조립된 모습은 위와 같습니다. 한 변의 길이가 157mm 인 정육면체입니다. 

728x90

+ Recent posts