Set display scale for Ubuntu 18.04 on Parallels 14

패러럴즈에 Ubuntu 18.04를 설치하고, 패러럴즈 툴을 설치했음에도 불구하고 해상도 설정이 좀 이상한 경우가 있다. 특히 Display scale을 조절할 수 있는 옵션이 나타나지 않는데, 이 경우 흐리멍텅한 화면이나, 네이티브 해상도 (아주 작은 글씨)로만 사용해야 한다.

검색해보니 설정에는 안보이지만, 터미널 상에서 UI 스케일을 조정할 수 있는 방법이 있었다.

$ gsettings set org.gnome.desktop.interface scaling-factor 2

원하는 스케일 팩터를 뒷부분에 적으면 된다. 2는 200%를 의미한다.

다시 초기값으로 돌리려면,

$ gsettings reset org.gnome.desktop.interface scaling-factor

와 같이 입력한다.

터미널에서 명령어를 입력 후, 재부팅하거나 Logout 후 재로그인하면 설정이 반영된다.

Advertisements

Kinematic Model for 3 Wheel Omni Drive Robot

3 Wheel Omni Drive 로봇은 메카넘휠(90º) 3개를 120º 간격으로 배치하여 구성하며, 바퀴 속도의 조합에 따라 전방향으로 이동 가능하다.

식은 다음과 같이 나타낼 수 있다.

\dot{\phi} = J_{2}^{-1} J_{1f} R(\theta) \dot{\xi_{I}} \dot{\xi_{I}} = R(\theta)^{-1}J_{1f}^{-1}J_{2}\dot{\phi}

여기서,

\dot{\phi} = \begin{bmatrix} \dot{\phi}_{1} \\ \dot{\phi}_{2} \\ \dot{\phi}_{3} \end{bmatrix} \dot{\xi_{I}} = \begin{bmatrix} \dot{x} \\ \dot{y} \\ \dot{\theta} \end{bmatrix} J_{2} = \begin{bmatrix} 2r & 0 & 0 \\ 0 & 2r & 0 \\ 0 & 0 & 2r \end{bmatrix} J_{1f} = \begin{bmatrix} sin(\frac{\pi}{3}) & -cos(\frac{\pi}{3}) & -l \\ 0 & -cos(\pi) & -l \\ sin(-\frac{\pi}{3}) & -cos(-\frac{\pi}{3}) & -l \end{bmatrix} R(\theta) = \begin{bmatrix} cos \theta & sin\theta & 0 \\ -sin \theta & cos \theta & 0 \\ 0 & 0 & 1\end{bmatrix}

r는 바퀴의 반지름, l은 로봇 중심으로부터 바퀴까지의 거리이다.

이제 바퀴의 속도 변경에 따른, 로봇의 움직임을 구하려면,

\begin{bmatrix} \dot{x} \\ \dot{y} \\ \dot{\theta} \end{bmatrix} = \begin{bmatrix} cos \theta & sin\theta & 0 \\ -sin \theta & cos \theta & 0 \\ 0 & 0 & 1\end{bmatrix}^{-1} \begin{bmatrix} sin(\frac{\pi}{3}) & -cos(\frac{\pi}{3}) & -l \\ 0 & -cos(\pi) & -l \\ sin(-\frac{\pi}{3}) & -cos(-\frac{\pi}{3}) & -l \end{bmatrix}^{-1} \begin{bmatrix} 2r & 0 & 0 \\ 0 & 2r & 0 \\ 0 & 0 & 2r \end{bmatrix} \begin{bmatrix} \dot{\phi}_{1} \\ \dot{\phi}_{2} \\ \dot{\phi}_{3} \end{bmatrix}

여기서 나온 결과, 즉 로봇의 속도 (\dot{x}, \dot{y}, \dot{\theta})를 누적하면 Odometry 정보를 얻을 수 있다.

이제 로봇을 제어하기 위해서, 원하는 로봇의 선속도 (\dot{x}, \dot{y} ), 각속도 (\dot{\theta})가 입력이 되면,

\begin{bmatrix} \dot{\phi}_{1} \\ \dot{\phi}_{2} \\ \dot{\phi}_{3} \end{bmatrix} = \begin{bmatrix} 2r & 0 & 0 \\ 0 & 2r & 0 \\ 0 & 0 & 2r \end{bmatrix}^{-1} \begin{bmatrix} sin(\frac{\pi}{3}) & -cos(\frac{\pi}{3}) & -l \\ 0 & -cos(\pi) & -l \\ sin(-\frac{\pi}{3}) & -cos(-\frac{\pi}{3}) & -l \end{bmatrix} \begin{bmatrix} cos(0) & sin(0) & 0 \\ -sin(0) & cos(0) & 0 \\ 0 & 0 & 1\end{bmatrix} \begin{bmatrix} \dot{x} \\ \dot{y} \\ \dot{\theta} \end{bmatrix}

와 같이 각 바퀴의 속도를 구할 수 있다. 이제 이 속도를 바퀴 모터에 적용하면 로봇이 원하는 방향으로 움직인다.

참고:

Ubuntu에서 USB 시리얼포트 low_latency 설정하기

로봇에 외장 기기를 부착할 경우 USB 시리얼포트 디바이스를 많이 사용한다. 요즘 나온 메인보드엔 시리얼포트가 없으니 당여한 이야기인데, USB 통신의 특성상 latency timer 값이 16ms로 기본으로 설정되어 있어, 빠른 응답 특성을 요구할때엔 속도 저하의 이유가 된다.

먼저 현재 설정된 latency_timer 값을 확인해본다.

$ cat /cat/sys/bus/usb-serial/devices/ttyUSB0/latency_timer
16

ttyUSB0는 사용자의 포트 번호에 따라 변경하여 사용하면 된다. 위와 같이 16ms로 설정되어 있는 값을 1ms로 변경해본다.

$ echo 1 | sudo tee /sys/bus/usb-serial/devices/ttyUSB0/latency_timer

문제는 이를 부팅때마다 반복해야 되는데, setserial 명령어를 udev 룰에 추가해서 이를 간단히 해결할 수 있다. 먼저 setserial를 설치한다.

$ sudo apt install setserial

다음으로 /etc/udev/rules.d로 이동해서, 99-ttyUSB.rules 파일을 만들거나, 이미 사용하고 있는 룰에 다음과 같이 추가한다.

KERNEL=="ttyUSB[0-9]*", MODE="666", ATTRS{idVendor}="0403", RUN+="/bin/setserial /dev/%k low_latency"

저장하고, 재부팅한다.

이제 명령어로 확인해보면

$ cat /cat/sys/bus/usb-serial/devices/ttyUSB0/latency_timer
1
$ cat /cat/sys/bus/usb-serial/devices/ttyUSB1/latency_timer
1
$ cat /cat/sys/bus/usb-serial/devices/ttyUSB2/latency_timer
1

모든 USB 시리얼포트의 latency_timer 값이 1ms로 설정되어 있음을 볼 수 있다.

기계 요소 설계 (3판)

태생이 전자 공돌이라, 소프트웨어까진 어떻게 해본다 쳐도, 기구설계는 완전 다른 이야기인듯 하다. 물론 요즘에야 개발 도구들이 잘 되어 있어 뚝딱뚝딱 만들어 볼수 있다곤 하지만, 그래도 기본적인 사항은 알아야 이해를 하고 만들어볼 수 있는 듯.

3D 프린터를 좀더 알차게 사용해보고 싶은 마음에, 서점 간 김에 그래도 좀 예제가 많아보이는 책을 구입했다. 기초적인 요소들에 대한 설명과 각종 수치들이 있고, 한국에선 요런거 사용함 등등의 내용이 보인다. 아주 자세히 보진 못하겠지만, 간단한 기구 설계할 때 유용하게 사용할 수 있을 듯 하다.

교보문고: http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788942907403&orderClick=LAH&Kc=#N

칼만 필터는 어렵지 않아

아마 예전 책 제목은 “칼만 필터의 이해”였던 것 같다. 칼만필터를 로봇에 적용해서 사용하긴 하는데 (OpenCV에서 함수 형태로 있으니…) 이게 어떻게 동작하는 것인지, 왜 적용해야 하는지에 대한 궁금함이 항상 있던 차에 예전 판본을 보고 이해했던 기억이 난다.

이번에 새로 개정되어 제목도 바뀌어 출시되었길래, 또 다시 구입했다. 내용도 약간 증가한듯 하고, 비록 매틀랩 코드이지만 예제도 잘 구현되어 있다. (이걸 파이썬이나 다른 언어로 바꾸는거야 머, 쉬운 작업이니)

교보문고: http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9791156644415&orderClick=LEB&Kc=

소라게 집 바꿔주기

한달 전 쯤? 아들 녀석이 방과후 학교에서 소라게 한마리를 가지고 왔습니다. 조그만 플라스틱 케이스와 젤리처럼 생긴 먹이 하나와 같이요. 사실 며칠 지나지 않아 죽거나 할 줄 알았는데 의외로? 한달이 지났는데도 잘 지내고, 밤이 되면 부스럭부스럭 조그만 케이스를 탈출하고자 노력하더군요. ㅠㅠ

인터넷을 검색해보니 소라게의 수명이 엄청 길더라고요. 자연에서 사는 녀석들은 몇십년을 산다고도 하고… 암튼 이대로는 안되겠다 싶어 인터넷을 검색해보고, 다이소에서 적당한 집 (큰 플라스틱 케이스)을 사오고, 코코칩이라 불리는 바닥재, 먹이용 젤리를 주문했습니다.

두텁게 코코칩을 깔아주고, 소라게를 새로운 집에 옮겨주고 젤리를 하나 까서 같이 놓아주었습니다.

원래 소라게의 습성이 어두운 밤에 주로 움직이고, 저런 코코칩 같은 바닥재를 깔아주면 파고 들어가서 산다고 하네요. 지금도 계속 바닥으로 파고들고, 가끔씩 먹이 있는 쪽으로 움직여 젤리를 파먹고 하고 있습니다. 새로운 집을 맘에 들어 하는 것 같습니다.

바닥재는 3주 정도에 한번씩 갈아주고, 그 동안은 너무 건조해지지 않도록 스프레이로 물을 조금씩 뿌려주면 되고, 젤리도 갈아주면 된다고 합니다. 혼자는 외로워할테니 한마리 더 넣어줘도 좋을듯 한데… 저 녀석이 암컷인지 숫컷인지 알 방법이 없네요.?? ^^

스팸무스비

이름은 뭔가 있어보이는데, 그냥 스팸 들어간 김밥인데 모양은 좀 다른 것. 아주~ 간단히 만들수 있고 재료를 좀더 추가하면 고급스럽게도 만들수 있다.

재료: 밥 2공기, 참기름 두 큰술, 깨소금 약간, 소금 약간, 스팸 작은 통 하나, 김밥용 김 2장.

  1. 밥 2공기를 큰 그릇에 덜어놓고 한소큼 식힌다. 참기름 혹은 들기름 2 큰술, 소금 약간, 깨소금 약간 넣고 잘 섞어준다. 밥의 간은 약간 싱겁게 해야 나중에 스팸의 간과 섞여 괜찮다.
  2. 스팸 작은 통을 열고 다 꺼낸 다음 스팸통 길이 방향으로 4개로 나눈다.
  3. 자른 스팸은 후라이팬에 잘 구워준다.
  4. 투명랩을 좀 크게 잘라, 빈 스팸통에 잘 깔아준다.
  5. 밥을 통의 1/3민큼 채우고, 그 다음 구운 스팸을 넣어준다.
  6. 나머지 공간을 또 밥으로 채운다.
  7. 랩을 잘 싸서 꺼낸다.
  8. 4 ~ 7 과정을 반복.
  9. 김밥용 김을 반으로 나눈다.
  10. 8번까지 만든 것을 김밥 중앙에 넣고, 김을 잘 싸준다.
  11. 먹기 좋게 썰어서 먹는다.

스팸 이외에 계란스크램플, 볶음양파, 볶음 김치 등을 추가해서 싸 먹어도 별미임.

끝!

Blockly 블럭 만들기 #1

Blockly는 사용자가 원하는 기능의 블럭을 자유롭게 만들수 있다. 기본 제공된 블럭 외에 사용자의 로봇이나 기타 기능과 연동하기 위한 블럭을 생성하고, 이를 툴박스에 넣어 사용하면 된다.

Blockly는 이러한 블럭들을 쉽게 만들수 있도록 도구를 제공한다. 재밌게도 블럭을 생성하는 것도 블럭으로 만든다. 물론 나중에 좀 익숙해지만 텍스트로 편집하는게 좀더 쉬울 수 있지만, 제공되는 도구를 이용하면 생성되는 블럭 모양을 확인하면서 수정이 가능하다.

