가장 먼저 내가 헤드셋을 사용하는 목적은, 업무할 때 통화용이고, 운동할 때 유튜브 청취용이다. 음악 감상 목적은 아니기 때문에 음질에 대한 깊은 비교는 없다. 

 

업무할 때 통화를 하면서 컴퓨터를 확인해야할 경우가 많기 때문에, 꼭 그렇지 않더라도 두 손을 자유롭게 해주는 헤드셋은 업무 효율성을 높여준다고 생각한다. 

 

일반적인  블루투스 이어폰을 쓰다가 항상 휴대해야 하는 불편함 때문에, Huawei 토크밴드B6를 알게되고 이것을 정말 잘써왔다. (이건 지금도 강추이고, 후속 모델이 없는게 너무 아쉽다.)

https://mrkool.tistory.com/56

 

Huawei 토크밴드B6 , 한 달 사용기

한 줄 평 : 이게 바로 실용적인 스마트 기기다!! 조깅할 때 거리측정의 목적으로 헬스밴드를 찾게 된다. 샤오미 미밴드의 엄청난 가격에 놀라서 구매를 했으나, 아... 싼 이유가 있구나.... 미밴드

mrkool.tistory.com

별도로 운동할 때에는 일반적인 블루투스 이어폰을 썼는데, 어느날 골전도 이어폰이라는 것을 알게되고 급 뽐뿌를 받는다.

더욱이 최근에는 온라인 회의가 많이 생겨서 헤드셋이 더욱 필요해졌는데, 귀를 막지 않아서 다른 소리도 들을 수 있다는 점이 매력적이라고 생각했다.

그래서 급기야 세 종류의 골전도 이어폰을 주르륵 사버리게 된다. 

그래서, 오늘 비교할 제품은, 아남 NO9, 로이체 BCE-300, 피스넷 Always이다.

아남 NO9은 방출해서 사진에 없다.

 

일단 골전도 이어폰의 장점은, 귀를 틀어막지 않기 때문에, 외부의 소리를 들을 수 있고, 귀를 막고 있는 답답함이 없다는 점이다.

그래서, 운동용으로 1차 아남 NO9을 샀다가, 이왕 산거 업무용으로도 쓰려고 통화음질을 찾으려고 BCE-300을 거쳐서 피스넷 Always에 멈추게 된다.

 

>> 아남 NO9   (구매가 \50,900)

골전도 이어폰을 찾다가 '아남'이란 브랜드를 보고 별 고민 없이 바로 질렀다. 가격이 부담 없기도 하지만, 국내 대표 음향기기 제조사를 응원하고 싶은 마음이 컸다. 

그러나, 바로 실망해버린다. 전원을 켤 때 '전원이 켜졌습니다'라는 여자 음성이 귀가 아플 정도로 우렁차다. 짜증이 날 정도... 개발자가 써보지도 않고 출시를 했나...

음질이야 소리만 나면 됬다고 생각하는데, 방출의 결정적인 이유는, 통화용으로는 절대 쓸 수가 없었다. 

목 뒤로 돌아가는 기구물이 좀 딱딱하다 싶고, 그 힘으로 귀 주변을 '찝어준다'는 느낌으로 귀에 장착되서, 좀 오래 쓰고 있으면 편하지는 않다.

 

>> 로이체 BCE-300 (구매가 \99,000)

앞서 역시 싼 건 안되겠구나 하고, 좀 더 비싼 제품, 통화음질이 괜찮다는 평을 보고 구매했다.

목 뒤로 돌아가는 기구물이 좀 더 부드럽고, 그래서 귀 주변을 찝는다는 느낌보다는 귓바퀴에 얺혀진다는 느낌이어서 착용감은 더 좋다.

통화 음질도 더 좋아졌으나, 역시 상대방으로부터 잘 안들린다는 불만이 생겼다. 역시 마이크 한 개로는 안되는건가... (그런데, 화에이 토크밴드는 통화 품질도 좋았는데...)

 

>> 피스넷 Always (구매가 \89,000)

통화를 하려면 좀 더 비싼 제품으로 가거나 아예 전용 마이크가 있는 제품으로 가야하나 하다가, 

통화품질을 전면에 내세우는 제품 설명을 보고 선택했다. 그리고 이 제품은, 골전도 방식은 아니고, '오픈형 이어폰'이라고 하는데, 느낌으로 말하자면, 귀 입구에 작은 스피커를 설치한 느낌?

음질은 충분히 좋다. 그리고 통화 음질도 합격점이다. (음질 비교는 아래에서...)

귀에 각각 착용되니까, 일체형 골전도 제품의 와이어가 걸리적 거리는 문제는 없다. 그렇다고 물리적으로 부딪치지 않는 이상, 운동하다가 벗겨질 것 같지도 않다.

 

아남 NO9 통화음
로이체 BCE-300 통화음
피스넷 Always 통화음

 

주파집 TWS 통화음

 

 

 

동일한 음량으로 말했는데, 차이가 확 난다. (너무 차이가 있어서, 피스넷의 제품이 볼륨을 더 크게 설정됬나 하는 의심은 있다.)

현재까지 며칠 업무상 통화에 사용했는데, 상대방으로부터 큰 컴플레인은 없었다. 그래도 역시 폰으로 직접 통화하는 것만큼은 못한 거 같다.

그래 이정도면 됬지... 하고 만족하려는데, 큰 결점이 발견됬다. 멀티페어링이 안된다!!  (앞선 두 제품은 멀티 페어링이 되는데, 가장 최근 출시된 제품이 안되다니?!!??!) 원래 생각했던 건, 노트북과 휴대폰에 멀티페어링을 해놓고, 온라인회의와 전화통화를 동시에 해결하려는 생각이었는데...  피스넷 제품은 1:1 연결만 지원한다.  별 수 없이, 이 부분은 포기해야지. 여기에서 제품을 하나 더 살 수는 없고...

 

앞선 세 제품을 구매하는데 총25만원이 들었다. 이렇게 될 걸, 애초에 가장 유명한 Shokz 제품을 샀으면 한 방에 해결됬을걸 하는 생각이 든다. 그래도 나는 2등을 응원한다는 소심한 방향성은 있다.

 

최종적으로 로이체 제품은 집에서 운동용으로 사용하고, 피스넷 제품은 회사에서 업무용으로 사용하게 됬다.

 

로이체 APT X HD탑재 멀티페어링 방수 방진 골전도 블루투스 무선 이어폰, BCE-300, 블랙

 

강력한 통화품질 핸즈프리 오픈형 무선 블루투스 이어폰 피스넷 올웨이즈 / 골전도 대체, 블루투스이어폰 피스넷 올웨이즈

 

 

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

 

엑셀 실무에서 vlookup은 기본중에 기본인데 (요새는 xlookup으로 사용하자)

가끔씩 2개 이상의 조건에 맞는 값을 가져와야 할 때가 있다. 아래의 경우에서는, code, part number, customer, 이 3개의 조건에 맞는 값을 오른쪽 녹색 표에 가져오는 것이겠다.

뭐 사실 vlookup/xlookup으로도 해결할 수는 있다. 조건 열들을 하나로 합쳐서 그 합친 셀로 vlookup을 하면 되는데...

보다시피, 열이 늘어나고, 없는 값은 #n/a가 표시된다.

 

그러나, 파워피벗을 사용하게 되면, 함수 사용 없이 깔끔한 표가 완성된다.

과정은,

] 각각의 테이블을 '표'로 변환한다. 단축키 ctrl + t

] 먼저 가져올 자료인 녹색 테이블 위에서 '데이터' > '테이블 범위에서'를 눌러서  '파워쿼리'를 실행한다.

] 여기서는 할 일 없고, '파일' 탭을 눌러서 다시 닫아주는데, '닫기 및 다음으로 로드...'를 누르고, 다음 화면에서 '연결만 만들기'를 선택한다. 

  그냥 '닫기 및 로드'를 선택하면 별도의 시트가 생성되는데, 그럴 필요가 없으니...

] 이제 같은 방법으로, 기준이 되는 자료(파란색 표)에서 파워쿼리를 실행한다. ( '데이터' > '테이블 범위에서')

] 메뉴 중간에 있는 '쿼리 병합'을 누른다. 팝업 창에서 상단에는 현재의 표가 있고, 아래쪽에서는 아까 만들었던 표를 선택해서 가져온다.

  여기서 조건이 될 열들을 위 아래에서 각각 선택해주면 된다. 

  중간에 '조인 종류'라고 선택이 있는데, 기본 값이 우리가 vlookup에서 알고 있던 조건이므로 손대지 않는다.

] 이제 가져오려던 표가 몽땅 불러들여와졌다. 여기서 필요한 열만 선택한다. 나는 Revenue 2개 값만 선택했다. 

] 여기서도 조건에 맞는 값이 없던 셀들은 null이 나오는데, 상단의 '값 바꾸기'에서 0으로 바꿔준다. (이렇게 바꿔주면, 향후에 데이타가 추가되서 또 다른 null의 경우가 생기더라도 0으로 바꿔주는 놀라운 기능이다.)

] 이제 '닫기 및 로드'를 눌러주면 새로운 시트에 깔끔한 표가 완성된다.

  이후에 데이터가 추가되더라도, '모두 새로 고침' 버튼 한 번에 자료가 수정되는 행복을 느낄 수 있다.

 

 

 

 