먼저 Blockly Developer Tools를 사용해보자. 사파리나 크롬 등 브라우저를 열고 (https://blockly-demo.appspot.com/static/demos/blockfactory/index.html)으로 이동한다.

위와 같은 화면이 나오는데, 왼쪽은 블럭을 생성하기 위한 블럭 코딩 영역, 오른쪽 상단엔 생성된 블럭 모양을 실시간으로 확인이 가능하고, 오른쪽 중앙엔 추후 코드에 삽입하기 위한 JSON 코드, 오른쪽 하단엔 블럭을 실제 코드로 생성하기 위한 generator 코드가 생성된다.

일단 흐름을 보기 위해 아주 간단한 블럭을 생성해보도록 한다. 사용자의 문자열 입력을 받아 console에 출력하는 블럭을 만들어 보록 한다. 먼저 블럭의 name을 수정한다. 여기선 console_print로 한다.

다음으로 이 블럭은 다른 블럭들과 상하 연결하여 사용 가능해야 하므로, connection을 top+bottom connections로 변경한다. 이렇게 되면 미리보기 창의 블럭 모양이 변경됨을 볼 수 있다.

다음으로 사용자의 문자열을 입력 받아야 한다. 왼쪽 툴박스 창에서 Input 카테고리내에 value input 블럭을 inputs에 추가한다. 이 입력을 받아서 내부에서 처리하기 위한 변수명은 value_input 옆에 있는 NAME이다. 이를 필요에 따라 적절하게 수정한다.

이제 블럭에 기능을 설명하기 위한 텍스트 블럭을 추가한다. (Field 카테고리 Text 블럭)

입력은 Text만 받아야 하므로, 입력 type에 String 블럭을 추가한다.

마지막으로 블럭의 색상과, 이 블럭을 사용하는데 필요한 tooltip, help url 등을 입력한다.

이제 생성된 블럭의 모양을 확인해보면,

와 같이 간단한 모양의 블럭이 생성되었다. 생성된 JSON 코드를 확인해보면,

{
  "type": "console_print",
  "message0": "console print %1",
  "args0": [
    {
      "type": "input_value",
      "name": "NAME",
      "check": "String"
    }
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 330,
  "tooltip": "Block for printing the user message",
  "helpUrl": "https://ahnbk.com"
}

그리고, 이와 같이 생성된 Generator stub을 보면,

Blockly.JavaScript['console_print'] = function(block) {
  var value_name = Blockly.JavaScript.valueToCode(block, 'NAME', Blockly.JavaScript.ORDER_ATOMIC);
  // TODO: Assemble JavaScript into code variable.
  var code = '...;\n';
  return code;
};

와 같이 되어 있다. 자 이제 블럭이 생성되었으므로, 이를 지난번에 만들었던 예제에 생성된 블럭을 추가해보도록 한다. 예제 디렉토리로 이동하여, my_blocks.js 파일을 생성하고, 다음과 같이 입력한다.

'use strict';

goog.require('Blockly.Blocks');
goog.require('Blockly');

Blockly.defineBlocksWithJsonArray(
[
    // insert blocks here

]);

이제 “insert blocks here 부분에 위에서 생성된 코드를 붙여 넣는다.

'use strict';

goog.require('Blockly.Blocks');
goog.require('Blockly');

Blockly.defineBlocksWithJsonArray(
[
    {
        "type": "console_print",
        "message0": "console print %1",
        "args0": [
          {
            "type": "input_value",
            "name": "NAME",
            "check": "String"
          }
        ],
        "previousStatement": null,
        "nextStatement": null,
        "colour": 330,
        "tooltip": "Block for printing the user message",
        "helpUrl": "https://ahnbk.com"
      },
]);

저장한 다음, index.html 파일을 열고 위 파일을 로딩하도록 추가한다.

<!DOCTYPE html>
<!-- HTML file to host Blockly in a mobile WebView. -->
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <style type="text/css">
    html, body, #blocklyDiv {
      border: 0;
      height: 100%;
      margin: 0;
      padding: 0;
      width: 100%;
    }
  </style>
  <script src="blockly_compressed.js"></script>
  <script src="blocks_compressed.js"></script>
  <!-- TODO: Select msg file based on locale. -->
  <script src="msg/js/en.js"></script>
  <script src="toolbox_standard.js"></script>
  <script src="my_blocks.js"></script>
</head>
<body>
  <div id="blocklyDiv"></div>
  <script type="text/javascript">
    var workspacePlayground = Blockly.inject('blocklyDiv', {
          media: 'media/',
          toolbox: BLOCKLY_TOOLBOX_XML['standard'],
          zoom: {controls: true}
        });
  </script>
</body>
</html>

바로 이전 포스팅에서 만든 Custom 카테고리에 생성된 블럭을 추가한다.

+ '<category name="Custom" colour="100">'
+   '<block type="console_print">'
+   '</block>'
+ '</category>'

자, 이제 예제를 다시 열어보면,

Custom 카테고리에 console print 블럭이 추가되어 있음을 볼 수있다. 만약 문자열 입력에 default 값을 넣어 주고 싶다면, 툴박스에 코드를 다음과 같이 수정한다.

+ '<category name="Custom" colour="100">'
+   '<block type="console_print">'
+     '<value name="NAME">'
+       '<shadow type="text">'
+         '<field name="TEXT">Hello Blockly</field>'
+       '</shadow>'
+     '</value>'
+   '</block>'
+ '</category>'

이제 다시 예제를 확인해보면,

와 같이 되어 있음을 확인할 수 있다. 다음엔 좀더 다양한 모양의 블럭을 만들어보록 한다.

Scratch 3.0 Scratch Link를 수정해보기

Scratch 3.0은 외부기기와 연동하기 위해서 Scratch Link 앱을 이용해야 한다. (Scratch 내부에 구현할 수도 있을 것 같은데, 이렇게 되면 다른 운영체제에서 호환이 안될테니 아마도 이렇게 만들어 놓은듯 하다) 내부를 들여다보면 Scratch Link에서 WebSocket 서버를 제공하고, BLE, BT로 구분하여 접속할 수 있다. 통신은 JSONRPC를 이용한다. BLE, BT 모두 프로토콜은 동일하다.

따라서 Bluetooth 시리얼, BLE 등을 이용한 기기들은 기존 프로토콜을 이용하여 접속 및 연동이 가능하다. OROCA-Edubot도 이와 같은 과정을 통해 연동에 성공하였다. 이제 좀더 나아가 시리얼포트를 이용할 경우 (예를 들어 Arduino 보드나 사용자가 개발한 보드들)엔 어떻게 해야 할까?

고민해본 결과 가장 클리어한 방법은 Scratch Link를 확장하여 시리얼 통신을 지원하게끔 하면 될 것 같다. 마침 기존까진 실행파일로만 제공되었던 Scratch Link가 이젠 소스까지 제공되고 있다. 개발 지원 운영체제는 macOS와 윈도우이다.

소스는 https://github.com/llk/scratch-link에서 받을 수 있다. 개발PC에 일단 클론해 보고,

$ git clone https://github.com/LLK/scratch-link.git

README.md 파일에 나온 것과 같은 과정을 통해 빌드해보자. 보안 WebSocket를 사용해야 하므로 인증서가 필요하다. 나중에 판매하거나 양상 목적이라면 돈을 주고 구입해야 하지만, 개인이 사용할 경우엔 PC에서 쉽게 생성 가능하다.

$ cd scratch-link
$ cd Certificates
$ openssl req -x509 -out scratch-device-manager.cer -keyout scratch-device-manager.key \
  -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=scratch-device-manager' -extensions EXT -config <( \
   printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

$ ./convert-certificates.sh

위 과정이 완료되면 out 디렉토리에  scratch-device-manager.pem, scratch-device-manager.pfx 파일이 생성된다.

현재 내가 사용하고 있는 개발환경은 macOS 이므로, macOS 폴더로 이동하여 빌드를 시작한다. Xcode, pngcrush를 미리 설치되어 있어야 한다. Xcode는 앱스토어에서, pngcrush는 homebrew를 이용하면 쉽게 설치할 수 있다.

$ cd ..
$ cd macOS
$ make

빌드에 필요한 패키지들이 자동으로 설치되고, 에러가 없이 완료되면 dist 디렉토리가 생성되고 Scratch Link 앱이 생성되어 있음을 볼 수 있다.

이제 이 앱을 실행해보면, 기존과 같이 메뉴바에 Scratch Link가 위치한다.

Scratch 3.0를 실행하고, BLE와 BT 등 기존과 동일하게 동작하는지 확인한다. 지난번 개발환경 구축 포스팅에서 device-manager.scratch.mit.edu를 hosts 파일을 이용해 127.0.0.1로 강제 변경하였는데, 이제 Scratch Link를 직접 사용할 수 있으므로 localhost로 변경하여 사용해도 무방하다.

따라서, hosts 파일을 변경하는 작업을 하지 않고, scratch-vm 내에서 다음의 파일에 있는 웹소켓 주소를 localhost로 변경한다.

> scratch-vm/src/io/ble.js

const ScratchLinkWebSocket = 'wss://localhost:20110/scratch/ble';
> scratch-vm/src/io/bt.js

const ScratchLinkWebSocket = 'wss://localhost:20110/scratch/bt';

이제 Scratch 3.0을 실행하고 확장카드를 실행해보면,

사파리의 경우, 위와 같이 Scratch Link와의 연결이 되지 않는다. 새로운 사파리 창을 띄우고 https://localhost:20110 로 접속한다. 다음과 같이 나오는데,

Show Details 버튼을 누르고, 아래쪽에 visit this website 링크를 누르고 다시 한번 접속하겠다고 하면, 어드민 암호를 입력하고 현재의 인증서가 사파리에 저장된다.

이제 Scratch 3.0에서 정상적으로 실행됨을 볼 수 있다.

다음엔 Scratch Link의 소스를 분석하고 시리얼 통신이 가능하도록 모듈을 작성해보도록 한다.


참고링크

잔치국수

아들 녀석이 국수를 좋아하여 종종 끓여주고 있음.

육수

  1. 물 650ml 정도에 국간장, 양조간장을 같은 비율로 섞어주고 끓인다. 이때 간을 봤을 따, 살짝 간장맛이 들 정도로.
  2. 당근, 호박, 양파를 채 썰고 끓는 물이 넣어준다.
  3. 야채가 익으면, 계란 한개를 풀어 불을 끈 상태에서 넣어준다.
  4. 다시 끓이면서, 소금으로 간을 맞춘다. 후추도 첨가.

국수

  1. 면의 종류가 많긴한데, 먹기 부드러운 세면으로 선택
  2. 1인분 양을 잡아 끓이고, 다 익었다 싶으면 찬물에 행궈서 그릇에 이쁘게 담아준다.

완성

  1. 국수를 담은 그릇에 국물만 적당량을 살살 부어준다.
  2. 야채 및 계란 등 삶은 건더기를 국수 위에 살포시 얹어준다.

간장을 많이 넣으면 국물이 짙은 색으로 탁해지니 약간만 넣고, 최종 간은 소금으로. 양념장을 만들어 넣어 먹어도 되지만 이대로 먹어도 큰 무리수는 없음.

취향에 따라 김치 등을 얇게 썰어 같이 먹어도 별미.

Anki Vector 언박싱

얼마전 Anki社가 문을 닫았다. Cozi, Vector 등 귀엽고 기능 많은 로봇들을 개발하였고, 언뜻 보기엔 많이 팔리기도 하였는데… 왜 그랬을까… 뭐 암튼! 항상 구매해보고 싶단 생각은 갖고 있었는데, 문을 닫았다니 더 구매해보고 싶어서 뉴스가 뜬 날 바로 주문했다. 가격은 대충 30만원 정도? 해외주문이라 시간이 좀 걸리는 듯 하더니 드디어 도착.

이 로봇은 저 귀여운 눈이 포인트! 로봇 전체 색상은 아주 짙은 회색 (검은색이라고 해야 되나?)이 기본이고, 군데군데 금색 포인트, LED 등이 배치되어 있다.

상자를 열어보면 알차게 로봇과 큐브가 넣어져 있다. 역시 제품은 꺼내자마자 켜고 동작되어야 제맛. 이것저것 많이 설정하거나 하면 사용자는 힘들어진다. 전원키고 스맛폰 연결해서 계정 연동하면 끝.

한글이 지원되지는 않고 영어로 명령을 내리거나 의사소통해야 된다. Wakeup 단어는 “Hey! Vector.”이다. 로봇이 뭔가 처리를 하는 동안엔 알아듣지 못하며, 중간중간 idle 상태에선 칼 같이 알아듣는다.

큐브를 이용해 이것저것 명령을 내릴수도 있고, 그냥 냅두면 알아서 갖고 논다. 몇시간 정도 갖고 놀아본 결과, 이 제품의 컨셉은 애완동물인듯 하다. 가만히 냅둬도 이곳저곳 돌아다니고, 충전을 위한 도킹 스테이션을 자기의 집으로 생각하는…

거리센서와 카메라를 이용해 어느 정도 SLAM 기능을 수행하는 듯하다. “Go to charging station!”이라고 명령을 내리면 스스로 주변에 있는 도킹 스테이션을 찾아 충전을 시작한다.

로봇을 제어하기 위한 API도 상당히 충실하게 지원한다. python3로 프로그래밍 가능하니 쉬울듯. 잠깐 생각해본 바로는 ROS 연동도 쉽게 될것 같다. 실제로 여러가지 프로젝트들이 Vector를 이용해서 진행되고 있는 듯.

참고링크

Jetson Nano에서 Intel RealSense D435 카메라 사용해보기

Jetson Nano에는 USB 3.1 gen2 포트가 4개 존재한다. 문득 집에서 놀고 있는 인텔 리얼센스 카메라가 있어 연결해보기 위해 작업 시작.

Intel에서 Intel® RealSense™ SDK의 arm64용 빌드된 패키지를 제공해주지 않으므로, Jetson Nano에서 사용하기 위해선 소스를 직접 빌드하여야 한다. 먼저 소스 빌드를 위해 필요한 패키지들을 설치한다.

$ sudo apt install libgtk-3-dev libxcursor-dev libxinerama-dev

다음으로 레포지토리 (https://github.com/IntelRealSense/librealsense)에서 최신 릴리즈된 소스를 받아온다. (https://github.com/IntelRealSense/librealsense/releases)

받아온 소스의 압축을 풀고,

$ tar zxf librealsense-2.21.0.tar.gz
$ cd librealsense.2.21.0
$ mkdir build
$ cd build 
$ cmake ..

정상적으로 종료되면, 빌드를 시작한다. 이때 메모리 부족이 일어나므로 이번 포스트와 마찬가지로 swap 파티션을 활성화 한다.

$ sudo swapon /swapfile

빌드 시작

$ make -j1

정상적으로 빌드가 완료되면, 이제 설치.

$ sudo make install

이제 리얼센스 카메라를 연결하고, 테스트용 프로그램인 realsense-viewer를 실행해본다.

$ realsense-viewer

카메라가 정상적으로 인식되고 USB 3.1 gen2로 연결되어 있음을 볼수 있다. 몇가지 테스트 해본 결과 Jetson Nano에서는 1280×720의 해상도를 처리하기엔 너무 느리다. 따라서 해상도를 640×480으로 변경하여 사용한다.

이제 카메라를 켜보면~,

Depth 이미지와 RGB 이미지가 정상적으로 잘 보인다. 코어의 성능때문인지 30프레임이 다 나오는 것 같진 않다.


주의사항! 현재 Jetson Nano에는 5V, 2.1A 어뎁터를 사용하여 연결하였는데, 위와 같이 코어의 성능을 뽑아쓰는 어플리케이션을 돌리다보면 갑자기 전원이 나가는 경우가 가끔씩 발생하였다. 좀더 높은 전류를 제공하는 어댑터를 사용하기를 권장함.

Blockly 툴박스에 카테고리 추가

Blockly를 실행하면 좌측 (혹은 설정에 의해서 하단)에 툴박스가 존재한다. 사용자의 필요에 따라 이 툴박스에 카테고리를 추가하는 등에 대한 작업을 할 수 있다.

툴박스에 설정은 toolbox_standard.js 파일에서 진행한다. 지난 포스팅에서 실행했던 디렉토리에서 toolbox_standard.js 파일을 열어보면…

var BLOCKLY_TOOLBOX_XML = BLOCKLY_TOOLBOX_XML || Object.create(null);

/* BEGINNING BLOCKLY_TOOLBOX_XML ASSIGNMENT. DO NOT EDIT. USE BLOCKLY DEVTOOLS. */
BLOCKLY_TOOLBOX_XML['standard'] =
// From XML string/file, replace ^\s?(\s*)?(<.*>)$ with \+$1'$2'
// Tweak first and last line.
'<xml>'
+ '<category name="Logic" colour="%{BKY_LOGIC_HUE}">'
+   '<block type="controls_if"></block>'
+   '<block type="logic_compare"></block>'
+   '<block type="logic_operation"></block>'
+   '<block type="logic_negate"></block>'
+   '<block type="logic_boolean"></block>'
+   '<block type="logic_null" disabled="true"></block>'
+   '<block type="logic_ternary"></block>'
+ '</category>'
+ '<category name="Loops" colour="%{BKY_LOOPS_HUE}">'
+   '<block type="controls_repeat_ext">'
+     '<value name="TIMES">'
+       '<shadow type="math_number">'
+         '<field name="NUM">10</field>'

...

와 같이 되어 있다. Javascript로 되어 있으며, 자세히 살펴보면 XML을 String 형태로 변환해서 사용함을 볼 수 있다. 주석에 나와 있는 것처럼, Blockly Dev Tools를 이용해서 만들어 줄 수 있지만, 간단한 작업은 본 파일을 수정하면 된다.

Custom이라는 카테고리를 추가해보도록 한다. 블럭은 아직 추가하지 않기로 한다. 카테코리를 추가하고 싶은 지점에 다음과 같이 추가한다.

+ '<category name="Custom" colour="100">'
+ '</category>'

이제 다시 웹페이지를 reload해서 보게 되면,

Custom 카테고리가 추가되어 있는 것을 볼 수 있다. 아직 블럭들이 추가되어 있지 않으므로, 클릭해도 블럭들은 보이지 않는다. 카테고리 사이에 구분자(Seperator)를 추가하려면 원하는 지점에 다음과 같이 추가한다.

여기까지.

Jetson Nano에서 OpenCV 4.1 with CUDA 빌드

영상처리에 많이 사용되는 OpenCV를 Jetson Nano에서도 사용 가능하다. 빌드 과정은 PC에서와 동일하나 플랫폼의 특성 상 몇가지 다른 부분이 있다. 기본으로 설치되어 있는 패키지를 사용해도 되지만, CUDA를 활용하기 위해선 빌드 과정을 통해 설치하여야 한다.

L4T에는 cuda10.0이 이미 설치되어 있다.

OpenCV github 레포지토리에서 소스를 다운로드한다.

현재 릴리즈된 최신 버전은 4.1.0이다.

먼저 cmake를 설치한다.

$ sudo apt install cmake

다운로드한 압축파일 (opencv-4.1.0.tar.gz, opencv_contrib-4.1.0.tar.gz) 을 풀고, 다음과 같이 cmake를 이용해 빌드 파일을 생성한다.

$ cd opencv-4.1.0
$ mkdir build
$ cd build
$ cmake -DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.1.0/modules -DWITH_CUDA=ON -DCUDA_FAST_MATH=1 -DBUILD_EXAMPLES=ON  -DBUILD_opencv_python3=ON -DPYTHON3_INCLUDE_DIR2=/usr/include/python3.6m -DPYTHON3_NUMPY_INCLUDE_DIRS=/usr/lib/python3/dist-packages/numpy/core/include -DCUDA_ARCH_BIN="5.3" -DCUDA_ARCH_PTX=""  -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_EXAMPLES=OFF ..

각종 의존 패키지들을 체크하고 정상적으로 종료되면 다음과 같은 결과를 보여준다.

-- General configuration for OpenCV 4.1.0 =====================================
--   Version control:               unknown
-- 
--   Extra modules:
--     Location (extra):            /home/byeongkyu/Downloads/opencv_contrib-4.1.0/modules
--     Version control (extra):     unknown
-- 
--   Platform:
--     Timestamp:                   2019-05-02T04:43:14Z
--     Host:                        Linux 4.9.140-tegra aarch64
--     CMake:                       3.10.2
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               Release
-- 
--   CPU/HW features:
--     Baseline:                    NEON FP16
--       required:                  NEON
--       disabled:                  VFPV3
-- 
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++ Compiler:                /usr/bin/c++  (ver 7.4.0)
--     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections    -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections    -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     C Compiler:                  /usr/bin/cc
--     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections    -fvisibility=hidden -O3 -DNDEBUG  -DNDEBUG
--     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wuninitialized -Winit-self -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections    -fvisibility=hidden -g  -O0 -DDEBUG -D_DEBUG
--     Linker flags (Release):      -Wl,--gc-sections  
--     Linker flags (Debug):        -Wl,--gc-sections  
--     ccache:                      NO
--     Precompiled headers:         YES
--     Extra dependencies:          m pthread cudart_static dl rt nppc nppial nppicc nppicom nppidei nppif nppig nppim nppist nppisu nppitc npps cublas cufft -L/usr/local/cuda/lib64 -L/usr/lib/aarch64-linux-gnu
--     3rdparty dependencies:
-- 
--   OpenCV modules:
--     To be built:                 aruco bgsegm bioinspired calib3d ccalib core cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev datasets dnn dnn_objdetect dpm face features2d flann fuzzy gapi hfs highgui img_hash imgcodecs imgproc line_descriptor ml objdetect optflow phase_unwrapping photo plot python2 quality reg rgbd saliency shape stereo stitching structured_light superres surface_matching text tracking ts video videoio videostab xfeatures2d ximgproc xobjdetect xphoto
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 cnn_3dobj cvv freetype hdf java js matlab ovis python3 sfm viz
--     Applications:                tests perf_tests examples apps
--     Documentation:               NO
--     Non-free algorithms:         NO
-- 
--   GUI: 
--     GTK+:                        NO
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/aarch64-linux-gnu/libz.so (ver 1.2.11)
--     JPEG:                        libjpeg-turbo (ver 2.0.2-62)
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         build (ver 1.6.36)
--     TIFF:                        build (ver 42 - 4.0.10)
--     JPEG 2000:                   build (ver 1.900.1)
--     OpenEXR:                     build (ver 1.7.1)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
--     PFM:                         YES
-- 
--   Video I/O:
--     DC1394:                      NO
--     FFMPEG:                      NO
--       avcodec:                   NO
--       avformat:                  NO
--       avutil:                    NO
--       swscale:                   NO
--       avresample:                NO
--     GStreamer:                   YES (1.14.1)
--     v4l/v4l2:                    YES (linux/videodev2.h)
-- 
--   Parallel framework:            pthreads
-- 
--   Trace:                         YES (built-in)
-- 
--   Other third-party libraries:
--     Lapack:                      NO
--     Eigen:                       YES (ver 3.3.4)
--     Custom HAL:                  YES (carotene (ver 0.0.1))
--     Protobuf:                    build (3.5.1)
-- 
--   NVIDIA CUDA:                   YES (ver 10.0, CUFFT CUBLAS FAST_MATH)
--     NVIDIA GPU arch:             53
--     NVIDIA PTX archs:
-- 
--   OpenCL:                        YES (no extra features)
--     Include path:                /home/byeongkyu/Downloads/opencv-4.1.0/3rdparty/include/opencl/1.2
--     Link libraries:              Dynamic load
-- 
--   Python 2:
--     Interpreter:                 /usr/bin/python2.7 (ver 2.7.15)
--     Libraries:                   /usr/lib/aarch64-linux-gnu/libpython2.7.so (ver 2.7.15rc1)
--     numpy:                       /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.13.3)
--     install path:                lib/python2.7/dist-packages/cv2/python-2.7
-- 
--   Python 3:
--     Interpreter:                 /usr/bin/python3 (ver 3.6.7)
--     Libraries:                   /usr/lib/aarch64-linux-gnu/libpython3.6m.so (ver 3.6.7)
--     numpy:                       /usr/lib/python3/dist-packages/numpy/core/include (ver )
--     install path:                lib/python3.6/dist-packages/cv2/python-3.6
-- 
--   Python (for build):            /usr/bin/python3
--
--   Java:                          
--     ant:                         NO
--     JNI:                         NO
--     Java wrappers:               NO
--     Java tests:                  NO
-- 
--   Install to:                    /usr/local
-- -----------------------------------------------------------------
-- 
-- Configuring done
-- Generating done
-- Build files have been written to: /home/byeongkyu/Downloads/opencv-4.1.0/build

빌드 중 램 부족으로 인한 에러가 발생하므로, swap 파티션을 생성하여 이를 보완하도록 한다.

$ sudo fallocate -l 4.0G /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile

부팅시마다 마운트 하도록 다음의 파일 수정
$ sudo vi /etc/fstab

라인 추가
/swapfile none swap 0 0

자, 이제 빌드를 시작해보면…

$ make -j1

코어 4개를 적극 활용하면 좋겠으나, 램이 4기가 밖에 없는 관계로 램 부족과 같은 에러가 발생하거나 아예 멈춰버리는 불상사가 발생한다. 따라서 쓰레드 1개로 빌드 시작! 컴파일 시간이 어마어마하게 걸리고 방열판이 엄청나게 뜨거워지므로 조심.

빌드가 완료되면, 완료된 파일들을 설치한다. 설치 경로는 /usr/local 이다.

$ sudo make install

이제 제대로 설치되었는지 확인해본다.

$ opencv_version 
4.1.0

$ python3
>>> import cv2
>>> cv2
<module 'cv2' from '/usr/local/lib/python3.6/dist-packages/cv2/python-3.6/cv2.cpython-36m-aarch64-linux-gnu.so'>
>>> cv2.__version__
'4.1.0'

일단 설치는 여기까지!

Jetson Nano 무선랜(wifi + bluetooth) 카드 장착

Jetson Nano엔 무선랜 기능이 포함되어 있지 않다. 라즈베리파이도 3b+ 모델에서는 무선랜 기능이 포함되어 있는데, 뭐 그냥 붙여줬으면 좋으련만… USB 동글 등을 이용해서 사용할수 있겠지만, Jetson Nano에는 pci-e 확장포트가 존재한다. 따라서 이 포트에 m.2 규격의 무선랜 모듈을 장착하여 사용할 수 있다.

주변에 쉽게 구할 수 있고, 나름 리눅스 친화적인 무선랜 모듈은 인텔 제품이며 여러가지 버전이 존재한다. 현재 Jetson Nano의 커널 버전은 4.9 (L4T) 버전이므로, 현재 구할 수 있는 무선랜 모듈 중 가장 나은 선택은 Intel ac8265이다. Intel ac9560이 좀더 최신 칩셋에 나은 기능을 갖고 있지만, 드라이버가 커널 4.14 이상에서만 동작하므로 현재로선 사용이 불가능하다.

약 3만원 정도에 구입이 가능하다. 단 구입할때 안테나도 같이 구매하여야 한다. Intel ac8265의 주요 사양은 https://ark.intel.com/content/www/us/en/ark/products/94150/intel-dual-band-wireless-ac-8265.html 에서 확인 가능하다.

Jetson Nano의 옆 나사 두개를 풀어주고 모듈을 제거하면, 확장기판 내에 m.2 슬롯이 존재함을 볼수 있다. 나사를 풀러주고 구입한 무선랜 모듈을 장착한다.

안테나도 연결해준다. 저런 패치형 안테나 말고도, 일반적인 스틱형 안테나도 장착할 수 있다. (NGFF antenna 또는 M.2 wireless antenna로 검색하면 됨)

다시 코어 모듈을 조립하고 전원을 인가한다. 부팅이 완료된 후 터미널을 열어 다음과 같이 입력하여 무선랜 카드가 잘 인식되었는지 확인한다.

$ lspci
00:01.0 PCI bridge: NVIDIA Corporation Device 0fae (rev a1)
00:02.0 PCI bridge: NVIDIA Corporation Device 0faf (rev a1)
01:00.0 Network controller: Intel Corporation Wireless 8265 / 8275 (rev 50)
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 15)