한빛미디어 엑셀 피벗 파워 쿼리 바이블 - 엑셀 피벗과 파워 쿼리를 다루는 거의 모든 기능

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

제목으로 말이 이상한데... 이미 피벗테이블을 거쳐서 나온 데이터를 원래의 데이터로 돌린다는 말이다.

엑셀의 정식 표현은 '열 피벗 해제'이다.

아래와 같이 월별로 정리된 데이타를 다시 원래의 데이터로 돌린다는 의미이다.

 

원래 데이터는 애초에 오른쪽과 같이 만들어야 여러가지로 활용이 가능할텐데, 이미 왼쪽처럼 작성된 자료를 오른쪽처럼 회복(?) 시켜야 할 때, 엑셀의 '파워쿼리'가 손쉽게 해결해준다. 

 

] 먼저 원래의 데이터를 '표'로 지정해준다.  단축키 ctrl + t

] '데이터' > '테이블 범위에서'를 누르면  '파워쿼리'가 실행된다.

] 데이터의 중간중간에 null 값이 보이는데, 1월부터 6월까지 데이터 열을 전체 선택하고,  '홈' >'값 바꾸기'에서 null을 0으로 바꿔주자.  엑셀에서 '찾아 바꾸기'와 동일한 기능.

  null 값이면, 행을 열로 바꿀 때, null은 열로 바꾸지 않고 누락시킨다.

] 이제 null은 0으로 바꼈고, 아직 1월~6월이 선택되어 있을텐데, 이 부분이 행으로 바꾸고 싶은 부분이다.

 선택한 상태 그대로 두고, '변환'>'열 피벗 해제'를 누르면 우리가 기대했던 결과가 나온다.

] 이제 '홈'>'닫기 및 로드'를 선택하면, 별도의 시트에 결과 값을 얻을 수 있다. 

 

막상 결과를 얻고 나면, 별거 아니게 느껴지지만, 이게 실무에서 닥치면 상당히 난감한 일이다. 일일이 한 행 한 행에다가 개월 수 만큼 열을 삽입해서 값을 넣어준다??  말도 안되는 일이다.  (물론 애초에 데이터 형태를 잘 맞추면 일어나지 않을 일이다. ㅎ)

 

파워쿼리의 강력한 점은, 한 번 이렇게 작업을 정의해 놓으면 데이터가 추가되더라도 간단하게 처리된다는 점이다.

아래와 같이 추가 데이터를 붙여넣어도, '모두 새로 고침' 버튼 한 번에 자료가 수정된다.

9백만이었던 숫자가 데이터를 추가하고 10백만으로 고쳐지는 걸 볼 수 있다.

이번에는 자료에 수량만 있었지만, 수량과 금액이 있는 경우에는 어떻게할지 다음 포스팅에서...

 

 

엑셀 피벗&파워 쿼리 바이블:엑셀 피벗과 파워 쿼리를 다루는 거의 모든 기능

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

blender... 알면 알수록 굉장한 프로그램이다. 무료라서 더더욱 놀랍다.

 

충돌,낙하,유체의 흐름 등을 시뮬레이션 할 수 있다.

라이언이 쇠줄에 매달려서 블럭에 충돌하는 영상을 만들어봤다.

원래 내가 본 동영상은 동그란 원형물체이지만, 나는 라이언으로 바꿔봤다. 

이 정도의 영상을 10분이면 만들 수 있다는...  @_@

 

시뮬레이션에서는 각 큐브 한 개씩이 1kg이고, 쇠사슬의 사슬 하나의 무게는 4kg, 라이언의 무게는 자그마치 150kg이다. 이런 무게들까지 감안해서 충돌이 일어나고, 매달린 라이언의 무게가 너무 지나치면 쇠사슬이 끊어진다. 놀라운 시뮬레이션....

 

만들 때마다 채색이 아쉽다. 물체의 재질과 조명을 잘 설정해야하는데, 여기서 전문가와의 차이가 생긴다. 스킬은 비슷하게 쫓아할 수 있지만, 마지막의 차이를 만드는 감성의 부분은 쫓아가기 힘들다.

 

 

 

웨이드 초고속 진공 블렌더 믹서기

COUPANG

www.coupang.com

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

앞서 만들었던 오목에 자신감을 얻고 다음 프로젝트로 리버시를 만들기로 한다. 

 

Javascript 오목 게임 만들기

오목 게임. 아이들이랑 놀 겸해서 만들어봤다. 완성본은 아래에서... omog-geim.bryanko555.repl.co HTML,CSS는 별거 없고, 게임승리 이미지를 안보이게 넣어뒀다가 오목이 만들어졌을 때 나타나게 했다. 큰

mrkool.tistory.com

리버시 게임은, 돌을 놓아서 자기편의 돌 사이에 상대편의 돌이 끼어 있는 형태를 만들게 되면 따먹을 수 있는데, 단, 따먹은 돌은 없어지는 게 아니라 자기편의 돌로 변한 채로 그 자리에 있게 된다. 즉, 상대편의 돌을 뒤집어 자기편의 돌로 만드는 것이다.

완성된 게임은 아래에서...

https://sad-jennings-0ef849.netlify.app/

 

HTML,CSS는 별거 없고, 게임승리 이미지를 안보이게 넣어뒀다가 오목이 만들어졌을 때 나타나게 했다.

이번에는 P5.js를 사용했기 때문에, P5.js파일을 읽어와야 된다.

 

처음 시작할 때는 오목보다 쉽게 만들 수 있을 줄 알았다. 그런데, 두 배는 더 어렵게, 시간을 더 들여서 만들었다.

오목에서보다 더 고려해야 할 점이,

] 돌을 놓을 수 있는 곳이 제한되어 있다. 오목처럼 아무곳에나 둘 수 있는 것이 아니어서, 둘 수 있는 칸을 매번 계산해서 보여줘야 된다. (검정색,하얀색 조그만 사각형)

] 게임 막판 즈음에는 돌을 놓을 수 없는 경우가 발생하고, 그렇게되면 1차는 상대방에게 순서를 넘겨야되고, 그 다음에도 놓을 곳이 없으면 게임 종료 시킨다.

] 오목은 돌의 색깔이 정해지면 계속 그대로이지만, 리버시는 매번 색깔이 바뀐다.

] 마지막에 자기 돌의 수가 많은 쪽이 이기는 게임이라, 돌의 수를 매번 세어서 보여줘야 한다.

 

오목에서처럼 각 칸을 숫자의 배열로 구성시키고, 거기서 연산을 해나간다. 

아래와 같이 빈 칸은 -1, 흰색 돌 0, 검정색 돌 1, 흰색이 둘 수 있는 곳 2, 검정색이 둘 수 있는 곳 3으로 숫자 배열을 계속 바꿔나가고, 그 배열에 맞춰 매 번 캔버스에 그림을 그려준다.

돌을 놓을 수 있는 곳은, 돌을 잡을 수 있는 곳에만 놓을 수 있는데, 이 경우를 찾는 곳에서 가장 애를 먹었던 것 같다.

매 번 각각의 칸에서 8방향을 모두 체크하고, 나와 다른 색깔의 돌이 있으면, 그 방향으로 다음 돌을 확인해나가다가, 그 끝에 나와 동일한 색의 돌이 있는 경우가 돌을 놓을 수 있는 경우다. 

 

돌이 놓아지는 경우에도 그 돌의 8방향을 모두 확인해서 잡은 돌의 색을 바꿔준다. (배열의 숫자 0을 1로, 아니면 1을 0으로...)

 

아래에 Javascript 파일 전문.  P5.js를 사용했지만, 그림 그리는 것만 좀 편해진 것이고, javascript의 기본 원리는 동일하다.

 

 

모던 자바스크립트 Deep Dive:자바스크립트의 기본 개념과 동작 원리

COUPANG

www.coupang.com