이제 무선랜 및 블루투스 기능을 정상적으로 사용 가능하다.

끝!

안드로이드 앱 여러 개 권한 요청

앱을 설치하고 처음 실행시 여러 개의 권한 요청 방법. requestPermissions 함수를 사용하는데, 두번째 인자인 퍼미션 목록은 String Array 타입이다. 즉 여러 개의 권한을 한꺼번에 요청 가능.

필요한 권한 목록을 ArrayList<String>에 저장하고, 목록이 완성되면 requestPermissions을 이용해 권한 요청

ArrayList<String> permissions = new ArrayList<String>();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            permissions.add(Manifest.permission.RECORD_AUDIO);

...

if(permissions.size() > 0) {
            String[] reqPermissionArray = new String[permissions.size()];
            reqPermissionArray = permissions.toArray(reqPermissionArray);
            ActivityCompat.requestPermissions(this, reqPermissionArray, MY_PERMISSIONS_REQUEST_MULTI);
        }

사용자가 권한을 승인하거나 거절한 경우에 대한 대응은 onRequestPermissionsResult 함수에서 처리.

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

if(grantResults.length > 0) {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
    ...
    }

    ...
}

끗.

3D 프린트 이것저것 팁 & 의견

필라멘트

  • 일반 가정 집에서 ABS은 절대 사용 불가이다. 프린팅하는 동안 냄새도 고약하고, 건강엔 엄청 안좋다. PLA가 가장 무난하고, 강도를 필요로하는 것이라면 PETG를 사용하는 것을 추천함. (요즘은 PLA+ 등도 나오는데 뭐 별다른건 없는듯)
  • 난 PLA를 사용하다가 현재는 PETG를 사용중인데, 차이점은 PETG가 좀더 질기다라고 느껴진다. 출력이 완료되고 굳은 후 PLA는 힘을 주면 (엄청 쎄게) 똑 부러지는 반면 PETG는 살짝 구부려지다가 부러진다. 그러니깐 좀더 질기다라는게 맞는듯.
  • 싸구려 필라멘트는 저렴해서 좋긴한데, 필라멘트의 굵기가 일정하지 않거나 감겨있는 게 잘못되어 꼬여버리면 출력 중 필라멘트가 끊기는 참사가 발생함.

출력 팁

  • 출력시 바닥면이 뜨는 변형이 일어난다면, 바닥 온도를 살짝 올려보자.
  • 첫번째 레이어의 출력속도를 현저히 낮춰보는 것도 해결 방법.
  • 출력 후 옆면이 고르지 않게 나온다면, X, Y축의 벨트 텐션을 좀더 강하게 조정한다.
  • 출력 중 출력물이 안착이 안된고 날라다닌다면, 베드의 레벨링이 잘못된 경우이다. 레벨을 세심하게 조정해본다.
  • 첫번째 레이어가 좀더 크기 출력되는 경우 (일명 코끼리발 Elephant’s Foot 현상), 이를 보정하기 위한 옵션이 슬라이싱 툴에 존재한다. 정확히는 첫번째 레이어의 크기를 일정 비율만큼 줄이는 것임.
  • 간격이 떨어져있는 출력물에 거미줄 같이 지저분한 것이 많이 생긴다면, 출력 온도를 좀 낮춘다.

재미난 출력물들 찾기

텐서플로와 머신러닝으로 시작하는 자연어 처리

머신러닝, 자연어처리, 텐서플로…

TensorFlow는 그냥 툴이고 배우는데야 큰 문제는 없지만, 머신러닝을 이해하지 않고 TensorFlow를 배우는건 그냥 겉핥기만 될뿐인듯 하다. 문제는 그것을 배우고 활용하기 위한 전처리 작업들이 만만치 않다는 점. 초보자들이 양질의 데이터를 구하기란 매우 힘든 일인듯.

이 책은 그냥 자연어 처리에 이러한 방법도 있다라는 것을 보기 위해 구입한 책이다. 완벽하게 분석해서 내 것으로 만들면 좋겠지만, 내가 아직은 많이 필요한 내용이 아니므로 그냥 트렌드 파악용?

http://kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9791158391379&orderClick=JAj

파이썬으로 만드는 OpenCV 프로젝트

OpenCV는 영상처리 부분에선 많이 (그냥 99% 정도?) 사용되는 소프트웨어 프레임워크이다. 사실 기술서적은 버전이 변화함에 따라 쓸모없어지는 경우가 많아 구입이 좀 꺼려지긴하는데, 기본 기능들 (버전이 변하더라도 사용법은 거의 변하지 않는)에 대해 잘 정리되어 있는 책인듯 하여 구입하였다.

기본 기능부터, 약간의 고급 기능까지 함수들의 사용법에 대해 잘 정리되어 있고, Python으로 예제 코드가 되어 있고 결과물에 대해 스샷까지 잘 되어 있어 책상이 꼽아두었다가 필요할때 한번씩 꺼내볼만하다.

http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262410&orderClick=LEB&Kc=

제육볶음

재료: 돼지고기(앞다리살, 제육볶음용 600g), 양파 1개, 당근 반개 or 한개, 고추장, 고추가루, 간장, 마늘 간것, 올리고당, 설탕, 굴소스

  • 양파, 당근은 먹기 좋게 손질해 놓는다.
  • 고추장 2큰술, 고추가루 1큰술, 간장 2큰술, 마늘 간것 1큰술, 올리고당 한큰술, 굴소스 한큰술을 넣고 섞어 양념장을 만든다.
  • 돼지고기는 제육볶음용이면 얇게 썰어져 있고, 이를 다시 먹기 좋은 크기로 자른다.
  • 프라이팬에 돼지고기를 볶다가 색깔이 거의다 변했을 쯤, 설탕 2큰술을 넣고 잘 섞어준다.
  • 야채 손질해 놓은 것과 양념장을 넣고 잘 볶아준다.
  • 재료가 완전히 익었을 때 쯤, 깨소금을 뿌려서 마무리.
  • 상추 등 쌈채소에 싸서 맛있게 냠냠.

생각보다 엄청 간단하게 만들수 있고, 양도 대단히 푸짐하다. 돼지고기 한근 정도면, 2명이 충분히 먹을수 있을 만한 양인듯. 소스도 맛있어서 밥을 비벼 먹어도 괜찮음.

upip를 이용하여 MicroPython 라이브러리 설치하기

Python에서 pip를 이용해 라이브러리를 설치했던 것처럼, MicroPython에서도 upip를 이용하면 MicroPython으로 포팅된 Python 코어 라이브러리를 사용할 수 있다. (심지어 보드 레벨에서!!)

먼저, WiFi가 연결되어 있어야 한다.

>>> import network
>>> sta_if = network.WLAN(network.STA_IF)
>>> sta_if.active(True)
>>> sta_if.connect("<your-ap-name>", "<your-ap-password>")

연결이 되고 IP가 할당되었는지 확인 후,

>>> import upip
>>> upip.install("<설치할 패키지명>")

위와 같이 실행하면 보드에 직접 Python 라이브러리를 받아온다. 예를 들면,

>>> upip.install("micropython-uasyncio")
Installing to: /lib/
Warning: pypi.org SSL certificate is not validated
Installing micropython-uasyncio 2.3 from https://files.pythonhosted.org/packages/2f/d0/da285cf389f3736b204514f936b9621976735096ba02f6cd701ef0426a05/micropython-uasyncio-2.3.tar.gz
Installing micropython-uasyncio.core 2.3 from https://files.pythonhosted.org/packages/2b/3a/5737ff41dfe85d3ddf4c783e9289f6c869526fd31b495bf012612e6c82cf/micropython-uasyncio.core-2.3.tar.gz

>>> import uasyncio

MicroPython으로 포팅된 Python 코어 라이브러리는 https://github.com/micropython/micropython-lib/에서 확인 가능하다.

닭곰탕

가끔씩 해먹는 닭곰탕. 맛도 좋고, 만드는 방법도 간단해서 맛의 편차가 거의 없는 것이 장점이다.

  1. 준비물: 생닭 (9호 or 11호), 대파, 양파 1개, 통마늘
  2. 생닭은 마트에서 구입할 때 곰탕용이라고 말하면, 그에 맞게끔 잘 손질해 줌. 주로 통으로 가져오거나 반으로 쪼개서 가져오면 됨.
  3. 큰 냄비에 생닭, 대파, 양파, 통마늘을 넣고 끓인다.
  4. 40~50분 정도면 되지만, 좀더 부드럽게 먹으려면 1시간 이상 푸욱 끓인다.
  5. 닭이 익었는지 확인하고, 닭을 꺼낸다. 나머지 야채들은 건져서 버린다.
  6. 꺼낸 닭에서 살을 발라내고, 잘게 찢는다.
  7. 발라낸 닭뼈를 다시 냄비에 집어넣고 또 끓인다.
  8. 국물이 진하게 우려날 때쯤, 발라낸 살을 넣고 끓인다.
  9. 따뜻한 밥 한공기에 국물을 충분히 넣고, 채썬 파를 넣고 먹는다.

끝!

MicroPython REPL 이것저것 on ESP32

  • REPL 접속(?)

micropython은 자체적으로 REPL을 제공한다. UART0를 통해 PC와 연결되며, 이를 사용하기 위해선 시리얼통신 프로그램(picom, putty 등)을 사용하거나, 터미널에서 screen 명령 등을 이용해서 이용 가능하다.

$ screen /dev/tty.SLAB_USBtoUART 115200

접속 종료는 ctrl+a, ctrl+\를 순서대로 누른다.

  • REPL에서 자동완성 기능 사용

import 후, 혹은 내장 펑션을 사용하는 경우에 tab 키를 이용한 자동완성 기능을 제공한다. 예를 들어 machine을 import 하고 machine.까지 입력 후 tab 키를 눌러보면,

>>> import machine
>>> 
>>> machine.
__class__       __name__        ADC             DAC
DEEPSLEEP       DEEPSLEEP_RESET                 EXT0_WAKE
EXT1_WAKE       HARD_RESET      I2C             PIN_WAKE
PWM             PWRON_RESET     Pin             RTC
SLEEP           SOFT_RESET      SPI             Signal
TIMER_WAKE      TOUCHPAD_WAKE   Timer           TouchPad
UART            ULP_WAKE        WDT             WDT_RESET
deepsleep       disable_irq     enable_irq      freq
idle            lightsleep      mem16           mem32
mem8            reset           reset_cause     sleep
time_pulse_us   unique_id       wake_reason
>>> machine.

와 같이 사용가능한 변수 명 함수명을 보여주고, 자동완성도 가능함.

  • 긴 코드 붙여넣기

REPL에서 예제 코드나 좀 긴 코드를 테스트해보고자 할 경우, 복사 붙이기 모드가 지원된다. 한줄씩 입력해야 하는 번거로움을 좀 덜 수 있다. >>> 에서 Ctrl+E키를 누르면,

>>> 
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== 

와 같이 보이고, 여기에 긴 코드를 입력하던지, 아니면 다른 곳에서 코드를 복사해서 붙인다. 입력이 완료되면, Ctrl+D를 눌러 모드를 종료하면 입력된 코드를 순차적으로 실행한다. 취소하려면 Ctrl+C.

  • PC에서 직접 실행하기