function setup(){
  canvasWidth = 600;
  canvasHeight = 600;
  cvs= createCanvas(canvasWidth,canvasHeight);
  background('#1b5e20');
    
  row = 8;
  rowWidth = canvasWidth / row;
  radius = rowWidth-20;
  count = 1// 돌을 놓는 차례. 1을 검정색으로 설정
  blackScore = whiteScore = 2
  blackAvailable = whiteAvailable = 2
  pass = 0;
  checkDirection = [[1-1], [10], [11], [01], [-11], [-10], [-1-1], [0-1],];
  board = new Array();
  buffer = new Array();
  boardHistory = new Array();
  tik = new Audio("tik.mp3");
  beep = new Audio("beep.wav");
  ending = new Audio("ending.wav");
  plz = new Audio("plz.m4a");
  oneMore = new Audio("oneMore.m4a");
 
  winScreen = document.querySelector('.winShow');
  turnPass = document.querySelector(".turnPass");
  // 보드 격자를 그리고, 모든 칸에 -1을 입력
  boardInit();
 
  // 시작 돌 4개 
  board[3][3= board[4][4= 1;
  board[4][3= board[3][4= 0;
  
  checkAvailable();
  drawBoard();
  
  document.querySelector("#black").innerHTML = "검정색 점수 : " + blackScore;
  document.querySelector("#white").innerHTML = "하얀색 점수 : " + whiteScore;
  button1 = document.querySelector("#withdraw");
  button2 = document.querySelector("#reload");
  troImg = document.querySelector("#trophyImg");
  
  // 무르기 버튼 동작
  button1.addEventListener('mouseup', ()=>{
    plz.currentTime = 0.5;
    plz.play();
    withdraw();
  })
  button2.addEventListener('mouseup', ()=>{
    oneMore.currentTime = 0.5;
    oneMore.play();
    setTimeout(() => {
      location.reload();
    }, 2000);
  })
 
  canvasPosition = cvs.position(0,30);
}
 
function boardInit(){
  // 보드 격자를 그리고, 모든 칸에 -1을 입력
  stroke("black");
  strokeWeight(2);
  fill('#1b5e20');
  for (i = 0; i < 8; i++) {
    board[i] = new Array(8);
    for (j = 0; j < 8; j++) {
      rect(i * rowWidth, j * rowWidth, rowWidth, rowWidth);
      board[i][j] = -1;
    }
  }
  console.log('-1 초기화')
   fill("black");
   circle(rowWidth * 2, rowWidth * 210);
   circle(rowWidth * 2, rowWidth * 610);
   circle(rowWidth * 6, rowWidth * 210);
   circle(rowWidth * 6, rowWidth * 610);
}
 
// 마우스 클릭하면 그 칸의 위치 파악
document.addEventListener("mouseup", (e) => {
  // console.log('offset' , e.offsetX, e.offsetY);
  // console.log('page' , e.pageX, e.pageY);
  
  if(e.offsetX > 0 && e.offsetX < canvasWidth && e.pageY > canvasPosition.y && e.offsetY > 0 &&  e.offsetY < canvasHeight){
    
  let rowX = floor(e.offsetX / rowWidth);
  let rowY = floor(e.offsetY / rowWidth);
  
  main(rowX, rowY);
  }
});
 
// 객체 복사하는데, 이전 값을 계속 참조하는 것을 막는 함수
function cloneObj(obj){
  const result = [];
  // console.log(obj)
  for( i = 0 ; i< 8 ;i++ ){
    result[i] = JSON.parse(JSON.stringify(obj[i]));
  }
  return result;
}
// 메인 함수. 클릭된 칸에 흰색(0), 검은색(1) 입력하고, 
// 뒤집어야 하는 함수 호출, 보드 전체 그리는 함수 호출
function main(x, y) {
 
  // 돌을 놓을 수 있는 곳일때만 주요 함수들 실행
  if (board[y][x] == 2 || board[y][x] == 3) {
    tik.currentTime = 0.5;
    tik.play();
    board[y][x] = count % 2;
    // 돌을 놓을 수 있는 위치에 3(검정)이나 2(흰색)로 보드에 입력하는 함수 호출
    checkReversible(x, y);
    count++;
    // 돌을 뒤집어야 하는 경우에, 바뀐 색으로 보드에 입력
    checkAvailable();
    let boardTemp = board;
    // board배열상태로 보드를 그려줌 
    drawBoard();
    // 검정,하얀 돌  개수 계산
    scoreCalc();
    // 무르기를 위해서 매 차례의 보드 배열을 통째로 boardHistory배열에 입력
     boardHistory.push(cloneObj(board));
 
 
 
    // console.log('boardHistory', boardHistory);
  } else {
    beep.play();
    console.log('Not Here')
  }
}
 
// 무르기 함수
function withdraw(){
  boardInit();
  boardHistory.pop();
  board = cloneObj(boardHistory.slice(-1)[0]);
  // board = boardHistory.slice(-1)[0];
  console.log(boardHistory);
  count--;
  drawBoard();
  scoreCalc();
}
 
// 점수 계산 함수
// 점수 계산 및 돌을 둘 수 있는 곳이 몇 개 있는지도 확인
// 만약 돌을 둘 수 있는 곳이 없으면, 나중에 패스하도록
function scoreCalc(){
  blackScore = whiteScore = 0;
  blackAvailable = whiteAvailable = 0
  for(i=0;i<8;i++){
    blackScore += board[i].filter((e) => e === 1).length;
    whiteScore += board[i].filter((e) => e === 0).length;
    blackAvailable += board[i].filter((e) => e === 3).length;
    whiteAvailable += board[i].filter((e) => e === 2).length;
  }
  document.querySelector("#black").innerHTML = "검정색 점수 : " + blackScore;
  document.querySelector("#white").innerHTML = "하얀색 점수 : " + whiteScore;
  
  if (count % 2 == 0 && whiteAvailable == 0 && pass != 2) {
    console.log("no white move");
    pass++;
  } 
  if (count % 2 == 1 && blackAvailable == 0 && pass != 2) {
    console.log("no black move");
    pass++;
  }
 
  // 놓을 곳이 없으면 상대방에게 차례 넘김
  if(pass == 1){
    console.log("다음 차례로 넘어갑니다.");
    turnPass.style.zIndex = 3;
    turnPass.style.visibility = "visible";
    turnPass.style.animationName = "moveDown";
    console.log(turnPass);
    setTimeout(() => {  
      turnPass.style.zIndex = -1;
    }, 2500);    
    count++;
  }
 
  // 혹시 둘 곳이 없어서 다음 차례로 넘어간 경우 때문에
  // 가능한 곳을 다시 찾고, 다시 그려주는 함수 호출
   pass++;
   checkAvailable();
   drawBoard();
 }
 
// 배열 상태대로 보드 전체에 돌 및 놓을 수 있는 위치를 그려줌
function drawBoard(){
   noStroke();
  
  // board배열에 따라 흰색,검정색,작은 사각형 그려주고
  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      switch (board[i][j]) {
        case 0:
          fill("white");
          circle((j+1)*rowWidth - floor(rowWidth/2), (i+1)*rowWidth - floor(rowWidth/2), radius);
          break;
        case 1:
          fill("black");
          circle((j+1)*rowWidth - floor(rowWidth/2), (i+1)*rowWidth - floor(rowWidth/2), radius);
          break;
        case 2:
          fill("rgba(255,255,255,1)");
          rect((j+1)*rowWidth - floor(rowWidth/2)-4, (i+1)*rowWidth - floor(rowWidth/2)-410,  10  );
          break;
        case 3:
          fill("rgba(0,0,0,1)");
          rect((j+1)*rowWidth - floor(rowWidth/2)-4, (i+1)*rowWidth - floor(rowWidth/2)-410,  10  );
          break;
        default : 
          fill("#1b5e20");
          rect((j+1)*rowWidth - floor(rowWidth/2)-8, (i+1)*rowWidth - floor(rowWidth/2)-816,  16  );
          break;
        }
    }
  }
}
 
// 원을 뒤집어야 하는지 여부 확인해서 0(하얀색),1(검정색)을 좌표에 입력
function checkReversible(x,y){
  // 8방향으로 체크하는 루프
  for (j = 0; j < checkDirection.length; j++) {
    cX = x;
    cY = y;
    while (cX >= 0 && cY >= 0 && cX < 8 && cY < 8) {
      cX = cX + checkDirection[j][0];
      cY = cY + checkDirection[j][1];
      if (cX < 0 || cY < 0 || cX >= 8 || cY >= 8) {
        break;
      } else {
          if (board[cY][cX] == count%2 || board[cY][cX] == -1 || board[cY][cX]  == 2 || board[cY][cX] == 3) {
            buffer.push([cX, cY]);
            break;
          } else {
            buffer.push([cX, cY]);
          }
      }
    }
    // console.log(buffer)
    if (buffer.length >= 1) {
      if (
        count%2 == board[buffer[buffer.length - 1][1]][buffer[buffer.length - 1][0]]
      ) {
        // console.log('here', count % 2);
        for (i = 0; i < buffer.length; i++) {
          board[buffer[i][1]][buffer[i][0]] = count%2;
        }
      }
    }
    buffer = [];
  }
}
 
// 돌을 놓을 수 있는 위치 파악해서, 검정색 가능위치(3), 하얀색 가능위치(2)로 board에 기록
function checkAvailable(){
  // 둘 곳 없어서 패스된게 두 번이 되면 게임 종료
  if(pass>1){
    console.log('game over')
    turnPass.style.visibility="hidden";
    gameOver();
  }
 
  // 이전 차례에서 2,3이었던 값을 -1로 초기화하는 함수 호출
  resetAvailable();
 
  boardCopy = board;
  // console.log(boardCopy)
  for (i=0;i<checkDirection.length;i++){
    for(k=0;k<checkDirection.length;k++){
      tX = i;
      tY = k;
  
  for (j = 0; j < checkDirection.length; j++) {
    // 검사할 좌표들을 aX,aY로 설정
    aX = tX;
    aY = tY;
    // 8방향으로 검사하는 루프
    while (aX >= 0 && aY >= 0 && aX < 8 && aY < 8) {
    aX += checkDirection[j][0];
    aY += checkDirection[j][1];
    // 검사 영역이 8x8 판 밖으로 나가면 멈추고,
    if (aX < 0 || aY < 0 || aX >= 8 || aY >= 8) {
      break;
    } 
    // 판 안에서 검사하는 칸들을 배열에 넣는다.
    else {
      buffer.push([aX, aY, boardCopy[aY][aX]]);
      // 검사한 칸의 색이 이번 차례의 색과 같거나, 빈 칸이면 배열에 넣기를 멈춘다.
      // 아니라면 검사한 칸의 값을 계속 배열에 넣는 루프를 반복한다.
      if (
        boardCopy[aY][aX] === count % 2 ||
        boardCopy[aY][aX] === -1 ||
        boardCopy[aY][aX] === 2 ||
        boardCopy[aY][aX] === 3 ||
        boardCopy[tY][tX] !== -1
      ) {
        break;
      } 
    }
  }
 
  // 만약 돌들의 배열이 돌을 놓을 수 있는 조건이면 3(검은색)이나 2(흰색)을 입력한다 
  if (
    buffer.length > 1 &&
    boardCopy[buffer[0][1]][buffer[0][0]] != count % 2 &&
    boardCopy[buffer[buffer.length - 1][1]][buffer[buffer.length - 1][0]] === count%2
  ) {
    // console.log(count);
    switch (count % 2 ) {
      case 0:
        board[tY][tX] = 2;
        break;
      case 1:
        board[tY][tX] = 3;
        break;
    }
    pass = 0;
  } 
  buffer = [];
}
}
}
}
 
function resetAvailable(){
  for (i=0;i<row;i++){
    for(k=0;k<row;k++){
      if(board[i][k]==2 || board[i][k]== 3){
        board[i][k]= -1;
      }
    }
  }
};
 
// 승리 화면 표시
function gameOver(x) {
  ending.play();
  // 음악이 재생되도록 약간의 시차를 두고 화면 표시
  setTimeout(() => {
    winScreen.style.visibility = 'visible';
    winScreen.style.zIndex = 2;
    if(blackScore > whiteScore){
      document.querySelector(".comment").innerHTML = "<br>" + "검정색 승리"
    }
    if(blackScore < whiteScore){
      document.querySelector(".comment").innerHTML = "<br>" + "하얀색 승리";
    }
    if(blackScore == whiteScore){
      document.querySelector(".comment").innerHTML = "<br>" + "무승부";
    }
 
    console.log(winScreen)
    troImg.style.animationName = "trophy";
  }, 300);
  
   
}
cs

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

3D, 입체의 세상은 멋지지만 구현하기는 힘들다.

3D는 전문가의 영역이라고만 생각했는데, 의외로 어렵잖게 진입할 수 있음을 알게됬고, 심지어 그 프로그램이 공개 무료라니!! (adobe가 2D 프로그램들로 돈을 긁어 먹고 있는 날도 머잖았지 싶다.)

 

블렌더(blender)... 정말 훌륭한 프로그램이다.

아들이 어몽어스를 3D로 그려보겠다는 걸 옆에서 도와주다가 내가 빠져버렸다. 

 

유튜브를 보고 따라하면서 주말을 갈아넣어 만든 결과물이다.

유튜브를 따라했지만, 중간중간에 스스로 만든 부분들이 있기 때문에 뿌듯하다.  특히 깃발에 태극기 사진을 넣은건... 훌륭하다...

내가 이런 걸 만들 수 있을거라고는 생각해본적이 없었는데... 

 

아는 만큼 보인다.  이런 3D의 세상을 알게되니까, 유튜브에 자신의 뛰어난 재능으로 지식을 공유해주는 수많은 사람들이 보인다. 

하려고만 하면, 유튜브만으로도 4년제 대학 전공 실력은 기를 수 있는 시대다.

 

그런데, blender는 우리가 흔히 '믹서'라고 하는 기기를 의미하더라. 왜 3D 프로그램에 믹서기를 의미하는 이름을 붙였을까... 

 

 

 

 

필립스 3000 시리즈 블렌더 블랙 HR2041/01

COUPANG

www.coupang.com

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

Omron은, 발열에 의한 에너지 손실을 막고, 시스템의 발전 효율을 향상시키는 고용량 파워 릴레이G9KA2021 발매를 하였습니다. 업계 최고수준인 초저접촉저항 0.2mΩ릴레이의 발열을 억제하여 전체 제품의 전류 효율 향상이 기대됩니다. 

초저접촉저항을 실현한 고용량파워 릴레이「G9KA」

지속 가능한 에너지 생산에 있어 에너지 변환의 고효율화가 요구되는 반면에태양광 등 재생 가능 에너지의 발전설비에서는 발전 시에 기기 발열로 인한 에너지 손실이 발생하는 것뿐 아니라 설비와 기기의 고용량화대전류화가 진행됨에 따라, 발열 대책은 중요한 과제입니다.

기기 발열의 요인의 하나로 들 수 있는 것이, 기기 내부 기판에 탑재 되어있는 릴레이입니다. 릴레이는 전력계통과의 연계 시에 기기에 흐르는 전류의 ON/OFF 제어 및 긴급 시의 안전 차단 용도로서 사용되는 부품입니다. 종래의 고용량파워 릴레이는 접촉 저항치가 높아서, 발열에 의한 에너지 손실이 과제입니다. 발열 대책으로 기기 내의 히트 싱크와 냉각 팬 등의 방열 기구의 설치 및 릴레이 발열로 인한 기판의 열화가 기기 본체의 수명을 저하시키는 사례가 있었습니다.

 

이번에 발매된 G9KA는,

 ] 접촉저항치를 업계 TOP CLASS0.2mΩ까지 낮추어서, 기존의 일반적인 고용량파워 릴레이에 비하여 릴레이의 상승 온도를 약30억제할 수 있습니다.

 ] 발열 대책용으로 설치된 히트 싱크와 냉각 팬 등을 간소화 가능하여, 기기 소형화경량화에 도움이 됩니다.

 ] 릴레이에서의 발열을 억제하는 것으로 기판의 상승 온도의 저감으로 이어지며, 기기의 수명을 늘리는 데에 공헌합니다.

또, 200AAC800V을 통전, 차단하는 것이 가능하기 때문에 큰 전류 부하를 차단할 필요가 있는 기기와 어플리케이션에 사용하는 것이 가능합니다. 그래서 고용량 전력 제어 용도로 주로 사용되는 컨택터에서 교체하는 것도 가능합니다. 같은 정도의 전류 용량의 컨택터 대비, 부품 본체의 높이가 1/3정도로 낮출 수 있기 때문에, 기기의 소형화공간 절약에 공헌합니다.

기판에 부품 탑재 시 높이 비교

 

적용 application 예시 :

 

G9KA주요 사양 : 

제품문의 : bryanko@asung.com / 010-9587-2555

 

 

 

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

'취미' 카테고리의 다른 글

[blender] 충돌 시뮬레이션  (0) 2022.04.24
[blender] 3D의 세상을 알게되다  (0) 2022.04.17
레이다센서 데모  (0) 2022.03.09
Huawei 토크밴드B6 , 한 달 사용기  (0) 2021.06.10
Kinetic retimer IC  (0) 2021.05.16

IoT시대에서 사람의 눈,코,입 등의 감각을 대신하는 센서의 필요성은 계속 커지고 있습니다.

기존의 센서는, 적외선센서,초음파센서가 널리 사용되었고, 최근에는 비디오 영상을 판독해서 센서의 역할을 대신하기도 합니다. 