REPL모드가 아니고, PC에서 코드를 완성하고 보드에 옮기지 않고 바로 실행이 가능하다. ampy를 이용하면 되는데,

$ ampy -p /dev/tty.SLAB_USBtoUART run <your_code>.py

와 같이 실행하면 바로 실행 가능.

WordPress에서 사용빈도를 반영한 태그 위젯 만들어 보기

참고링크: https://www.wpbeginner.com/plugins/how-to-display-most-popular-tags-in-wordpress

기본으로 제공되는 Tags 위젯은 사용된 Tag를 순서대로 모두다 보여줘서 좀 번거로운 면이 있다. 사용 빈도를 반영하여 많이 사용된 Tag를 크게 보여주고, 또 원하는 순위까지만 보여주는 것이 좀 괜찮을 것 같은데, 이를 위해선 해당 기능을 포함하는 플러그인을 설치해서 사용하거나, 간단히 functions.php를 수정하면 된다.

사용하는 테마의 디렉토리로 가서, functions.php 파일을 열고, 다음의 구문을 추가한다.

function wpb_tag_cloud() {
$tags = get_tags();
$args = array(
    'smallest'                  => 12,
    'largest'                   => 24,
    'unit'                      => 'px',
    'number'                    => 15,
    'format'                    => 'flat',
    'separator'                 => " ",
    'orderby'                   => 'count',
    'order'                     => 'DESC',
    'show_count'                => 1,
    'echo'                      => false
);

$tag_string = wp_generate_tag_cloud( $tags, $args );

return $tag_string;

}
// Add a shortcode so that we can use it in widgets, posts, and pages
add_shortcode('wpb_popular_tags', 'wpb_tag_cloud');

// Enable shortcode execution in text widget
add_filter ('widget_text', 'do_shortcode');

여기에서 설정할 옵션은

  • smallest: 가장 낮은 순위의 Tag 폰트 크기
  • largest: 가장 높은 순위의 Tag 폰트 크기
  • number: 15 순위까지 보여주기
  • seperator: Tag들 보여줄때 구분자

이와 같이 설정하고, Widget 설정에서 Text 위젯을 추가하고, 내용에 wpb_popular_tags을 입력한다. 결과를 보면,

와 같이 깔끔하게 보인다.

바나나 거치대 (Banana Stand)

바나나를 나무에 걸려 있는 모양으로 두면 보관을 오래할 수 있다고 한다. 옷걸이를 이용해서 만들거나, 파는 제품을 살 수도 있지만, 3D 프린터로 한번 만들어 본다.

CAD를 이용해서 모양을 만들고 (구조는 대단히 단순함)…

3D 프린터로 뽑아주면 (채움 20%, PETG 필라멘트 사용)…

이제 바나나를 걸어주면~~~~!!!

안정적으로 잘 매달려 있게 된다. 좀더 큰 것을 걸어두면 어떨런지는 모르겠는데, 일단은 만족!

Setup MicroPython on ESP32 (for macOS)

CP210x 드라이버 설치 (https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)

esptool 설치 (pip3가 없는 경우, homebrew를 이용해 설치한다)

$ pip3 install esptool

보드를 연결하고, 기존 flash 모두 초기화

$ esptool.py --chip esp32 -p /dev/tty.SLAB_USBtoUART erase_flash

esptool.py v2.6
Serial port /dev/tty.SLAB_USBtoUART
Connecting........__
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 84:0d:8e:0c:c9:f0
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 2.9s
Hard resetting via RTS pin...