그러나, 아래와 같은 단점이 있습니다. 

  > 적외선,초음파 센서 : 감지 범위가 좁음. 미세한 움직임을 놓치기 쉬움. 센서가 밖으로 노출되어야 함(무언가가 앞을 가리면 안됨)

  > 영상 판독 : 카메라의 전력 소모가 큼.  사생활 보호 문제.

 

레이다센서는 위와 같은 단점들을 보완하면서 아래와 같은 장점이 있습니다.

] 온도,조명 등 외부환경에 영향 받지 않고, 8미터, 감지각도 110~120도의 넓은 범위에서 센싱 영역(거리,각도)을 손쉽게 설정 가능합니다.

  그래서 일반적인 적외선 센서보다 훨씬 높은 감도로 더 넓은 범위를 센싱 가능합니다.

] 감지 각도에 제한을 걸 수가 있기 때문에, 예를들어, 화장실에 센서를 설치했을 때, 열린 문 앞으로 사람이 지나가도 감지되지 않도록 감지 각도를 제한해서 사용할 수 있습니다.

] 초음파,적외선 센서와는 달리, 기구물이 센서를 가려도 센싱이 가능합니다.
  
그래서 제품 외관에 변형이 없이 센서 적용이 가능합니다.

 

아래는 간단하게 제작한 데모 영상입니다. 

https://youtu.be/4H1wqG1Zekc

2미터로 감지거리 제한을 뒀고, 그 영역 내에서만 감지를 합니다. 

의자에 앉아서 큰 움직임이 없으나 계속 감지를 하고 있습니다. (물론 작정하고 안움직이면 감지되지 않습니다만...)

영상에서는 잘 보이지 않으나, 움직임이 감지되는 거리,각도 값을 출력해주기 때문에, 다양한 application에 활용이 가능합니다. 

 

제품문의 : bryanko@asung.com / 010-9587-2555

 

 

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

+ Recent posts