펌웨어 다운로드 (https://micropython.org/download/#esp32)

펌웨어를 보드에 Flash 한다.

$ esptool.py --chip esp32 -p /dev/tty.SLAB_USBtoUART write_flash -z 0x1000 esp32-bluetooth.bin

esptool.py v2.6
Serial port /dev/tty.SLAB_USBtoUART
Connecting.....
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 84:0d:8e:0c:c9:f0
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1549888 bytes to 970594...
Wrote 1549888 bytes (970594 compressed) at 0x00001000 in 85.5 seconds (effective 145.0 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

보드의 전원을 껐다가 다시 인가하고, 터미널에서 다음과 같이 입력하여 REPL 환경으로 진입.

$ screen /dev/tty.SLAB_USBtoUART 115200

처음엔 아무런 내용이 나타나지 않지만, 명령어를 입력하면 됨. 평소 사용한 REPL 환경와 동일.

>>> print("hello")
hello
>>> 

REPL 환경에서 나오려면, ctrl + a, ctrl + \ 키를 순서대로 누르고, 화면 밑 프롬프트가 나오면 y를 눌러 종료 가능.

Adafruit에서 제공하는 Micro Python Tool을 이용해 보드 내부의 파일 시스템에 파일을 넣거나 스크립트를 실행할 수 있음.

$ pip3 install adafruit-ampy

보드 내부 파일 시스템에 있는 파일들 표시

$ ampy -p /dev/tty.SLAB_USBtoUART ls

/boot.py

다음의 명령어를 이용해 파일들 조작 가능.

ampy
Usage: ampy [OPTIONS] COMMAND [ARGS]...

  ampy - Adafruit MicroPython Tool

  Ampy is a tool to control MicroPython boards over a serial connection.
  Using ampy you can manipulate files on the board's internal filesystem and
  even run scripts.

Options:
  -p, --port PORT    Name of serial port for connected board.  Can optionally
                     specify with AMPY_PORT environment variable.  [required]
  -b, --baud BAUD    Baud rate for the serial connection (default 115200).
                     Can optionally specify with AMPY_BAUD environment
                     variable.
  -d, --delay DELAY  Delay in seconds before entering RAW MODE (default 0).
                     Can optionally specify with AMPY_DELAY environment
                     variable.
  --version          Show the version and exit.
  --help             Show this message and exit.

Commands:
  get    Retrieve a file from the board.
  ls     List contents of a directory on the board.
  mkdir  Create a directory on the board.
  put    Put a file or folder and its contents on the board.
  reset  Perform soft reset/reboot of the board.
  rm     Remove a file from the board.
  rmdir  Forcefully remove a folder and all its children from the board.
  run    Run a script and print its output.

보드에 있는 LED로 GPIO 테스트. 13번 핀에 연결되어 있음.

>>> import machine
>>> led = machine.Pin(13, machine.Pin.OUT)
>>> led.value(1)
>>> led.value(0)

일단은 여기까지.

참고링크: https://github.com/pvanallen/esp32-getstarted

짜장밥

준비물: 돼지고기, 양파 2개, 감자 반개, 호박 반개, 당근 반개, 짜장가루 (2인분)

  1. 양파를 채 썰고, 후라이펜에 기름을 두르고 볶는다.
  2. 양파가 갈색이 되면 돼지고기를 넣고 또 볶는다.
  3. 돼지고기에 핏기가 사라지면, 감자, 양파, 호박, 당근을 넣고 또 볶는다.
  4. 3번에 넣은 야채가 좀 익었다 싶으면, 물 700ml를 넣고 끓인다.
  5. 야채가 거의다 익었으면, 짜장가루를 넣고 불을 줄인 후 살살 섞어준다.

끝!.

전반적인 과정은 카레와 완전 비슷. 다만 야채의 모양을 좀 다르게 해주는게 나은 듯. 짜장밥에 들어가는 야채는 깍뚝썰기로.

카레

준비물: 돼지고기 or 소고기, 양파 2개, 당근 반개, 감자 반개, 카레 고형분 2인분, 버터 쪼금

  1. 양파, 당근, 감자는 얇게 채 썰기해서 준비. 당근, 감자는 채칼을 이용하면 쉽게 가능.
  2. 후라이팬에 버터 (없으면 올리브유)를 넣고, 양파를 다 넣고 살짝 갈색이 될때까지 볶는다.
  3. 고기를 넣고 볶는다.
  4. 고기가 핏기가 사라지면, 당근, 감자를 넣고 볶는다.
  5. 야채가 숨이 죽고 좀 익었다 싶으면 (이때쯤 양파는 좀더 진한 갈색으로 변함), 물을 700ml 정도 넣고 끓인다.
  6. 물이 끓기 시작하면, 카레를 넣고 저어준다.
  7. 야채가 완전히 익을때까지 저어준다.

끝!.

양파가 볶으면 볶을수록 단맛이 올라와, 아이들도 좋아하는 달달한 맛을 느낄수 있음. 거의 익어버려 양파의 아삭한 감이 사라지므로 먹기도 편함.

Jetson Nano GPIO 사용 해보기

Jetson Nano에는 라즈베리파이와 마찬가지로 40핀의 GPIO 헤더가 존재한다. 이를 이용해 다양한 외부기기와 연결 가능한데, python의 라이브러리를 이용하면 사용자가 제어 가능하다.

먼저 필요한 패키지를 설치한다. python3는 기본 설치되어 있고, pip3는 설치해야 한다.

$ sudo apt install python3-pip

다음으로 Jetson.GPIO 패키지를 설치한다.

$ sudo pip3 install Jetson.GPIO

이제 python3를 실행하고 설치한 패키지를 import 해보면 다음과 같이 퍼미션 에러가 발생한다. 몇가지 설정이 필요하다.

>>> import Jetson.GPIO
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/dist-packages/Jetson/GPIO/__init__.py", line 1, in <module>
    from .gpio import *
  File "/usr/local/lib/python3.6/dist-packages/Jetson/GPIO/gpio.py", line 33, in <module>
    raise RuntimeError("The current user does not have permissions set to "
RuntimeError: The current user does not have permissions set to access the library functionalites. Please configure permissions or use the root user to run this

gpio 그룹을 생성하고 사용자를 gpio 그룹에 추가한다.

$ sudo groupadd -f -r gpio
$ sudo usermod -a -G gpio <user_id>

다음으로 udev 룰을 rules.d 디렉토리로 복사한다.

$ sudo cp /opt/nvidia/jetson-gpio/etc/99-gpio.rules /etc/udev/rules.d/

재부팅하거나, 다음과 같이 입력하여 udev 룰을 다시 불러온다. (재부팅해야 함.)

$ sudo udevadm control --reload-rules && sudo udevadm trigger

이제 python3를 실행한 다음, 패키지를 import 해보면, 정상적으로 사용 가능하다. 몇가지 예제 코드들이 /opt/nvidia/jetson-gpio/samples에 있으므로 참고하면 될듯하다. 사용법은 RPi.GPIO와 동일하다.

>>> import Jetson.GPIO as GPIO
>>> GPIO.setmode(GPIO.BOARD)
>>> GPIO.setup(33, GPIO.OUT)
>>> GPIO.output(33, GPIO.HIGH)
>>> GPIO.output(33, GPIO.LOW)

위와 같이 간단히 사용 가능하고, 인터럽트, 콜백함수 등 다양한 기능을 지원한다. 몇가지 주의 사항으로는,

  • GPIO의 전압은 5V가 아닌 3.3V
  • PWM 기능은 지원하지 않음
  • I2C, SPI는 각각 두개씩 지원
  • 몇가지 특수펑션들 사용하고, 전원관련 핀을 빼면 여분의 GPIO는 별로 없는듯.

상세한 핀아웃은 https://www.jetsonhacks.com/nvidia-jetson-nano-j41-header-pinout/을 참고하면 됨.

Jetson Nano Developer Kit 사양 & 크기 정보

Technical Specifications

GPU128-core Maxwell
CPUQuad-core ARM A57 @ 1.43 GHz
Memory4 GB 64-bit LPDDR4 25.6 GB/s
StoragemicroSD (not included)
Video Encode4K @ 30 | 4x 1080p @ 30 | 9x 720p @ 30 (H.264/H.265)
Video Decode4K @ 60 | 2x 4K @ 30 | 8x 1080p @ 30 | 18x 720p @ 30 (H.264/H.265)
Camera1x MIPI CSI-2 DPHY lanes
ConnectivityGigabit Ethernet, M.2 Key E
DisplayHDMI 2.0 and eDP 1.4
USB4x USB 3.0, USB 2.0 Micro-B
OthersGPIO, I2C, I2S, SPI, UART
Mechanical100 mm x 80 mm x 29 mm

보드 자체의 크기는 실제 측정해보면 100mm x 79mm 이다. 나사 홀의 위치는 다음과 같다.

Blockly 실행 해보기

지난번 포스팅 (https://ahnbk.com/?p=469)대로 Blockly 소스를 받아 빌드하고, 그 결과물로 실행보도록 한다. 나중에 iOS나 Android에서도 어짜피 webview를 이용해서 실행해야 하므로, 과정은 동일하다.

먼저 작업할 디렉토리를 생성한다. 여기에선 편의상 blockly_demo란 디렉토리를 사용한다.

$ mkdir blockly_demo
$ cd blockly_demo

이제 이 디렉토리에 빌드된 파일을 복사한다.

javascript_compressed.js
blocks_compressed.js
blockly_compressed.js

다음으로 demos/mobile/html/toolbox_standard.js 툴박스 파일도 작업 디렉토리로 복사한다. 또 localization 관련한 디렉토리도 복사한다. 복사 위치는 msg 디렉토리 밑으로 한다. 본래 Blockly 디렉토리의 msg/js 디렉토리를 현재 개발 디렉토리로 복사한다. 완료되었으면 다음과 같이 보여야 한다.

이제 에디터를 이용해서 파일을 하나 생성한다. 파일 이름은 index.html 이다. 파일 내용은 다음과 같다.

<!DOCTYPE html>
<!-- HTML file to host Blockly in a mobile WebView. -->
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <link rel="stylesheet" href="styles.css">
  <script src="blockly_compressed.js"></script>
  <script src="blocks_compressed.js"></script>
  <!-- TODO: Select msg file based on locale. -->
  <script src="msg/js/en.js"></script>
  <script src="toolbox_standard.js"></script>
</head>
<body>
  <div id="blocklyDiv"></div>
  <script type="text/javascript">
    var workspacePlayground = Blockly.inject('blocklyDiv', {
          media: 'media/',
          toolbox: BLOCKLY_TOOLBOX_XML['standard'],
          zoom: {controls: true}
        });
  </script>
</body>
</html>

또 style.css 파일로 생성하여 다음과 같이 입력한다.

html, body, #blocklyDiv {
    border: 0;
    height: 100%;
    margin: 0;
    padding: 0;
    width: 100%;
}

이제 크롬, 사파리, 인터넷 익스플로러 등 웹브라우저를 이용해 index.html을 열어본다.

Blockly가 잘 로딩되어 실행됨을 볼수 있다.

벚꽃

아… 올해도 제대로 된 벚꽃 구경은 못하나보다. 매년 가자가자 했는데, 결국엔 벚꽃 구경 소식은 뉴스로만 듣게 되는듯.

독산역 앞 벚꽃거리

아쉬우나마 길거리 걸어가다 찍은 벚꽃 거리 사진을 올린다. 업무 때문에 정처없이 걸어다가 문득 보인 철길 옆으로 주욱 늘어선 벚꽃 나무 사진.

Jetson Nano Developer Kit 개봉기

지난 달에 열린 GTC에서 NVIDIA가 JETSON NANO를 발표하였습니다. 라즈베리파이만한 크기에 가격도 저렴? ($99)하고, 게다가 CUDA 코어까지 내장되어 있어, 요즘 유행하는 머신러닝 알고리즘들을 테스트 해보거나, 가지고 놀기 좋게끔 만든 보드인듯 합니다.

한국은 공식판매처가 한컴MDS로 되어 있어, 맘편하게 하나 주문해봤는데, 오늘에서야 도착했습니다. 아마 다른 분들도 다 오늘쯤 받으시겠네요.^^

패키징은 벌것 없습니다. 딸랑 종이박스 하나이고, 내용물도 메뉴얼을 제외하면 보드 하나만 들어있습니다. 흔한 USB 케이블도 없네요. 녹색 커버를 열면 아래와 같이 보드가 담겨있는 봉투가 보이고,

그 밑에 간단한 보드 메뉴얼과, 보드 받침대? 역할을 하는 종이접기류가 보이네요.

보드는 정전기 방지 봉투가 잘 포장되어 있고, 뜯어보면 많이 보셨던 JETSON NANO가 들어있습니다. 뭐 크게 감흥이 있는 건 아니고, 나노 모듈에 확장보드 형태로 되어 있습니다.

뒷면은 부품들을 배치하지 않아, 거의 평면이고, 다만 단자들이 전부다 노출되어 있는 관계로 사용하실땐 받침이나 커버가 꼭 있어야겠네요. (위에서 본 종이접기처럼….)

한쪽면에 확장 커넥터들을 몰아놨습니다. 왼쪽부터 DC어댑터 단자(5V/4A max), HDMI, DP, USB3.0 x4, Ethernet, Micro USB B (전원공급용, 5V/2A) 이고요.

보드 오른쪽은 라즈베리파이와 유사하게 확장 포트들이 배치되어 있습니다. GPIO와 POE 등. 반대쪽엔 UART, POWER SW, RESET, 카메라를 연결할 수 있는 단자가 보이고요. 여기에 라즈베리파이에 사용했던 카메라를 꼽을수 있다네요.

나노모듈을 제거하면 밑에 PCIe 확장포트가 보입니다.

여기에 아래 제품과 같은 무선랜/블루트스 카드를 꼽으면 무선 연결이 가능해집니다. 다른 용도로도 사용이 가능할 것 같고요. 다만 안테나가 비포함되어 있으니 안테나도 같이 주문해야 합니다.

나노모듈 밑에는 MicroSD 카드를 꼽을수 있습니다. JETSON 웹페이지에서 이미지를 다운로드 받아 SD카드에 굽고, 끼워서 부팅하면 됩니다.

라즈베리파이와 크기를 비교하면 가로 길이는 비슷하지만, 세로 길이가 좀 깁니다. 하지만 라즈베리파이의 경우 확장커넥터들이 오른쪽에 밀려있는 관계로 실제 조립하거나 사용할때는 나노가 좀더 편리할 수도 있겠단 생각이 듭니다.

몇가지 아쉬운 점들이 보이는데, USB C 단자를 설계해 놓고 Micro USB B 단자를 꼽아놓은 점, USB포트에 커넥터들 임시땜빵, 오디오출력이 가능함에도 오디오출력 포트가 없다는 점 등이 있네요. RTC를 위한 배터리 단자도 자리만 남겨놓고 조립은 안했네요.

뭐.. 처음 제작된 제품이니 조만간 리비전되어 나올 듯 합니다. 전원을 넣고 부팅하면 Ubuntu 설치할 때와 마찬가지로 언어선택, 키보드, 계정 생성 등의 진행절차가 나오고 완료하면 Ubuntu로 부팅이 가능합니다. Ubuntu 버전은 18.04가 설치되어 있으며, 일단 처음 설치한 후의 느낌은 라즈베리파이보단 좀더 쾌적하게 움직인다 정도 입니다.

Prusament PETG Urban Grey 필라멘트 구입

Prusa i3 MK3를 구입하고 번들로 같이 왔던 Prusament PLA Galaxy Silver 필라멘트를 사용해왔더랬습니다. 짙은 회색에 PLA 재질이라 프린트 품질도 훌륭하고 표면도 아주 괜찮았습니다만… 그럭저럭 사용하다보니 한 롤을 다 써버렸습니다.

처음에 같이 주문했던 Prusament PLA Azure Blue, Prusament PLA Lipstick Red도 있긴 했지만 색상이 상당히 튀는 색이라 나중에 특별한 넘 뽑을때나 사용하기로 하고, 일반적으로 사용할 필라멘트를 추가 주문하였습니다.

이번에 주문한 제품은 Prusament PETG Urban Grey로 밝은 회색 빛의 PETG 재질의 필라멘트입니다. PETG는 PLA 보다 강도도 뛰어나고, ABS에 비해 환경 유해물질도 나오지 않습니다. 또 프린트 중 냄새도 현저히 없는 수준이고요.

오늘 받아서 간단히 큐브를 프린트 해보았는데, 출력 중 변홍도 없고 꽤 괜찮게 나옵니다. 다만 노즐 온도가 290도, 베드 온도가 90도까지 올라가야하니 PLA 출력때보다 열기가 좀 느껴지네요. 냄새도 PLA보다 덜 납니다. 가격은 한롤 당 $28.49 정도로 저렴한 PETG보단 비싼 편이나 Prusa에서 셋팅한 값을 그대로 사용할 수 있고, 출력 품질도 보장되니 그다지 비싸게 느껴지진 않습니다.

Scratch 3.0 블로킹 블럭 만들기

확장블럭 중 블로킹 기능을 필요로 하는 블럭을 만들어야 할 필요가 있다. 예를 들면 로봇의 경우 setDistance, setRotation 등 특정 거리나 특정 각도까지 움직이고, 이때 동작이 완료될 때까지 기다려야 하는 블럭이 존재한다.

Scratch 3.0의 Extension의 경우 개발 언어는 Javascript이다. 따라서 일반 언어에서 사용하듯 while 문을 이용한 제어가 불가능하다. 만약 while 문을 사용하면 스크립트 실행 자체가 멈춰버리므로, 프로그램 자체가 멈춰버리고, 이게 길게되면 각종 브라우저에서 에러와 같이 인식한다.

이를 구현하기 위해서 Promise와 setInterval의 조합으로 해결이 가능하다. 로봇이 움직이고 있다는 신호는 로봇의 상태 정보를 통해 파악할 수 있고, 움직이는 명령을 보낸 후, 로봇의 상태 정보를 지속적으로 모니터링하여 로봇의 동작이 완료되었음을 의미하는 플래그가 셋되면 블럭의 동작을 완료하면 된다.

기존 setDistance() 함수는 다음과 같이 되어 있다.

setDistance (args) {
    const l_dist = parseInt(args.L_DIST);
    const r_dist = parseInt(args.R_DIST);

    this._peripheral.setDistance(l_dist, r_dist);
}

이제 여기에 플래그를 모니터링하고, 블럭의 동작을 완료하는 부분을 추가한다.

setDistance (args) {
    const l_dist = parseInt(args.L_DIST);
    const r_dist = parseInt(args.R_DIST);

    this._peripheral.setDistance(l_dist, r_dist);

    return new Promise(resolve => {
        var first_check = true;
        var ttt = setInterval(() => {
            if(this._peripheral.isRobotMoving == false && first_check == true) {
                first_check = false;
            }
            else if(this._peripheral.isRobotMoving == false && first_check == false) {
                resolve();
                clearInterval(ttt);
            }
        }, 100);
    });
}

이제 로봇의 연결하고 위 블럭을 실행해보면, 다음과 같이 동작이 완료될 때까지 대기함을 볼 수 있다.

워드프레스에서 카테고리 리스트 페이지 만들기

워드프레스에서 카테고리를 선택하였을 때, 해당 카테고리에 해당되는 포스트들의 리스트만 보여주는 페이지가 필요할 수 있다. 아마 찾아보면 플러그인도 있긴 할텐데, 간단히 파일 하나 정도만 생성해주면 사용자가 원하는 카테고리 페이지를 만들 수 있다.

현재 사용하고 있는 테마의 디렉토리로 이동한다.

$ cd /var/www/html/wp-content/theme/twentyseventeen

category.php 파일을 생성한다. 만약 카테고리 이름별로 페이지를 생성하고 싶다면, 원하는 카테고리 이름을 추가하여 만들어주면 된다. 예를 들어 scratch 카테고리 페이지를 만든다면, category-scratch.php를 만들어준다. 워드프레스는 해당 페이지를 읽을 때 우선순위를 두게 되는데,

category-{name}.php — category.php — archive.php — index.php

와 같은 우선순위를 두고 읽게 된다.

category.php 파일을 생성하고, 다음과 같이 입력한다. archive.php 파일에서 필요한 부분만 수정하였다.

<?php
    get_header(); ?>

<div class="wrap">
    <?php if ( have_posts() ) : ?>
        <header class="page-header">
        <?php
            the_archive_title( '<h1 class="page-title">', '</h1>' );
            the_archive_description( '<div class="taxonomy-description">', '</div>' );
        ?>
        </header><!-- .page-header -->
    <?php endif; ?>

    <div id="primary" class="content-area">
        <main id="main" class="site-main" role="main">

        <?php
        if ( have_posts() ) :
        ?>
        <?php
            /* Start the Loop */
            while ( have_posts() ) :
                    the_post(); ?>

            <div id="category-post">+ <a href="<?php the_permalink(); ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a>
            <small><?php the_time('F jS, Y') ?> by <?php the_author_posts_link() ?></small> </div>

            <?php
            endwhile;
        else :
            get_template_part( 'template-parts/post/content', 'none' );
        endif;
        ?>
        </main>
    </div>
<?php get_sidebar(); ?>
</div>

<?php
get_footer();

저장한 다음, 다시 블로그에서 카테고리를 선택하면 다음과 같이 보인다.

이때 보여지는 포스트의 수는 워드프레스의 Reading 설정에 있는 갯수를 따른다. 이를 늘려도 되지만, 그렇게 되면 첫 페이지에 보여지는 포스트의 수가 너무 늘어나게 되므로, archive 페이지에서만 보여지는 포스트의 수를 늘려주도록 한다.

마찬가지로 테마의 디렉토리에서 functions.php 파일을 열어 다음의 내용을 추가한다.

add_action( 'pre_get_posts', 'prefix_category_query' );
function prefix_category_query( $query ) {
    if( is_archive() && $query->is_main_query() ) {
        $query->set( 'posts_per_page', '100' );
    }
}

archive 페이지의 경우에 보여지는 포스트의 수를 100개로 늘렸다. 이제 다시 카테고리를 선택해보면,

전체 포스트가 잘 보여짐을 볼 수 있다.

Scratch 3.0 업데이트

스크레치 3.0은 현재도 활발하게 업데이트가 진행 중이다. 이에 따라, 기존에 작성하였던 Extension들도 이에 맞추어 몇가지 수정해야 하는 상황이 발생한다.

scratch-gui

  • 확장카드의 이미지들의 위치가 한 디렉토리로 통일됨. 기존은 외부 연결에 사용되는 아이콘 그림의 경우 peripheral-connection에 넣었으나, 이젠 확장카드 이름의 디렉토리에 모두 넣어 사용하고 peripheral-connection 디렉토리는 사라짐.
  • 기존 외부링크로 되어 있던 리소스들이 로컬로 전환 중. 사운드, 이미지 등이 로컬 파일로 존재. 즉, 이제 인터넷 연결 없이도 원할히 사용 가능.
  • 확장카드 추가 – gdx, LEGO Boost 등

scratch-vm

  • 추가된 확장카드에 대한 소스들 추가.

scratch-l10n

  • 추가된 확장카드에 대한 언어 추가.

Wire cover for Dynamixel PRO

로봇 조립 중 다이나믹셀의 전선을 바짝 붙여야 할 일이 생겼습니다. 전선이야 케이블타이로 잘 정리하면 되겠지만 그렇게 묶은 전선이 로봇 관절이 움직일때 영향을 줄 수도 있어서 정리하기 위한 커버가 필요했습니다.

사용하려는 모델은 H42P-020-S300-R 이고, 프로 모델 중에선 가장 작은 타입입니다.

H42P-020-S300-R

다행스럽게 로보티즈에서 도면 및 step 모델 등을 제공해주므로 쉽게 만들수 있습니다. 일단 onshape.com으로 가서, 다운로드한 모터의 step 파일을 업로드해서 만듭니다.

이제 모델의 크기를 반영해서 커버를 만들어줍니다. 전선이 지나갈 홈도 파 주고요. 다 그렸으면 어셈블리로 모터에 붙여서 크기가 잘 맞는지 확인해봅니다.

잘 맞는것 같네요. 이제 이걸 stl 파일로 export하고, 슬라이서 프로그램을 통해 gcode를 생성해줍니다. 양쪽 두개가 필요하니까 한꺼번에 두개를 배치하고 생성!. 표면이 거칠어도 사용하는데는 큰 무리가 없으니, 적측두깨는 0.2mm로 강도는 좀 있어야 하니 채움은 30% 정도?

약 1시간 40분 정도 걸린다고 나오네요.. 프린터로 옮겨서 출력을 해주면!!??

이렇게 예쁘게 출력이 잘되고~~, 모터와 결합해보면??!!

모터의 크기에 딱! 맞게 끼워지고, 나사 구멍의 위치도 정확하게 맞네요..^^

끗!

M5STACK FIRE DEVELOPMENT KIT

M5Stack은 ESP32를 사용하여 만들어진 개발용 킷트이다. 현재 참여하고 있는 EduBot에도 ESP32가 들어가는데, 이번에 구입한 FIRE 버전은 16M Flash와 4M PSRAM을 가진 ESP32가 들어가 있다. (좀더 용량이 낭낭하게 많아졌단 얘기, 램도.. 어쨌든 다다익선).

현재 알리익스프레스에서 팔고 있고, 한국에서도 위즈넷(?)이란 곳에서 판매하고 있다고 한다.

구매링크 바로가기

가격은 대략 7만원 ~ 8만원대인데, 구성이 상당히 알차게 들어 있다. 마이크, 스피커, BLE, WiFi, 가속도, 자이로, 지자기센서, LCD, 버튼, RGB LED 등등 단독으로 사용해도 뭔가 재밌는 것을 만들어볼수 있을 것 같다. 물론 확장포트도 있어서, 외부센서를 추가로 연결할 수 있다. 배터리도 내장되어 있어 충전독 혹은 USB-C 케이블을 이용하여 충전한다.

io.m5go.com 웹페이지를 이용하여 온라인으로 블럭코딩 및 코딩을 하여 M5Stack를 제어할 수 있다. WiFi가 지원된다는 이점을 활용한 것 같다.

위 웹페이지에서 만든 블럭코딩 결과물을 실행하면, 현재 내가 갖고 있는 M5Stack에서 바로 실행된다. (WiFi가 연결되지 않으면 당연히 사용할 수 없음)

코어 성능도 빠방하고, 직접 개발시 Arduino Sketch를 사용하고 M5Stack에 대한 Library도 충분히 지원되니 환경 설정에 애먹고 시간을 허비하는 일은 거의 없을 듯 하다.

이외에도 요새 유행한다는 마이크로 Python도 돌아간다고 하고… 뭐 용도는 무궁무진할 듯.

자~ 이제 이걸로 뭘 해 볼까나??

Blockly 개발환경 구축

Blockly는 오픈소스로 소스가 모두 개방되어 있다. 이를 가져와 개발자의 의도 및 용도에 맞게 수정하여 사용 가능하다. Blockly는 미들웨어 성격으로, 사용자의 어플리케이션에 맞게끔 수정 및 기능 추가가 용이하다.

일단 Blockly 소스를 가져와 빌드해보도록 한다. Javascript의 빌드 결과물은 주로 xxxx_compressed.js의 이름으로 저장되며, 여러개로 분산된 코드를 하나의 파일에 압축(정확히는 함축)하여 저장한다.

먼저 소스를 가져온다. github의 Blockly 레포지토리 (https://github.com/google/blockly/releases) 에서 최신 릴리즈 소스 (https://github.com/google/blockly/archive/1.20190215.0.tar.gz)를 다운로드한다.

받은 압축 파일을 임의의 디렉토리로 이동한 후 압축을 푼다. (본 포스팅에선 ~/Developer 를 사용.)

$ cd ~/Developer
$ tar zxf blockly-1.20190215.0.tar.gz

빌드하기 위해선 일단 python2.7이 설치되어 있어야 한다. (macOS엔 python 2.7이 기본 설치되어 있으므로 괜찮음. Windows에선 따로 설치 필요)

$ cd blockly-1.20190215.0
$ ./build.py

이때 다음과 같은 에러가 발생하면, closure-library가 필요하다.

Error: Closure not found.  Read this:
developers.google.com/blockly/guides/modify/web/closure

위 에러 메시지에서 알려준 링크 (developers.google.com/blockly/guides/modify/web/closure)로 가서 압축 파일을 다운로드 한다.

받은 파일을 ~/Developer에 풀고, 디렉토리 이름을 closure-library로 변경한다.

$ cd ~/Developer
$ tar zxf ~/Downloads/google-closure-library-v20190301-20-gde66a8a.tar.gz 
$ mv google-closure-library-de66a8a closure-library

이제 다시 blockly 디렉토리로 이동하여 빌드한다.

$ cd blockly-1.20190215.0
$ ./build.py

여러 메시지가 쭈욱 나오고, 에러가 없이 마무리되면 다음과 같은 파일이 생성된다. (이미 컴파일된 파일이 있긴 하지만, 업데이트 된다) 만약 java.lang.RuntimeException: INTERNAL COMPILER ERROR와 같은 에러가 발생한다면, 잠시후 다시 실행하면 정상적으로 빌드 된다.

...

SUCCESS: msg/js/tlh.js
SUCCESS: msg/js/ba.js
SUCCESS: blockly_uncompressed.js
SUCCESS: blockly_accessible_uncompressed.js
SUCCESS: blockly_compressed.js
Size changed from 2637 KB to 780 KB (30%).
SUCCESS: blockly_accessible_compressed.js
Size changed from 2739 KB to 826 KB (30%).
SUCCESS: blocks_compressed.js
Size changed from 154 KB to 74 KB (48%).
SUCCESS: javascript_compressed.js
Size changed from 85 KB to 47 KB (56%).
SUCCESS: python_compressed.js
Size changed from 71 KB to 36 KB (51%).
SUCCESS: php_compressed.js
Size changed from 74 KB to 38 KB (52%).
SUCCESS: lua_compressed.js
Size changed from 66 KB to 33 KB (50%).
SUCCESS: dart_compressed.js
Size changed from 78 KB to 41 KB (52%).

빌드 완료.

생성된 파일의 용도를 설명하면…

  • blockly_compressed.js : Blockly 코어 파일
  • blocks_compressed.js : 기본 블럭
  • javascript_compressed : Javascript 코드 제너레이터
  • python_compressed.js : Python 코드 제너레이터
  • php_compressed.js : PHP 코드 제너레이터
  • lua_compressed.js : Lua 코드 제너레이터
  • dart_compressed.js : Dart 코드 제너레이터

끗!

납걸이 (릴납 스탠드)

인두기를 구입할 때 납걸이 (릴납 스탠드)를 같이 구매했어야 됐는데, 시기를 놓치니 그냥 귀찮더라도 릴납에서 납을 조금씩 풀어서 사용하고 있었습니다. 대충 6,000원 정도 하는데 그것만 주문하기도 좀 애매하기도 했고, 다른 것 주문할 땐 꼭 까먹더라고요.

3D 프린터도 요즘 슬슬 사용하고 있겠다, 모델링 하는 것도 어렵진 않아서 사용하고 있는 릴납 기준으로 납걸이를 만들어보았습니다. 사용하고 있는 실납입니다, (http://eleparts.co.kr/goods/view?no=3224253)유연 실납으로 땜질할 때도 냄새도 거의 나지 않고, 품질도 좋습니다. 저정도 양이면… 특별한 일이 없는 한 거의 평생 사용할 것 같네요.

크기는 자를 이용해서 가운데 봉이 들어갈 부분의 지름과 전체 길이, 전체 지름 등을 재고, onshape.com에서 모델을 만듭니다. 총 3개의 파트로 구성되고, 베이스, 릴납이 끼워질 부분, 양쪽으로 움직이지 못하게 하는 마개 부분이네요.

이제 이것을 STL 파일로 변환해서 슬라이서 툴에 넣고, gcode를 생성합니다. 워낙 단순 생김새이니 infill은 15%, 적층두께는 0.2mm로 좀더 빠르게 설정했습니다. 필라멘트 색상을 교환해 가면서 뽑으면 좀더 이쁘겠지만, 역시 귀차니즘에 의해서 그레이 색상으로 통일.

출력 결과는…..

짜잔!!

이제 자알 조립해 보면,

파는 제품에 비교해봐도 손색이 없는 품질! 생긴것도 깔끔하고요..^^ 끗!

Blockly 소개

Blockly (블럭클리?, 블로키?)는 구글에서 오픈소스로 개발하고 있는  visual programming editors (소위 블럭코딩)을 개발하기 위한 Javascript 라이브러리이다. Scratch 3.0도 블럭을 제어하기 위한 부분은 Blockly 라이브러리를 가져와 수정하여 사용하고 있다.

대다수의 블럭코딩 툴들이 Blockly를 기반으로 개발되고 있다. 라이센스는 Apach 2.0을 사용하며, 소스는 https://github.com/google/blockly에 있다. 상업적 사용이 가능하고, 변경 및 배포에 아무런 제약이 없다.

Scratch 3.0이 그만의 프레임웍에 맞추어 개발해야 했다면, Blockly는 사용자가 자유롭게 변형하여 목적에 맞는 프로그램을 개발 가능하다.

블럭으로 만들어놓은 부분을 각종 언어 (Javascript, Pythom, Lua, Dart 등)로 생성이 가능하다. 또 사용자가 원하는 블럭도 생성이 가능하다. 코어가 Javascript로 되어 있어, 웹은 물론 Android, iOS에서도 WebView를 통해 실행이 가능하다. (동일한 코드로)

https://developers.google.com/blockly/ 이 메인 싸이트이며, Blockly에 대한 설명, 사용방법, 개발 방법 등에 대한 부분이 상세하게 적혀있다.

https://groups.google.com/forum/#!forum/blockly 는 Blockly 사용자들이 모여 있는 포럼으로 다수의 사용자들이 Blockly를 Customizing하고, 다양한 사례에 적용할 때 발생하는 문제점을 제시하고 서로 논의 하는 곳이다.


Scratch 3.0 exe, app으로 패키징하기

모든 개발이 완료되고, 배포를 해야 하는 경우에 윈도우의 경우 exe 파일, macOS의 경우 .app으로 패키징하여야 한다. 물론 소스 파일을 배포하고 사용자가 지난번 포스팅(https://ahnbk.com/?p=366, https://ahnbk.com/?p=383)과 같이 개발환경을 갖추어서 실행할 수 있지만 매우 복잡하고, 릴리즈 모드가 아닌 관계로 살짝 느린 면이있다.

Scratch 3.0은 React.js를 사용하여 개발되었다. 즉 이를 실행하기 위해선 웹브라우저가 필요하다. 개발 시에는 webpack-dev-server를 이용하였다. 이를 대체할 것이 필요한데, 이때 필요한 것이 Electron(https://electronjs.org)이다.

Electron은 NodeJS, Chromium을 이용하여 JavaScript, HTML, CSS를 이용하여 동일한 소스로 Windows, macOS, Linux 등에서 실행 가능한 Desktop 앱을 개발할 수 있는 플랫폼이다.

Electron은 npm을 이용하여 쉽게 설치할 수 있다.

$ npm install -g electron

다음으로 지금까지 개발한 Scratch 3.0을 릴리즈 형태로 빌드한다. Scratch-gui 디렉토리로 이동하여 다음과 같이 입력한다.

$ cd scratch-gui
$ npm run-script build

이제 빌드가 완료되면, build 디렉토리에 release 모드로 빌드된 파일들이 생성되어 있음을 볼 수 있다.

이제 편의상 scratch-app 디렉토리를 하나 생성하고 위 build 디렉토리를 복사한다. 다음으로 election 앱을 만들기 위해 다음과 같이 입력한다.

$ cd scratch-app
$ npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (scratch-app) 
version: (1.0.0) 
description: Scratch 3.0 for OROCA Edubot
entry point: (index.js) main.js
test command: 
git repository: 
keywords: scratch, oroca, edubot, block-coding
author: Byeong-Kyu Ahn
license: (ISC) BSD-2-Clause
About to write to /Users/byeongkyu/Developer/scratch/scratch-app/package.json:

{
  "name": "scratch-app",
  "version": "1.0.0",
  "description": "Scratch 3.0 for OROCA Edubot",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "scratch",
    "oroca",
    "edubot",
    "block-coding"
  ],
  "author": "Byeong-Kyu Ahn",
  "license": "BSD-2-Clause"
}


Is this OK? (yes) 

위와 같이 사용자의 환경에 맞추어 입력하게 되면, package.json 파일이 생성되어 있음을 볼수 있다. package.json 파일을 에디터를 이용해 다음과 같이 수정한다.

{
  "name": "scratch-app",
  "version": "1.0.0",
  "description": "Scratch 3.0 for OROCA Edubot",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "keywords": [
    "scratch",
    "oroca",
    "edubot",
    "block-coding"
  ],
  "author": "Byeong-Kyu Ahn",
  "license": "BSD-2-Clause"
}

이제 main.js 파일을 생성하고 다음과 같이 입력한다.

const { app, BrowserWindow } = require('electron')
var path = require('path')

let win

function createWindow () {
  win = new BrowserWindow({
    frame: true,
    width: 1200,
    height: 800,
    icon: path.join(__dirname, 'assets/icons/png/64x64.png')
  })

  win.loadFile('./build/index.html')

  win.on('closed', () => {
    win = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (win === null) {
    createWindow()
  }
})

다음과 같이 입력하여 실행해 본다.

$ npm start

정상적으로 되었다면, 앱이 실행 됨을 볼 수 있다.

이제 이렇게 생성된 electron 앱을 패키징하는 과정만 남아 있다. 먼저 앱의 아이콘을 생성한다. 기본값은 Electron의 기본 아이콘이다. 이미지 편집기 등을 이용하여 1024×1024 크기의 png 파일을 생성한다.

윈도우 앱의 경우 ico 파일을 사용하고, macOS의 경우 icn 파일을 사용한다. https://icoconvert.com, https://iconverticons.com/online 등의 웹페이지에서 변환이 가능하다. 생성된 파일을 scratch-app 디렉토리에 복사한다.

다음으로 electron-packager를 설치한다. npm을 이용하여 쉽게 설치할 수 있다.

$ npm install -g electron-packager

다음으로 패키징에 필요한 electron을 설치한다.

$ cd scratch-app
$ npm install --save-dev electron

마지막으로 macOS용 앱을 패키지할 경우 다음과 같이 입력한다.

$ electron-packager . --overwrite --platform=darwin --arch=x64 --icon=./assets/icons/edubot_icon.icns --prune=true --out=release-builds

다음과 같은 메시지가 나오면 성공

Packaging app for platform darwin x64 using electron v4.0.8
Wrote new app to release-builds/scratch-app-darwin-x64

이제 위에서 알려준 디렉토리로 이동해 보면 .app 파일이 생성되어 있음을 볼 수 있다. macOS의 경우 /Application으로 복사하여 사용하면 된다.

윈도우용 앱을 패키징 할 때, macOS에서 진행하는 경우 wine 툴이 필요하다. homebrew를 이용하여 쉽게 설치가 가능하다.

$ brew install wine

설치가 완료되면, 다음과 같이 입력하여 윈도우용 앱을 패키징한다.

$ electron-packager . scratch-edubot-app --overwrite --platform=win32 --arch=x64 --icon=assets/icons/edubot_icon.ico --prune=true --out=release-builds --version-string.CompanyName="OROCA" --version-string.FileDescription="OROCA Edubot" --version-string.ProductName="Scratch Edubot"

다음과 같은 메시지가 나오고 해당 디렉토리로 이동하면 exe 파일이 생성됨을 볼 수 있다.

Packaging app for platform win32 x64 using electron v4.0.8
Wrote new app to release-builds/scratch-edubot-app-win32-x64

위 디렉토리를 압축하여 윈도우 환경에서 exe 파일을 실행한다.

끝!

Scratch 3.0 확장블럭 종류

Scratch엔 다양한 종류의 블럭들이 존재한다. 사용자가 확장 블럭을 만들 경우, 제공되는 데이터의 종류에 맞추어 블럭을 만들어야 하는데, 반드시 다음의 종류 중 하나 이어야 한다.

참고할 파일은 scratch/scratch-vm/src/extension-support/block-type.js이다.

1.BOOLEAN

육각형 모양으로 되어 있으며, 출력 결과는 true or false 두개의 값만을 가진다. 주로 논리(If else 등)에서 사용된다.

2.COMMAND

위와 아래에 다른 블럭을 연결할 수 있으며, 주로 어떠한 명령을 내리기 위해 사용한다.

3.CONDITIONAL

COMMAND 블럭의 특수한 형태로, 주어진 조건에 맞을 시, 바로 아래에 연결된 블럭을 실행한다. 조건이 맞든 맞지 않든, 다음 블럭으로 무조건 실행한다. (Non blocking 실행이라는 의미인듯)

4.HAT

위와 같이 생긴 블럭으로 스택 (블럭들이 연결되어 있는 모듬)의 처음에만 위치 할 수 있다. 한마디로 특정 기능의 맨처음에 위치

5.EVENT

HAT 블럭의 특수한 형태로, 특정 이벤트를 만족하면 실행하는 블럭. 거의 대부분의 HAT 블럭이 이와 같은 형태임.

6.LOOP

위아래 블럭 연결이 가능하고, Child 블럭을 포함하는 블럭. Child 블럭을 반복하여 실행함. 횟수나 조건식 등을 포함하여 Loop를 제어할 수 있음.

7. REPORTER

숫자나 문자등 값을 저장하고 있는 블럭. 단일값인 경우 앞쪽에 체크 박스가 존재하며 이를 클릭하면 Sprite 화면에서 값을 모니터링 가능. 배열값인 경우는 체크박스가 존재하지 않으며, 블럭을 터치하는 경우 값 확인 가능.

solve connection problem for surface mouse on ubuntu 16.04

Edit the file /etc/bluetooth/main.conf

line 89, uncomment

AutoEnable=false -> AutoEnable=true

and, edit the file /lib/udev/rules.d/50-bluetooth-hci-auto-poweron.rules

uncomment all

# Set bluetooth power up
ACTION=="add", SUBSYSTEM=="bluetooth", KERNEL=="hci[0-9]*", RUN+="/bin/hciconfig %k up"

done.

Scratch 3.0 확장블럭 다국어 지원

Scratch 3.0은 다국어를 지원한다. 인터페이스에서부터 블럭까지 모든 부분을 다국어를 지원하도록 만들수 있다. 이를 위해선 scratch-l10n 을 수정하여야 한다.

먼저 지난번 개발환경 구축과 마찬가지로 scratch-l10n을 클론하여 사용한다. 지난번 Scratch 개발 공간 내에 다음과 같이 입력한다.

$ git clone https://github.com/byeongkyu/scratch-l10n.git
$ cd scratch-l10n
$ npm install
$ npm link

이제 scratch-gui가 local에 있는 scratch-l10n을 사용하도록 연결하여 준다.

$ cd scratch-gui
$ npm install
$ npm link scratch-l10n scratch-blocks scratch-vm
/Users/byeongkyu/Developer/scratch/scratch-gui/node_modules/scratch-blocks -> /usr/local/lib/node_modules/scratch-blocks -> /Users/byeongkyu/Developer/scratch/scratch-blocks
/Users/byeongkyu/Developer/scratch/scratch-gui/node_modules/scratch-vm -> /usr/local/lib/node_modules/scratch-vm -> /Users/byeongkyu/Developer/scratch/scratch-vm
/Users/byeongkyu/Developer/scratch/scratch-gui/node_modules/scratch-l10n -> /usr/local/lib/node_modules/scratch-l10n -> /Users/byeongkyu/Developer/scratch/scratch-l10n

확장카드

먼저 확장카드에 대한 부분을 수정해보록 한다. 지난번 설명했던 바와 같이, 확장카드는 scratch/scratch-gui/src/lib/libraries/extensions/index.jsx 파일 내에 위치한다. Edubot의 경우엔 다음과 같이 되어 있다.

    {
        name: 'OROCA Edubot',
        extensionId: 'edubot',
        collaborator: 'OROCA',
        iconURL: edubotImage,
        insetIconURL: edubotMenuImage,
        description: (
            <FormattedMessage
                defaultMessage="Play with powerful small robot!"
                description="Description for the 'OROCA_Edubot' extension"
                id="gui.extension.edubot.description"
            />
        ),
        featured: true,
        disabled: false,
        bluetoothRequired: true,
        launchPeripheralConnectionFlow: true,
        useAutoScan: false,
        peripheralImage: edubotPeripheralImage,
        smallPeripheralImage: edubotMenuImage,
        connectingMessage: (
            <FormattedMessage
                defaultMessage="Connecting"
                description="Message to help people connect to their edubot."
                id="gui.extension.edubot.connectingMessage"
            />
        ),
        helpLink: 'https://github.com/oroca/OROCA-EduBot'
    },

여기에서 다국어 지원이 가능한 부분은 description의 “Play with powerful small robot!”과 connectingMessage의 “Connecting”이다. 이 부분은 각각 gui.extension.edubot.description과 gui.extension.edubot.connectingMessage와 같은 id를 가지고 있다.

이제 다시 scratch-l10n으로 가서 다음의 경로에 있는 파일을 수정한다.

scratch/scratch-l10n/editor/interface/en.js

파일을 열고, 임의의 곳에 다음과 같이 입력한다.

    "gui.extension.edubot.description": "Play with powerful small robot!",
    "gui.extension.edubot.connectingMessage": "Connecting",

이제 한국어를 지원하게 하려면, 같은 경로의 ko.js 파일을 열고 다음과 같이 입력한다.

    "gui.extension.edubot.description": "조그맣지만 강력한 로봇과 놀아보세요.",
    "gui.extension.edubot.connectingMessage": "연결 중",

저장한 다음, 빌드한다. 실제로 빌드를 하여야 scratch-gui에서 사용할 수 있는 파일이 만들어진다.

$ cd scratch/scratch-l10n
$ npm run-script build

빌드 과정이 완료되면, dist와 locales 디렉토리가 생성되고 위에서 수정된 내용을 반영하여 파일을 만들어준다. 이제 Scratch를 실행하고, 잘 적용되었는지 확인해본다.

다국어의 선택은 왼쪽 상단의 지구본 모양을 눌러서 선택한다.

먼저 영어 버전은 다음과 같다.

다음으로 인터페이스를 한국어로 바꾸면,

한글도 잘 적용됨을 볼 수 있다.


확장블럭

블럭들도 위와 마찬가지로 각 요소별로 id를 가지고 있다. 이 id를 각 언어에 맞추어 작성해주면 된다. 반복 작업이 대부분이므로 한가지 예만 들어보도록 한다. Edubot의 블럭 중 버튼에 관련된 다음의 블럭에 대해 한국어로 표시되게끔 해보도록 한다.

위 블럭에 대한 서술은 scratch/scratch-vm/src/extensions/scratch3_edubot/index.js 파일에 있다. getInfo() 함수 내에

                {
                    opcode: 'whenButtonPressed',
                    text: formatMessage({
                        id: 'edubot.whenButtonPressed',
                        default: 'when button pressed',
                        description: 'when the button on the edubot is pressed'
                    }),
                    blockType: BlockType.HAT,
                    arguments: {
                    }
                },
                {
                    opcode: 'isButtonPressed',
                    text: formatMessage({
                        id: 'edubot.isButtonPressed',
                        default: 'button pressed?',
                        description: 'is the button on the edubot pressed?'
                    }),
                    blockType: BlockType.BOOLEAN,
                    arguments: {
                    }
                },

와 같이 되어 있는데, 좀 전과 마찬가지로 각 텍스트에 대해 id가 부여되어 있음을 볼수 있다. 따라서 이에 대한 부분을 수정해주면 된다. 블럭에 관련한 부분은 scratch/scratch-l10n/editor/extensions 디렉토리에 있다. 먼저 영어 대한 부분부터 작성한다. en.js 파일을 열고 임의의 위치에 다음과 같이 입력한다.

    "edubot.whenButtonPressed": "when button pressed",
    "edubot.isButtonPressed": "button pressed?",

다음으로 한국어에 대한 부분은 ko.js 파일을 열고 임의의 위치에 다음과 같이 입력한다.

    "edubot.whenButtonPressed": "버튼이 눌리면",
    "edubot.isButtonPressed": "버튼이 눌러졌는가?",

수정된 파일을 저장하고, 위와 마찬가지고 빌드 작업을 진행한다.

$ cd scratch/scratch-l10n
$ npm run-script build

이제 Scratch를 다시 실행해보면,

잘 적용이 됨을 볼수 있다. 끝!

Scratch 3.0 확장블럭 추가 (2)

업데이트


본 예제를 실행해서 로봇과 연결하려면 Edubot과 최신 펌웨어가 있어야 한다. Edubot과 펌웨어 관련한 내용은 https://github.com/oroca/OROCA-EduBot/tree/android_app을 참고한다. 펌웨어 개발환경 구축은 https://cafe.naver.com/openrt/19738을 참고한다.


이제 Scratch Link와 확장블럭에 대한 모든 것이 준비되었으니 실제 사용해보록 한다.

지난번 포스팅에서 언급했던 개발환경 (https://ahnbk.com/?p=366)은 모두 갖춰져 있다는 가정하에 진행한다.

scratch 3.0의 원래 소스를 가져와 현재 작업중인 OROCA-EduBot에 대한 확장블럭을 작성하였다. 수정된 소스는 다음의 링크에서 확인 가능하다. 지난번과는 달리 scratch-blocks에 대한 부분은 현재까진 수정할 필요가 없으므로, 이는 사용하지 않는다.

개발환경 구축 포스팅에서 설명했던 것과 같이, 임의의 디렉토리에 위 repository를 클론한다. (윈도우나 macOS나 모두 동일함).

$ git clone https://github.com/byeongkyu/scratch-gui.git
$ git clone https://github.com/byeongkyu/scratch-vm.git

scratch-vm부터 설치한다.

$ cd scratch-vm
$ npm install
$ npm link

다음으로 scratch-gui를 설치한다.

$ cd ../scratch-gui
$ npm install
$ npm link scratch-vm

이제 실행해보면

$ npm start

크롬이나 사파리, 인터넷 익스플로러 등 브라우져를 열고 http://localhost:8601 로 접속하면 다음의 화면을 볼 수 있다.

왼쪽 하단의 확장블럭 추가 버튼을 누른다.

Edubot의 확장카드가 보이고 이를 누르면,

스캔을 자동을 실행하고, 주변의 Edubot을 보여준다. Connect 버튼을 눌러 연결한다.

정상적으로 연결됨을 볼 수 있다. 이제 Go to Editor 버튼을 눌러 메인 화면으로 이동한다.

왼쪽에 Edubot에 대한 블럭들이 생겼음을 볼 수 있다. 이제 이 블럭들을 이용하여 코딩해보면 된다.

Scratch 3.0 스크래치 링크 설치 및 사용

Scratch 3.0에서 외부 기기 및 서비스를 이용하기 위해선 Scratch Link를 사용해야 한다. 물론 확장 프로그램에서 직접 하드웨어에 접속하게 해도 되지만, Scratch 개발자들은 다양한 하드웨어를 같은 프로토콜로 연결하기 위해 Scratch Link를 외부에 실행하고, 이를 통해 하드웨어와 연결한다.

Scratch와 Scratch Link는 websocket을 이용하여 통신한다. 패킷 내용은 까보면 json으로 구성되어 있다. Scratch Link는 시리얼통신 (블루투스 시리얼 포함), Bluetooth LE를 이용해 외부 하드웨어와 연결한다. Linux, macOS의 경우 위 기능을 모두 지원하나, 윈도우의 경우 10버전에서만 Bluetooth LE를 지원한다.

Scratch Link는 아직 소스가 공개되어 있지 않으므로, 설치하기 위해선 다음의 링크를 이용한다.

위 링크에서 파일을 다운로드 한 다음 설치한다.

Scratch Link를 사용하기 위해선 hosts 파일의 수정이 필요하다. 이유는 모르겠지만 Scratch Link의 서버 주소가 Local에서 실행되고 있음에도 불구하고 device-manager.scratch.mit.edu로 되어 있기 때문에 그냥 사용하게 되면 연결이 되지 않는다. 따라서 위 주소를 Local로 접속하도록 만들어야 되는데, 이를 위해 hosts 파일을 수정한다.

macOS

macOS에서 hosts 수정은 아주 간단하다. 터미널을 열고

$ sudo vi /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
127.0.0.1       device-manager.scratch.mit.edu
255.255.255.255 broadcasthost
::1             localhost

시스템 파일이기 때문에, 계정 암호가 필요하다. 위와 같이 수정하고 저장한다. 그 다음

$ ping device-manager.scratch.mit.edu
PING device-manager.scratch.mit.edu (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.045 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.107 ms
...

와 같이 나오면 성공.

Windows 10

윈도우의 hosts 파일은 C:\Windows\System32\drivers\etc에 위치한다. 하지만 직접 수정하는 것을 막아놨기 때문에, 탐색기로 위 위치로 이동한 후 hosts 파일을 임의의 위치로 복사한다.

Notepad나 기타 편집기를 이용하여, 다음과 같이 수정한다.

# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

127.0.0.1	device-manager.scratch.mit.edu

그런 다음 수정된 파일을 C:\Windows\System32\drivers\etc에 복사해 넣는다.

와 같이 나오고, 덮어 씌우겠다고 선택하면,

와 같이 나오는데, Continue를 눌러 진행한다. 그런 다음 코맨드 창을 열고 ping을 테스트해보면,

와 같이 나오면 성공.

설치된 Scratch Link를 실행하면 websocket 서버가 백그라운드에서 실행된다.

이제 사용할 준비 끝.

Scratch 3.0 확장블럭 추가 (1)

Scratch가 3.0으로 버전이 올라가면서 사용자가 확장 블럭 (Extension)을 추가하는 것이 좀더 간단해졌다. 확장 블럭은 Scratch의 기본 기능 외에 다양한 하드웨어나 클라우드 서비스의 기능을 사용할 수 있는 것인데, 메인 화면 왼쪽 하단의 버튼을 눌러 추가한다.

Scratch에 기본적으로 포함되어 있는 확장 블럭은 다음과 같다. 외부 기기나 하드웨어 클라우드 서비스 등이 포함된다.

이제 이것들 이외에 사용자만의 블럭을 추가 할 수 있다. 이 작업은 크게 두가지로 나뉠 수 있는데, 처음은 위 화면에서 본것과 같은 확장 카드를 추가하기, 다음으론 확장 블럭 생성하기이다.

먼저 사용할 이미지를 준비한다. 위 확장 카드에서 가장 크게 보이는 이미지로, 크기는 600×372 이고, png 타입이다.

준비된 이미지를 다음의 경로에 복사한다. (경로는 앞 포스트에서 설명한 경로를 기준으로 설명함).

~/Developer/scratch/scratch-gui/src/lib/libraries/extensions/edubot.png

다음으로 확장카드에 들어갈 작은 이미지와 추후 메인화면의 카테고리에 들어갈 중간 사이즈의 이미지를 준비한다. 이 이미지는 가급적이면 SVG 타입의 벡터 이미지를 사용한다. (벡터 이미지는 Illustrator, Sketch, Affinity Designer 등의 툴을 사용하면 쉽게 생성 가능)

112×92 SVG
39×39 SVG

준비된 이미지를 다음의 경로에 복사한다. (디렉토리를 생성해야함).

~/Developer/scratch/scratch-gui/src/lib/libraries/extensions/peripheral-connection/edubot/edubot-illustration.svg
~/Developer/scratch/scratch-gui/src/lib/libraries/extensions/peripheral-connection/edubot/edubot-small.svg

이제 index.jsx 파일을 수정한다. 파일의 경로는 다음과 같다.

~/Developer/scratch/scratch-gui/src/lib/libraries/extensions/index.jsx

저장된 이미지에 대한 변수 선언

import edubotImage from './edubot.png';
import edubotPeripheralImage from './peripheral-connection/edubot/edubot-illustration.svg';
import edubotMenuImage from './peripheral-connection/edubot/edubot-small.svg';

이제 중간 쯤 적당한 곳에 블럭 생성을 위한 코드 삽입.

    {
        name: 'OROCA_Edubot',
        extensionId: 'edubot',
        collaborator: 'OROCA',
        iconURL: edubotImage,
        insetIconURL: edubotMenuImage,
        description: (
            <FormattedMessage
                defaultMessage="Play with powerful small robot!"
                description="Description for the 'OROCA_Edubot' extension"
                id="gui.extension.oroca_edubot.description"
            />
        ),
        featured: true,
        disabled: false,
        bluetoothRequired: true,
        launchPeripheralConnectionFlow: true,
        useAutoScan: false,
        peripheralImage: edubotPeripheralImage,
        smallPeripheralImage: edubotMenuImage,
        connectingMessage: (
            <FormattedMessage
                defaultMessage="Connecting"
                description="Message to help people connect to their edubot."
                id="gui.extension.edubot.connectingMessage"
            />
        ),
        helpLink: 'https://github.com/oroca/OROCA-EduBot'
    },

각 설정값의 의미는 다음과 같다.

이외에도

  • extensionId: 확장블럭에 대한 고유 이름
  • launchPeripheralConnectionFlow: 선택시 기기를 연결하기 위한 다이얼로그를 실행할 지 여부
  • useAutoScan: 다이얼로그를 띄운 뒤, 자동 스캔 시작 여부

일단 저렇게 수정한 파일을 저장한다. 다음으로 확장블럭에 대한 파일을 작성한다. 해당 경로는 다음과 같다.

~/Developer/scratch/scratch-vm/src/extensions

위 디렉토리에 확장 블럭의 파일을 위한 디렉토리를 생성하고, index.js 파일을 생성한다. index.js 파일의 템플릿은 ~/Developer/scratch/scratch-gui/src/examples/extensions/example-extension.js 를 참고한다.

일단 여기까지!.

Scratch 3.0 개발 환경 구축

우선 Node.js를 설치하여야 한다. macOS의 경우 homebrew를 사용하면 쉽게 설치가 가능하다. 권장 버전은 Node 8이나 현재 LTS 버전은 Node 10이므로, 둘 중 아무거나 사용해도 무방하다. (테스트 해봤는데 별 이상은 없다.)

  • Update: BLE 통신을 위한 noble 모듈은 Node 10을 지원하지 않는다. 따라서 Node 8로 설치해야함.
  • Node10도 상관없음.

homebrew의 설치 방법은 https://brew.sh을 참조하면 된다. 명령 한줄로 쉽게 설치가 가능하다. 설치가 완료되면 Node 10을 설치한다.

$ brew install node@8
or
$ brew install node@10

윈도우10의 경우, 설치파일을 이용하여 설치한다. 또 Git도 설치하여야 한다 (macOS에는 기본 포함). Git (https://git-scm.com/download/win), Node.js (https://nodejs.org/en/)를 설치한다.

Ubuntu or Linux의 경우, 해당되는 패키지 매니저를 사용하여 설치하도록 한다.

아래의 설명에서 디렉토리의 경로는 macOS를 기준으로 설명하나, 다른 OS에서도 유사하므로 감안하여 사용하도록 한다.


Scratch는 크게 세개의 파트로 구성되어 있다. 사용자가 직접 Interaction 할 수 있는 GUI를 제공하는 scratch-gui, Scratch의 실행 (Back-end)을 담당하는 scratch-vm, Scratch의 블럭 디자인 및 블럭간의 연결, 관리 등을 담당하는 scratch-blocks이다.

실제론 위 세개의 Repository를 자신의 Repository로 Fork하여 사용하는 것을 권장하고 있다. 위와 같이 공식 Repository를 Clone하여 사용하는 경우, 개발자가 수정한 다음 commit 및 push가 불가능 하므로 (승인없이는), github의 계정을 생성하고 위 Repository를 Fork하여 사용하도록 한다.

  • scratch-blocks는 사용자가 수정할만한 요소가 없다. 따라서 이 설치 과정에서 scratch-blocks는 건너뛰어도 됨.

이제 https://github.com/llk/scratch-gui, https://github.com/llk/scratch-vm, https://github.com/llk/scratch-blocks를 Fork 하여 자신의 Repository로 가져온다.

이제 Scratch의 소스를 받아온다. 임의의 디렉토리를 생성하고 (여기선 ~/Developer/scratch) 이동한 후 다음과 같이 입력한다.

$ mkdir -p ~/Developer/scratch
$ cd ~/Developer/scratch

$ git clone https://github.com/byeongkyu/scratch-gui
$ git clone https://github.com/byeongkyu/scratch-vm
$ git clone https://github.com/byeongkyu/scratch-blocks (안해도됨)

이제 각각의 프로젝트에 필요한 모듈을 설치한다.

$ cd scratch-vm
$ npm install
$ npm link

--- 이과정은 무시 ---
$ cd ../scratch-blocks
$ npm install
$ npm link
--- 이과정은 무시 ---

$ cd ../scratch-gui
$ npm install
$ npm link scratch-vm

참고로 npm link 명령은 local (현재 PC)에 저장된 모듈을 사용하겠다는 의미이다. 따라서 scratch-gui에서 scratch-blocks와 scratch-vm은 온라인에서 받아오는게 아닌 우리가 받아서 저장한 것을 사용한다. 실제 위 명령을 실행하고 난 다음의 결과 메시지가 다음과 같이 보인다.

$ npm link scratch-vm scratch-blocks
/Users/byeongkyu/Developer/scratch/scratch-gui/node_modules/scratch-blocks -> /usr/local/lib/node_modules/scratch-blocks -> /Users/byeongkyu/Developer/scratch/scratch-blocks
/Users/byeongkyu/Developer/scratch/scratch-gui/node_modules/scratch-vm -> /usr/local/lib/node_modules/scratch-vm -> /Users/byeongkyu/Developer/scratch/scratch-vm

위까지 실행 완료하고 에러가 없다면, 다음과 같이 입력하여 실행해본다.

$ cd ~/Developer/scratch/scratch-gui
$ npm start

이제 사파리나 크롬 등을 실행하여 http://0.0.0.0:8601 으로 접속하면, 다음과 같은 실행 화면을 볼 수 있다.

Scratch 3.0 소개

Scratch (https://scratch.mit.edu)는 전세계적으로 가장 널리 알려진 블럭 코딩 툴이다. 다른 거의 대부분의 블럭 코딩 도구들이 참조를 하고 있고, 거의 유사한 형태로 개발되고 있기도 하다.

MIT 미디어랩의  Lifelong Kindergarten Group에서 프로젝트로 개발되고 있고, 이전 버전은 사용해보지 않아서 모르겠지만 3.0은 오픈소스 형태로 개발중이며, 사용하고 있는 거의 모든 소스를 공개해 놓고 있다.

블럭 관련한 부분은 구글 Blockly를 가져와 디자인, 일부 동작 관련한 부분을 수정하여 사용하고 있으며, 나머지는 그룹에서 자체 개발 중인듯 하다.

사용하고 싶은 기업이나 개발자들은 자유롭게 복사해서 수정, 재배포 등이 가능하다. Scratch의 스크린샷을 책이나 발표자료에 사용하는 것도 가능하며, 브로셔 등에도 삽입이 가능하다. 다만 각 자료에 다음과 같은 내용을 담아주길 권고하고 있다.

“Scratch is a coding language and online community where you can create your own interactive stories, games, and animations — and share your creations with others around the world. As young people create and share Scratch projects, they learn to think creatively, reason systematically, and work collaboratively. Scratch is a project of the Scratch Foundation in collaboration with the Lifelong Kindergarten group at the MIT Media Lab. It is available for free at https://scratch.mit.edu

Scratch를 사업화에 사용하려는 기업에서 소스를 가져와 수정하고 이를 상용화 하여도 문제가 없다. 자세한 라이센스 및 사용 관련한 내용은 https://scratch.mit.edu/info/faq 를 참조하면 된다.

실제 동작하는 데모 버전을 구경하고 싶다면 https://llk.github.io/scratch-gui/develop/ 에서 사용해볼 수 있다.

Fix the freezing when lid close for XPS9570 on Ubuntu 18.04

해결 방법을 찾아보면 9570 뿐만이 아니라, 외장 GPU를 사용하는 대부분의 델 랩탑에 해당되는 내용인듯. Ubuntu를 사용하다가 노트북을 닫거나, Sleep 모드로 전환 후 다시 노트북을 깨우려고 하면 멈춰버리는 현상이 발생함. 어쩔수 없이 강제 재부팅을 해야 되서 엄청 불편한데, 구글링 후 해결 방법을 찾아봄.

$ sudo vi /etc/default/grub

다음과 같이 수정함.

GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX="mem_sleep_default=deep"

저장하고, 다음의 명령어로 업데이트 완료 후 재부팅.

$ sudo update-grub

잠재우기 모드를 아예 강제로 deep 모드로 해버리는 것 같은데, 이렇게 되면 suspend 모드로 전환하거나 다시 복귀할때 시간이 좀 걸림. 아주 완전한 해결책은 아니지만, 그래도 멈추진 않으니 이대로 사용하는 수 밖에. .^^

[소설] 신의 망치

리디북스에서 가볍게 읽을만한 책을 고르다가 선택한 책. 영화 “딥 임팩트”의 원작(?)정도 되겠음. 딥 임펙트의 시대적 배경이 현재라면, 이 책의 배경은 미래의 얘기. 화성과 달에 사람들이 거주하고, 이미 한 세대가 지나 화성인, 지구인으로 구별되어 있을 정도로 먼 미래 얘기.

지구를 향해 다가오는 소행성을 처리하기 위해, 추진체를 소행성에 부착하여 궤도를 바꾸기 위해 노력한다든가, 이를 방해하기 위한 이상한 존재들과의 대립, 또 실패 후 우주선을 이용해 해결해보려는 노력 등.

영화와는 달리 목숨을 건 희생이 있진 않고, 나름 해피 엔딩으로 마무리 됨. 가볍게 술술 읽을만한 책.

Launchpad에 아이콘 수 조정 & 초기화

macOS를 처음 설치하고 나면 런치패드(Launchpad)의 아이콘이 상당히 크게 보여진다. 한 화면에 7×5로 나타내다보니 그런 것인데, 터미널에서 간단한 입력을 통해 이 숫자를 조정할 수 있다.

터미널을 열고 다음과 같이 입력한다.

$ defaults write com.apple.dock springboard-rows -int <세로로 보여질 숫자>
$ defaults write com.apple.dock springboard-cols -int <가로로 보여질 숫자>
$ killall Dock

와 같이 하면 다음과 같이 바로 적용된다.

추후 다시 기본 크기로 돌아가려면 위 옵션에서 크기를 다시 입력하면 된다. 기본 크기는 7×5이다.

더불어 Dock과 Launchpad를 초기화 할 수 있는 명령어도 존재하는데,

$ defaults delete com.apple.dock
$ killall Dock
$ defaults write com.apple.dock ResetLaunchPad -bool true
$ killall Dock

와 같이 실행하면, 처음 설치했을때와 같이 설정되고, 사용자 프로그램들은 2페이지에 자동으로 추가된다.

[노트북] MacBook Pro 15″ 2018 CTO

지난번 구입했던 델은 순수하게 리눅스 작업용으로 사용 중입니다. 물론 윈도우도 필요할 때마다 사용중이긴 한데, 대부분 Ubuntu에서 ROS 패키지 개발 전용이죠.


기존에 사용하던 맥북 (MacBook Pro 15″ 2012mid)이 요즘따라 계속 버벅이고 발열도 심한 통에 간단한 문서 작업용으로만 사용 중이었는데 (이전엔 요녀석으로 Ubuntu/ROS 작업을 했습니다), 6년 정도 사용한 지금 이젠 보내줘야 할 듯 하여 새로운 녀석으로 구입하였습니다.

이 녀석도 오랜 기간 사용해야 할 녀석이기에 사양은 일단 가능 좋은 녀석으로 골랐는데, 가격이 거의 2배네요. ㅠㅠ.

CPU가 명성이 자자한 i9이어서 그런지, 뭔가 백그라운드에서 작업을 계속 해대서 그런지 발열도 살짝 나는것 같습니다만 이런 문제는 언제든지 잡힐테고요. 어쨌든 새로운 기기 사용해보는 것은 언제나 재밌습니다. 요녀석 사용해서 돈 많이 벌로 재밌는 것들 많이 해봐야겠습니다.

Disable TouchPad while Typing on Ubuntu 16.04

Ubuntu 18.04에선 기본으로 제공하는 기능인데, 16.04에선 해당 옵션 선택 기능이 없음. 터미널 사용 중이거나 프로그래밍 중 터치패드가 작동되서 여기저기 튀는 현상때문에 골치가 아픈데… 다음과 같이 설정하면 기능 적용됨.

$ sudo vi /usr/share/X11/xorg.conf.d/51-synaptics-quirks.conf

파일 내에 다음과 같은 내용을 추가.

Section "InputClass"
Identifier "SynPS/2 Synaptics TouchPad"
      MatchProduct "SynPS/2 Synaptics TouchPad"
      MatchIsTouchpad "on"
      MatchOS "Linux"
      MatchDevicePath "/dev/input/event*"
      Option "Ignore" "on"
EndSection

재부팅하면 해결.

tmux

tmux 설치: https://github.com/tmux/tmux

필요한 패키지 설치

$ sudo apt install libevent-dev libcurses-ocaml-dev

tmux plugin manager 설치

$ git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

tmux option 설정

$ vi ~/.tmux.conf
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-yank'

set -g mouse on
set -g destroy-unattached on
setw -g monitor-activity on
set -g visual-activity on
set -g default-terminal "screen-256color"
set -g history-limit 30000

set -g base-index 1
set -g pane-base-index 1

# Pane splitting.
bind \ split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind r source-file ~/.tmux.conf \; display "Reloaded ~/.tmux.conf"

run '~/.tmux/plugins/tpm/tpm'

[노트북] DELL XPS15-9570 D662X9570508KR

현재 사용하고 있는 맥북프로 레티나 2012mid 모델이 오래된 티를 내는지 Ubuntu에서 조금만 빡센 작업을 하면 쓰로틀링이 걸려 엄청 느려지기 시작했습니다.

Ubuntu/ROS를 사용하면서 성능도 괜찮은 노트북을 검색하다가 맨처음 맘에 들었던 제품은 Razer Blade 15 2018 이었는데, 아쉽게도 아직 한국에 정식 출시도 안되었고 직구하기엔 시간이 좀 걸리는 관계로… 다음 순위였던 델 노트북으로 선택.

들고 다닐수 있는 고성능 노트북 중 그래도 납득할 만한 가격과 어느 정도 받쳐주는 성능으로 DELL XPS15-9570 D662X9570508KR을 선택하였습니다. 4k 디스플레이, GTX1050Ti, 인텔 i9 8세대, 램 16GB. 이정도면 큰 무리없이 몇년간은 사용할만한 사양인듯 합니다.

DELL XPS15-9570 D662X9570508KR

며칠간 사용해본 소감으론

  • 팬 소리가 심하다
  • 성능은 뭐 나름 만족
  • 디스플레이도 만족
  • 다시 사용하게 된 윈도우10은 역시나 별로
  • 스피커, 트랙패드 등은 기대도 안함.

끝!.

MD Gundam RX-78-02 The Origin

1/100 사이즈 건담은 처음이었는데, 부품 수와 크기도 적당하여 조립하기 꽤 괜찮았었던 것 같음. 화려한 모델보단 저런 수수한 모델(?)이 괜찮아 보이는 듯. 저 모델도 여러가지 버전이 있는 것 같은데, 나중에 또 다른 것 사다가 조립해봐야 할 듯. 

Solve “permission denied” when using libusb on Ubuntu

libusb를 이용한 디바이스를 Ubuntu에 연결하고, 관련 프로그램을 실행시 “Permission denied” 혹은 알수없는 오류를 발생하는 경우가 있다. 보통 sudo 명령을 이용하여 실행하면 잘 해결되는 경우인데, 매번 sudo를 붙여서 실행하는 것이 번거롭다. 이때는 udev 룰을 추가하면 해결된다. (제조사에서 제공하는 경우도 있다.)

사용자가 udev 룰을 추가하려면 해당 디바이스의 Vender ID, Product ID를 알아내야 한다. 이는 디바이스를 연결하고, 터미널에서 다음과 같이 입력한 다음 확인이 가능하다.

$ dmesg

이때 나오는 메시지 중 idVendor, idProduct에 나오는 값을 기억한다.

/etc/udev/rules.d 에 다음과 같이 파일을 작성한다.

$ cd /etc/udev/rules.d
$ vi 99-<user_device>.rules

SUBSYSTEM=="usb", ATTRS{idVendor}=="<Vendor ID>", ATTRS{idProduct}=="<Product ID>", MODE="0666"

저장한 다음, 디바이스를 뽑았다가 다시 꼽으면 해결된다.

느타리버섯 무침

(1) 느타리버섯은 뿌리부분을 자르고, 잘게 찢는다.

(2) 끓는 물이 (1)을 넣고 잠시 동안 데친다.

(3) (2)를 꺼내어 찬물에 행구고, 물을 최대한 짠다.

(4) 다진마늘, 간장, 소금, 들깨 으깬것, 들기름을 넣고 무친다.

끝!

Swift 개발서적

사실 프로그래밍 개발 관련 책은 사놓아도 몇번 보곤 책장에서 공간을 채워주는 장식품으로 생각한다. 이번 책도 아마 마찬가지 일꺼라고 생각되는데, 책이 뭔가 안좋다는 것보단 개발 서적은 으례 그래야 한다고 생각하기 때문이다.

기본적인 개발 환경과 아주 기본적인 문법만 익히고, 나머진 개발하려는 앱이나 프로그램에 따라 구글링 or 책 내용 (운 좋으면)을 참고 하면 끝.

이번에도 iOS 앱을 개발할 일이 생겨서, 개발 흐름이라든가 아주 기초적인 부분만 참조하려고 책을 찾아봤는데 다음의 두 책이 괜찮은 평가를 받고 있어서 서점에서 사왔음.

자~ 이제 그램 시작해보실까나~…

Install specific version when using apt

When you need specific version of package, you can install the version you want using apt.

To show the list versions of package,

 $ sudo apt-cache policy <package-name>

To install specific version,

$ sudo apt install <package-name>=<version-you-want>;

Example:

$ sudo apt-cache policy librealsense2
librealsense2:
  Installed: (none)
  Candidate: 2.16.4-0~realsense0.127
  Version table:
     2.16.4-0~realsense0.127 500
        500 http://realsense-hw-public.s3.amazonaws.com/Debian/apt-repo xenial/main amd64 Packages
     2.16.3-0~realsense0.115 500
        500 http://realsense-hw-public.s3.amazonaws.com/Debian/apt-repo xenial/main amd64 Packages
     2.16.3-0~realsense0.103 500
        500 http://realsense-hw-public.s3.amazonaws.com/Debian/apt-repo xenial/main amd64 Packages
     2.16.3-0~realsense0.97 500
        500 http://realsense-hw-public.s3.amazonaws.com/Debian/apt-repo xenial/main amd64 Packages
...

$ sudo apt install librealsense2=2.11.1-0~realsense0.70

Ignore installed package when using pip

If you have an error when you install python package using pip like this,

Cannot uninstall '~~~'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.

You can solve this problem by adding this option:

--ignore-installed

For example,

$ sudo pip install <package-name-to-install> --ignore-installed <package-name-get-error>

산책@우이동계곡

장어를 먹으러 우이동 계곡에 있는 장어집을 방문하였습니다. 예전에도 한번 갔던 가게인데, 맛이 꽤 괜찮았던 곳이었거든요.

iPhone X 2018-11-11 11:29:49 f/1.8 1/30sec ISO-25 4mm

이번엔 식사를 마치고 근처 산 길을 좀 걸어보았습니다. 단풍도 짙게 드리우고, 공기도 괜찮고 분위기도 좋네요.

iPhone X 2018-11-11 13:13:08 f/1.8 1/120sec ISO-25 4mm

어디를 찍어도 예술 작품이네요. ^^ 가을 냄새 물씐 풍깁니다. 

길 가다가 만난 개…들도 참 부럽게… 있네요. 니네들 팔자가 상팔자로구나…

심층학습 (Deep Learning)

딥러닝 기술 중 GAN의 창시자인 이안 굿펠로우가 작성한 책으로 http://www.deeplearningbook.org 에서 영문책은 쉽게 볼 수 있지만, 내용을 이해하기에 한글로 된 책도 하나 있으면 괜찮을듯 하여 구입함. 

이런 기술 번역서는 어색하지 않은 번역과 용어 등의 사용이 중요한데, 서점에서 잠깐 살펴본 바로는 큰 어색함이 느껴지지 않았고, 주요 용어들은 한글과 영문을 동시 표기하여 추후 영문 자료를 참고하는데 헷갈리지 않을 것 같음.

딥러닝에 필요한 기초 수학부터 응용까지 꽤 많은 내용이 포함된 교과서로 완독하지도 않더라도 참고서로 한권씩은 갖고 있어야 될 책.

아침안개@청양

새벽녘 아스라이 깔려있는 안개와 텅빈 도로를 보고 있으면 마음이 차분해지는 느낌이다. 상쾌한 시골의 아침 공기도 느껴보고, 살포시 산 위에 걸쳐있는 태양도 하루를 시작하는데 좋은 기운을 주는 듯.

iPhone X 2018-11-04 08:03:54 f/1.8 1/510sec ISO-20 4mm

산 중턱에서 내려다본 모습은 더욱더 멋진 듯. 자욱히 깔려있는 안개와 저 멀리 보이는 산이마치 수묵화와 같은 느낌을 준다.

iPhone X 2018-11-04 08:23:08 f/2.4 1/1779sec ISO-16 6mm

단!! 이게 그냥 구경만 하는 것이라면 좋겠으나~ 저 날은 고추따러 밭에 가던 날 ㅠㅠ

imu_complementary_filter를 이용한 IMU 자세 추정

IMU를 이용한 자세추정 방법은 보통 보상 필터를 많이 사용한다. 3축 가속도 센서와 3축 자이로스코프를 사용하고, 3축 지자기 센서를 이용하여 보정한다. 가속도 센서는 3축의 가속도 값 (m/s^2)을 두번 적분하여 위치를 구할수 있으나 회전 및 진동 등에 의해서 값이 변하는 단점이 있고, 자이로스코프는 3축의 각속도 (rad/s)를 한번 적분하여 회전각을 알아낼수 있지만 각 축에 포함된 화이트 노이즈 덕분에 시간이 흐를수록 값이 변한다 (일명 드리프트 현상).

따라서 각각의 센서가 가지는 장점을 뽑아서 사용하자는게 보상필터이고, 간단하게는 Low-pass filter, High-pass filter를 사용하거나, 두개의 Band-pass filter를 사용하는게 일반적이다. 이게 바로 보상 (complementary) 필터이다.

직접 구현해서 사용하는 것도 방법이긴하나, 이미 많이 알려진 알고리즘이고 ROS에 패키지로도 존재하므로 쉽게 사용이 가능하다.

사용할 패키지는 imu_complementary_filter이다. 사용 방법은 연결된 링크의 wiki 페이지에 자알~ 되어있다. 논문을 기반으로 개발된 것 같고, 간단한(?) 블록 다이러그램은 다음과 같다.

Ref: https://www.mdpi.com/1424-8220/15/8/19302

설치는 다음과 같이 하고,

$ sudo apt install ros-kinetic-imu-complementary-filter

사용은 다음과 같이,

$ rosrun imu_complementary_filter complementary_filter_node

complementary_filter_node는 /imu/data_raw (sensor_msgs/Imu)를 Subscribe 한다. 사용하려는 IMU가 위 토픽을 Publish 한다면 고맙게 사용할 수 있고, 토픽 이름이 다르다면 다음과 같이 실행하면 끝!,

$ rosrun imu_complementary_filter complementary_filter_node /imu/data:=/<your_topic_name>

결과로는 imu/data (sensor_msgs/Imu)를 Publish 한다. 결과를 살펴보면 입력 데이터에 Orientation 값이 계산되어 나옴을 확인할 수 있다.

동해 일출@양양

일출을 그렇게 많이 본적이 있는건 아니지만, 이번 일출은 구름이 거의 없고 바다의 수평선이 깨끗하게 보인다는 점에서 참 인상적이었다.

요즘은 겨울이 가까워져 일출시간도 아침 6시 45분 정도라 부담도 덜했던 것 같고. 해 뜨는 시간이 가까워지면서 수평선 중앙쯤이 붉그스레 변해갔고 다른 사람들도 한 두명씩 보이기 시작했다.

일출 장면은 타임랩스를 찍느라 사진은 없고, 숙소로 돌아가는 길에 좀더 위로 올라온 장면을 찍었다.

일출을 보았으니 소원을 빌어야겠지. 내 소원은 “로또 되게 해주세요~~~!!” ^^

WordPress -> Ghost -> WordPress

자료나 글을 충실하게 올리는 블로그는 아니었다.  툭탁툭탁 뭔가 만들고 삽질하는 것이 재밌어 시작한 것이었고, 그 외의 목적은 별 관심이 없었다. 가상서버호스팅을 사용해서 리눅스에서 웹서버를 구축하고, 툴을 설치하고, 이리저리 테마를 고치는게 주 목적인 블로그이다. 이런 과정을 거치면서 배우는 점도 있고, 리눅스에 좀더 친근하게 다가갈 수 있기도 했던 것 같다.

그간 WordPress를 잘 사용하다가 약간 지루하기도 하여, 요즘(?) 유행한다는 Ghost를 사용해 보았는데 몇가지 블로그로 사용하기엔 문제가 많을 것 같았다.

  • 글을 묶을수 있는 방법이 존재하지 않았다. WordPress의 카테고리와 같은 기능인데, Tag를 사용할 수 있지만, 글들을 묶고 분류하기엔 부족했다.
  • 이미지에 대한 처리 기능이 부족하다. 리사이즈도 사용자 몪. 요 근래 버전이 올라가면서 기능을 지원하게 되었으나, 여전히 살짝 모자른듯.
  • 모양을 고치긴 위해 다른 툴들과 마찬가지로 CSS를 사용한다. 하지만 테마를 수정하려면 다른 것들과는 다르게 수정 이후 웹서버에 접속해 ghost를 다시 시작해야 한다. 불편.
  • 댓글 시스템이 없다. 다른 프로그램을 설치하고 연동은 가능하나 테마 업데이트시 수정된게 날라간다. ㅠㅠ

결국 다시 WordPress로 돌아왔다. 마침 5.0 버전 베타가 시작되었고, 기본 테마는 Twentynineteen이 되었다. (오호~~ 또 새로운 삽질꺼리다!!!)

슬슬 포트폴리오 자료나 다른 것들 정리해서 올려야 할 듯.