728x90

출처

소스

/*Example sketch to control a 28BYJ-48 stepper motor with ULN2003 driver board, and Arduino UNO. More info: https://www.makerguides.com */
// Include the Arduino Stepper Library:
#include <Stepper.h>
// Number of steps per rotation:
const int stepsPerRevolution = 2048;
//Wiring:
// Pin 8 to IN1 on the ULN2003 driver
// Pin 9 to IN2 on the ULN2003 driver
// Pin 10 to IN3 on the ULN2003 driver
// Pin 11 to IN4 on the ULN2003 driver
// Create stepper object called 'myStepper', note the pin order:
Stepper myStepper = Stepper(stepsPerRevolution, 8, 10, 9, 11);
void setup()
{
  // Set the speed to 5 rpm:
  myStepper.setSpeed(5);
  // Initialize the serial port:
  Serial.begin(9600);
}
void loop() 
{
  // Step one revolution in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  delay(500);
  // Step one revolution in the other direction:
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  delay(500);
}

실행 영상

728x90
728x90

출처

micro:bit : 스탭모터(28BYJ48 ​+ ULN2003) 제어

스탭모터(28BYJ48)와 스텝 모터 드라이버(ULN2003)는 저렴하고 많이 사용하고 있어서 많은 예제가 있습니다. 스탭의 반복하면서 반복 하는 시간차와 회수를 계산해서 원하는 각도로 회전하거나, 스탭의 방향에 따라서 정방향, 역방향으로 회전 시킬 수 있습니다.

  • IN1 = micro:bit 디지탈 0번핀
  • IN2 = micro:bit 디지탈 1번핀
  • IN3 = micro:bit 디지탈 2번핀
  • IN4 = micro:bit 디지탈 3번핀​​

소스

/*
############################################
##           sMotor v0.1 Test Program     ##
##          created by Samuel Matildes    ##
############################################
        ---- sam.naeec@gmail.com -----
This library was made for 4-Phase Stepper Motors
I don't take any resposability for the damage caused to your equipment.
 
*/
 
#include "MicroBit.h"
#include "sMotor.h"
 
//MicroBit uBit;
MicroBitSerial gSerial(USBTX, USBRX);
sMotor motor(P0_0, P0_1, P0_2, P0_3); // creates new stepper motor: IN1, IN2, IN3, IN4
//BusOut motor_out(P0_0, P0_1, P0_2, P0_3);  // blue - pink - yellow - orange
 
int step_speed = 1200; // 1200 ; // set default motor speed
int numstep = 512 ; // defines full turn of 360 degree
//you might want to calibrate this value according to your motor
 
int step = 0; 
int dir = 1; // direction
 
int main() {
	
	 //uBit.init();
	 //uBit.display.disable();
 
    //Credits
    printf("4 Phase Stepper Motor v0.1 - Test Program\r\n");
    printf("developed by Samuel Matildes\r\n");
    printf("\n\r");
 
    // Screen Menu
    printf("Default Speed: %d\n\r",step_speed);
    printf("1- 360 degree clockwise step\n\r");
    printf("2- 360 degree anticlockwise step\n\r");
    printf("3- 180 degree clockwise step\n\r");
    printf("4- 180 degree anticlockwise step\n\r");
    printf("5- Change Speed\n\r");
    
    while (1) {
 
        if (gSerial.readable()) { // checks for serial
 
            if (gSerial.getc()=='1') 
                motor.step(numstep,0,step_speed); // number of steps, direction, speed
 
            if (gSerial.getc()=='2')
                motor.step(numstep,1,step_speed);
 
            if (gSerial.getc()=='3')
                motor.step(numstep/2,0,step_speed);
 
            if (gSerial.getc()=='4')
                motor.step(numstep/2,1,step_speed);
 
            if (gSerial.getc()=='5') {
                printf("Current Speed: %d\n\r", step_speed);
                printf("New speed: \n\r");
                //gSerial.scanf("%d",&step_speed); // sets new speed
            }
        }
    }
    
    /*
		while(1)
    { 
        switch(step)
        { 
            case 0: motor_out = 0x1; break;  // 0001
            case 1: motor_out = 0x3; break;  // 0011
            case 2: motor_out = 0x2; break;  // 0010   
            case 3: motor_out = 0x6; break;  // 0110
            case 4: motor_out = 0x4; break;  // 0100
            case 5: motor_out = 0xC; break;  // 1100
            case 6: motor_out = 0x8; break;  // 1000
            case 7: motor_out = 0x9; break;  // 1001
            
            default: motor_out = 0x0; break; // 0000
        }
  
        if(dir) step++; else step--; 
        if(step>7)step=0; 
        if(step<0)step=7; 
        //wait(0.015);  // speed
        wait_us(step_speed);
    }
    */
}

실행 영상

728x90
728x90

출처

ROC-RK3328-CC : LAKKA 설치하기

ROC-RK3328-CC 비롯해서 Rockchip 칩을 사용하는 대부분의 SBC 보드들이 안드로이드 OS용 그래픽 가속 드라이버는 제공 되지만, 리눅스용 그래픽 드라이버가 제공 되지 않아 RetroPie와 같은 게임 에뮬레이터를 실행 할 수가 없는데, 최근에 LAKKA용 OS 이미지가 제공 되어 게임 에뮬레이터를 실행 보았습니다. 아쉽게도 PSP 에뮬레이터는 조금 느리게 동작했습니다.

ROC-RK3328-CC용 LAKKA 이미지 다운로드

(http://le.builds.lakka.tv/Rockchip.ROC-RK3328-CC.arm/)

다운받은 이미지 Etcher로 SD 메모리에 복사

[Select image] 버튼 선택

다운로드 이미지 선택

[Select target] 버튼 선택

SD 메모리 선택

[Flash!] 버튼 선택

이중선형 필터링 (HW Bilinear Filtering)

SAMBA 활성화

SAMBA 네트워크 드라이브 접근

MSX(blueMSX) 에뮬레이터 복사

MSX를 실행하기 위해서는 BIOS(http://www.bluemsx.com/)를 다운로드 받아서 설치하면 blueMSX가 설치된 위치의 서브 폴더 Machines 을 System 폴더에 복사합니다.

MSX ROM 파일 복사

Lakka 에서 MSX ROM 파일 불러오기

MSX 실행화면

PSP 에뮬레이터 복사

MSX, PSP 에뮬레이터 실행 영상

728x90
728x90

출처

micro:bit : BLE 통신 - App Inventor 2 과 BLE 통신

micro:bit를 이용해서 BLE 서버를 만들고 App Inventor를 이용해서 안드로이드 용 BLE 클라이언트를 만들어 보았습니다.

BLE 서버는 BLE 이름과 UUID(고유주소)를 송출하고, 이 정보로 BLE 클라이언트가 접속하면, BLE 기기는 다른 BLE 클라이언트가 접속하지 않도록, BLE 이름을 더 이상 송출하지않고, 서비스목록과 해당 서비스의 특성 정보를 송출합니다. BLE 클라이언트는 필요한 서비스와 특성을 찾아서 용도에 따라 다르겠지만 여기 예제에서는 간단하게 문자열을 주고 받도록 했습니다.

micro:bit BLE 서버 만들기 pulse-combined.hex

서비스 UUID, 특성 UUID는 고정 되어 수정 할 수 없고, 정해지 UUID를 사용해야 됩니다.

micro:bit BLEUART Service 구성 UUID

  • Service UUID : 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
  • TX Characteristic : 6E400002-B5A3-F393-E0A9-E50E24DCCA9E
  • RX Characteristic : 6E400003-B5A3-F393-E0A9-E50E24DCCA9E

micro:bit 소스 - main.cpp

#include "MicroBit.h"
#include "MicroBitUARTService.h"

MicroBit uBit;
MicroBitUARTService *uart;

int connected = 0;

void onConnected(MicroBitEvent e) {
    uBit.display.scroll("C");

    connected = 1;

    // my client will send ASCII strings terminated with the colon character
    ManagedString eom(":");

    while (connected == 1) {
        ManagedString msg = uart->readUntil(eom);
        uBit.display.scroll(msg);
    }
}

void onDisconnected(MicroBitEvent e) {
    uBit.display.scroll("D");
    connected = 0;
}

void onButtonA(MicroBitEvent e) {
    if (connected == 0) {
        uBit.display.scroll("NC");
        return;
    }
    uart->send("YES");
    uBit.display.scroll("YES");
}

void onButtonB(MicroBitEvent e) {
    if (connected == 0) {
        uBit.display.scroll("NC");
        return;
    }
    uart->send("NO");
    uBit.display.scroll("NO");
}

void onButtonAB(MicroBitEvent e) {
    if (connected == 0) {
        uBit.display.scroll("NC");
        return;
    }
    uart->send("GOT IT!!");
    uBit.display.scroll("GOT IT!!");
}

int main() {
    // Initialise the micro:bit runtime.
    uBit.init();

    // listen for Bluetooth connection state changes
    uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_CONNECTED, onConnected);
    uBit.messageBus.listen(MICROBIT_ID_BLE, MICROBIT_BLE_EVT_DISCONNECTED, onDisconnected);

    // listen for user button interactions
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_AB, MICROBIT_BUTTON_EVT_CLICK, onButtonAB);

    // Note GATT table size increased from default in MicroBitConfig.h
    // #define MICROBIT_SD_GATT_TABLE_SIZE             0x500
    uart = new MicroBitUARTService(*uBit.ble, 32, 32); 
    uBit.display.scroll("AVM");

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

config.json

{
    "microbit-dal": {
        "bluetooth": {
            "enabled": 1,
            "pairing_mode": 1,
            "private_addressing": 0,
            "open": 1,
            "security_level": "SECURITY_MODE_ENCRYPTION_NO_MITM",
            "whitelist": 1,
            "advertising_timeout": 0,
            "tx_power": 7,
            "dfu_service": 0,
            "event_service": 1,
            "device_info_service": 1
        },
        "gatt_table_size": "0x600"
    }
}

module.json

{
  "name": "pulse",
  "version": "0.0.0",
  "keywords": [],
  "author": "",
  "license": "Apache-2.0",
  "repository": {
    "url": "https://github.com/ARMmbed/mbed-os.git",
    "type": "git"
  },
  "dependencies": {
  	"mbed-classic": "lancaster-university/mbed-classic#microbit_hfclk+mb6",
    "microbit": "lancaster-university/microbit"
  },
  "extraIncludes": [
  	"source/Device",
  	"source/ChaN",
  	"source/ea3a618e0818",
  	"source/ESP8266",
  	"source/ESP8266/ATParser",
  	"source/ESP8266/ATParser/BufferedSerial",
  	"source/ESP8266/ATParser/BufferedSerial/Buffer"
  ],
  "bin": "./source"
}

App Inventor 2 : BLE 클라이언트 만들기 (http://ai2.appinventor.mit.edu/microbit_ble.apk

App Inventor는 MIT에서 만든 블럭 형태의 코딩으로 안드로이드 어플을 쉽게 만들 수 있어서 IOT 개발시 많이 사용됩니다. 기본적으로 BT 통신만 지원했고, BLE 통신은 지원하지 않았지만, 최근에 확장 라이브러리를 통해서 지원하고 있습니다. BLE 확장 라이브러리를 다운 받아서 Import 하시면 BLE 통신을 구현 할 수 있습니다.

예제는 BLE 목록을 조회하고, 조회된 목록에서 micro:bit를 선택하여 BLE 서버에 접속하고, 미리 정해둔 서비스와 특성을 등록하고, micro:bit에서 A나 B버튼을 선택시 전달 받은 문자열을 텍스트박스에 출력하고, 안드로이드 어플에서도 문자열을 micro:bit에 전송 합니다.

App Inventor BLE 확장 라이브러리 다운로드

http://appinventor.mit.edu/extensions 에 접속하셔서 BluetoothLE.aix 파일을 다운 받습니다.

App Inventor BLE 확장 라이브러리 Import

팔레트 -> Extension -> import extension 에서 파일 선택버튼을 누른 후 위에서 다운받은 bluetoothLE.aix 를 선택해줍니다.

App Inventor 화면 구성

전역 변수 선언 (서비스, 특성 UUID 정의)

BLE 문자열 전달 함수 생성

[버튼1]을 선택해서 BLE 목록 조회

BLE 목록이 조회되면 목록를 리스트 박스(목록_선택1)에 담기

BLE 목록에서 접속하려고 하는 BLE 기기 선택했을 경우 BLE 주소 UUID(리스트의 문자열 1에서 17의 문자열)를 가지고 와서 해당 BLE에 접속 시도

BLE 기기에 접속하면 BLE로 문자열 수신 이벤트를 받기 위해서 서비스와 특성 등록

BLE 기기에서 문자열을 수신 했을 경우 텍스트 박스(텍스트_상자1)에 수신한 문자열 출력

[버튼3]을 선택해서 텍스트 박스(텍스트_상자2)의 문자열을 BLE기기에 전송

[버튼2]을 선택해서 BLE 연결끊기

App Inventor 전체 소스

실행 영상

728x90
728x90

출처

라즈비안(Raspberry pi OS)의 업데이트와 업그레이드

$ sudo apt-get update && sudo apt-get upgrade

현재 설치된 버전 확인

$ pkg-config opencv --modversion
3.3.1
$ python -c "import cv2; print (cv2.__version__)"
3.3.1
$ python3 -c "import cv2; print (cv2.__version__)"
3.3.1

OpenCV 4.1 설치

Jetson Nano에 OpenCV 4.0 버전을 설치하는 스크립트를 다운받아서 OpenCV 4.1으로 변경해서 설치 스크립트를 만들고 실행만 하면 간단하게 OpenCV 4.1이 설치가 됩니다.

$ wget https://raw.githubusercontent.com/AastaNV/JEP/master/script/install_opencv4.0.0_Nano.sh
$ cp install_opencv4.0.0_Nano.sh install_opencv4.1.0_Nano.sh
$ sed -i 's/4.0.0/4.1.0/g' install_opencv4.1.0_Nano.sh
$ mkdir opencv410
$ chmod 755 install_opencv4.1.0_Nano.sh
$ sudo ./install_opencv4.1.0_Nano.sh opencv410

cmake 옵션 (OPENCV_GENERATE_PKGCONFIG 옵션 추가)

cmake -D WITH_CUDA=ON -D CUDA_ARCH_BIN="5.3" -D CUDA_ARCH_PTX="" -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.1.0/modules -D WITH_GSTREAMER=ON -D WITH_LIBV4L=ON -D BUILD_opencv_python2=ON -D BUILD_opencv_python3=ON -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D BUILD_EXAMPLES=OFF -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D OPENCV_GENERATE_PKGCONFIG=ON ..

cmake 실행 결과 : 설치 스크립트 실행 중간 과정

-- General configuration for OpenCV 4.1.0 =====================================
--   Version control:               unknown
-- 
--   Extra modules:
--     Location (extra):            /home/bluesanta/opencv410/opencv_contrib-4.1.0/modules
--     Version control (extra):     unknown
-- 
--   Platform:
--     Timestamp:                   2019-08-04T15:08:51Z
--     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 -lpthread 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 freetype fuzzy gapi hdf hfs highgui img_hash imgcodecs imgproc line_descriptor ml objdetect optflow phase_unwrapping photo plot python2 python3 quality reg rgbd saliency sfm shape stereo stitching structured_light superres surface_matching text tracking video videoio videostab xfeatures2d ximgproc xobjdetect xphoto
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 cnn_3dobj cvv java js matlab ovis ts viz
--     Applications:                apps
--     Documentation:               NO
--     Non-free algorithms:         NO
-- 
--   GUI: 
--     GTK+:                        YES (ver 3.22.30)
--       GThread :                  YES (ver 2.56.4)
--       GtkGlExt:                  NO
--     VTK support:                 NO
-- 
--   Media I/O: 
--     ZLib:                        /usr/lib/aarch64-linux-gnu/libz.so (ver 1.2.11)
--     JPEG:                        /usr/lib/aarch64-linux-gnu/libjpeg.so (ver 80)
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         /usr/lib/aarch64-linux-gnu/libpng.so (ver 1.6.34)
--     TIFF:                        /usr/lib/aarch64-linux-gnu/libtiff.so (ver 42 / 4.0.9)
--     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:                      YES
--       avcodec:                   YES (57.107.100)
--       avformat:                  YES (57.83.100)
--       avutil:                    YES (55.78.100)
--       swscale:                   YES (4.8.100)
--       avresample:                NO
--     GStreamer:                   YES (1.14.4)
--     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)
--     NVIDIA GPU arch:             53
--     NVIDIA PTX archs:
-- 
--   OpenCL:                        YES (no extra features)
--     Include path:                /home/bluesanta/opencv410/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.15+)
--     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.8)
--     Libraries:                   /usr/lib/aarch64-linux-gnu/libpython3.6m.so (ver 3.6.8)
--     numpy:                       /usr/local/lib/python3.6/dist-packages/numpy/core/include (ver 1.17.0)
--     install path:                lib/python3.6/dist-packages/cv2/python-3.6
-- 
--   Python (for build):            /usr/bin/python2.7
-- 
--   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/bluesanta/opencv410/opencv-4.1.0/release

OpenCV 4.1 용 Python 3 가상 환경 구성

pip 설치

$ wget https://bootstrap.pypa.io/get-pip.py
$ sudo python3 get-pip.py
WARNING: The directory '/home/bluesanta/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
WARNING: The directory '/home/bluesanta/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting pip
  Downloading https://files.pythonhosted.org/packages/62/ca/94d32a6516ed197a491d17d46595ce58a83cbb2fca280414e57cd86b84dc/pip-19.2.1-py2.py3-none-any.whl (1.4MB)
     |████████████████████████████████| 1.4MB 150kB/s 
Collecting setuptools
  Downloading https://files.pythonhosted.org/packages/ec/51/f45cea425fd5cb0b0380f5b0f048ebc1da5b417e48d304838c02d6288a1e/setuptools-41.0.1-py2.py3-none-any.whl (575kB)
     |████████████████████████████████| 583kB 379kB/s 
Collecting wheel
  Downloading https://files.pythonhosted.org/packages/bb/10/44230dd6bf3563b8f227dbf344c908d412ad2ff48066476672f3a72e174e/wheel-0.33.4-py2.py3-none-any.whl
ERROR: launchpadlib 1.10.6 requires testresources, which is not installed.
Installing collected packages: pip, setuptools, wheel
Successfully installed pip-19.2.1 setuptools-41.0.1 wheel-0.33.4
$ rm get-pip.py

virtualenv, virtualenvwrapper 설치

$ sudo pip install virtualenv virtualenvwrapper

python3, virtualenv 환경설정

$ echo -e "\n# virtualenv and virtualenvwrapper" >> ~/.profile
$ echo "export WORKON_HOME=$HOME/.virtualenvs" >> ~/.profile
$ echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.profile
$ echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.profile
$ source ~/.profile

가상환경을 만들기

$ mkvirtualenv cv -p python3
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /home/pi/.virtualenvs/cv/bin/python3
Also creating executable in /home/pi/.virtualenvs/cv/bin/python
Installing setuptools, pip, wheel...
done.
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/predeactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/postdeactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/preactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/postactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/get_env_details

workon 명령을 사용하여 cv 환경에 있는지 확인

pi@raspberrypi:~$ workon cv
(cv) pi@raspberrypi:~$ 

numpy 파이썬 패키지 설치(OpenCV관련 수학 함수 모음)

pi@raspberrypi:~$ workon cv
(cv) pi@raspberrypi:~$ pip install numpy
(cv) pi@raspberrypi:~$ python
Python 3.6.8 (default, Jan 14 2019, 11:02:34) 
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> quit()

OpenCV 4를 Python 3 가상 환경에 복사

$ cd ~/.virtualenvs/cv/lib/python3.6/site-packages/
$ ln -s  /home/bluesanta/opencv410/opencv-4.1.0/release/lib/python3/cv2.cpython-36m-aarch64-linux-gnu.so cv2.so
$ cd ~

OpenCV 설치 확인

파이썬

$ workon cv
(cv) bluesanta@bluesanta-desktop:~$ python
Python 3.6.8 (default, Jan 14 2019, 11:02:34) 
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'4.1.0'
>>> exit()

C++

#include "opencv2/opencv.hpp"
 
using namespace cv;
using namespace std;
 
int main( int argc, char** argv )
{
  cout << "OpenCV version : " << CV_VERSION << endl;
  cout << "Major version : " << CV_MAJOR_VERSION << endl;
  cout << "Minor version : " << CV_MINOR_VERSION << endl;
  cout << "Subminor version : " << CV_SUBMINOR_VERSION << endl;
}

$ g++ opencv_check_version.cpp -o opencv_check_version `pkg-config --cflags --libs opencv4`
$ ./opencv_check_version 
OpenCV version : 4.1.0
Major version : 4
Minor version : 1
Subminor version : 0
728x90
728x90

출처

라즈비안(Raspberry pi OS)의 업데이트와 업그레이드

$ sudo apt-get update && sudo apt-get upgrade

OpenCV 4.1 관련 패키지 설치

OpenCV 빌드 관련 도구 설치

$ sudo apt-get install git cmake
$ sudo apt-get install libatlas-base-dev gfortran
$ sudo apt-get install libhdf5-serial-dev hdf5-tools
$ sudo apt-get install python3-dev

OpenCV 4.1 용 Python 3 가상 환경 구성

pip 설치

$ wget https://bootstrap.pypa.io/get-pip.py
$ sudo python3 get-pip.py
WARNING: The directory '/home/bluesanta/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
WARNING: The directory '/home/bluesanta/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Collecting pip
  Downloading https://files.pythonhosted.org/packages/62/ca/94d32a6516ed197a491d17d46595ce58a83cbb2fca280414e57cd86b84dc/pip-19.2.1-py2.py3-none-any.whl (1.4MB)
     |████████████████████████████████| 1.4MB 150kB/s 
Collecting setuptools
  Downloading https://files.pythonhosted.org/packages/ec/51/f45cea425fd5cb0b0380f5b0f048ebc1da5b417e48d304838c02d6288a1e/setuptools-41.0.1-py2.py3-none-any.whl (575kB)
     |████████████████████████████████| 583kB 379kB/s 
Collecting wheel
  Downloading https://files.pythonhosted.org/packages/bb/10/44230dd6bf3563b8f227dbf344c908d412ad2ff48066476672f3a72e174e/wheel-0.33.4-py2.py3-none-any.whl
ERROR: launchpadlib 1.10.6 requires testresources, which is not installed.
Installing collected packages: pip, setuptools, wheel
Successfully installed pip-19.2.1 setuptools-41.0.1 wheel-0.33.4
$ rm get-pip.py

virtualenv, virtualenvwrapper 설치

$ sudo pip install virtualenv virtualenvwrapper

python3, virtualenv 환경설정

$ echo -e "\n# virtualenv and virtualenvwrapper" >> ~/.profile
$ echo "export WORKON_HOME=$HOME/.virtualenvs" >> ~/.profile
$ echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.profile
$ echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.profile
$ source ~/.profile

가상환경을 만들기

$ mkvirtualenv cv -p python3
Already using interpreter /usr/bin/python3
Using base prefix '/usr'
New python executable in /home/pi/.virtualenvs/cv/bin/python3
Also creating executable in /home/pi/.virtualenvs/cv/bin/python
Installing setuptools, pip, wheel...
done.
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/predeactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/postdeactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/preactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/postactivate
virtualenvwrapper.user_scripts creating /home/pi/.virtualenvs/cv/bin/get_env_details

workon 명령을 사용하여 cv 환경에 있는지 확인

pi@raspberrypi:~$ workon cv
(cv) pi@raspberrypi:~$ 

numpy 파이썬 패키지 설치(OpenCV관련 수학 함수 모음)

pi@raspberrypi:~$ workon cv
(cv) pi@raspberrypi:~$ pip install numpy
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting numpy
  Using cached https://www.piwheels.org/simple/numpy/numpy-1.16.4-cp37-cp37m-linux_armv7l.whl
Installing collected packages: numpy
Successfully installed numpy-1.16.4
(cv) pi@raspberrypi:~$ python
Python 3.7.3 (default, Apr  3 2019, 05:39:12) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> quit()

TensorFlow 설치 : NVIDIA는 Jetson Nano의 TensorFlow 공식 릴리스를 제공

$ pip install --extra-index-url https://developer.download.nvidia.com/compute/redist/jp/v42 tensorflow-gpu==1.13.1+nv19.3
 
Successfully installed absl-py-0.7.1 astor-0.8.0 gast-0.2.2 grpcio-1.22.0 h5py-2.9.0 keras-applications-1.0.8 keras-preprocessing-1.1.0 markdown-3.1.1 mock-3.0.5 protobuf-3.9.0 six-1.12.0 tensorboard-1.13.1 tensorflow-estimator-1.13.0 tensorflow-gpu-1.13.1+nv19.3 termcolor-1.1.0 werkzeug-0.15.5

scipy, keras 설치

$ pip install scipy
$ pip install keras

Jetson Inference 컴파일 및 설치

$ cd ~
$ git clone https://github.com/dusty-nv/jetson-inference
$ cd jetson-inference
$ git submodule update --init
$ mkdir build
$ cd build/
$ cmake ../
$ make
$ sudo make install

이미지 인식 예제 실행

$ cd aarch64/bin
$ python3 my-recognition.py --network=googlenet black_bear.jpg
jetson.inference.__init__.py
jetson.inference -- initializing Python 3.6 bindings...
jetson.inference -- registering module types...
jetson.inference -- done registering module types
jetson.inference -- done Python 3.6 binding initialization
jetson.utils.__init__.py
jetson.utils -- initializing Python 3.6 bindings...
jetson.utils -- registering module functions...
jetson.utils -- done registering module functions
jetson.utils -- registering module types...
jetson.utils -- done registering module types
jetson.utils -- done Python 3.6 binding initialization
[image] loaded 'black_bear.jpg'  (800 x 656, 3 channels)
jetson.inference -- PyTensorNet_New()
jetson.inference -- PyImageNet_Init()
jetson.inference -- imageNet loading build-in network 'googlenet'

imageNet -- loading classification network model from:
         -- prototxt     networks/googlenet.prototxt
         -- model        networks/bvlc_googlenet.caffemodel
         -- class_labels networks/ilsvrc12_synset_words.txt
         -- input_blob   'data'
         -- output_blob  'prob'
         -- batch_size   1

[TRT]   TensorRT version 5.1.6
[TRT]   loading NVIDIA plugins...
[TRT]   Plugin Creator registration succeeded - GridAnchor_TRT
[TRT]   Plugin Creator registration succeeded - NMS_TRT
[TRT]   Plugin Creator registration succeeded - Reorg_TRT
[TRT]   Plugin Creator registration succeeded - Region_TRT
[TRT]   Plugin Creator registration succeeded - Clip_TRT
[TRT]   Plugin Creator registration succeeded - LReLU_TRT
[TRT]   Plugin Creator registration succeeded - PriorBox_TRT
[TRT]   Plugin Creator registration succeeded - Normalize_TRT
[TRT]   Plugin Creator registration succeeded - RPROI_TRT
[TRT]   Plugin Creator registration succeeded - BatchedNMS_TRT
[TRT]   completed loading NVIDIA plugins.
[TRT]   detected model format - caffe  (extension '.caffemodel')
[TRT]   desired precision specified for GPU: FASTEST
[TRT]   requested fasted precision for device GPU without providing valid calibrator, disabling INT8
[TRT]   native precisions detected for GPU:  FP32, FP16
[TRT]   selecting fastest native precision for GPU:  FP16
[TRT]   attempting to open engine cache file networks/bvlc_googlenet.caffemodel.1.1.GPU.FP16.engine
[TRT]   cache file not found, profiling network model on device GPU
[TRT]   device GPU, loading networks/googlenet.prototxt networks/bvlc_googlenet.caffemodel
[TRT]   retrieved Output tensor "prob":  1000x1x1
[TRT]   retrieved Input tensor "data":  3x224x224
[TRT]   device GPU, configuring CUDA engine
[TRT]   device GPU, building FP16:  ON
[TRT]   device GPU, building INT8:  OFF
[TRT]   device GPU, building CUDA engine (this may take a few minutes the first time a network is loaded)
[TRT]   device GPU, completed building CUDA engine
[TRT]   network profiling complete, writing engine cache to networks/bvlc_googlenet.caffemodel.1.1.GPU.FP16.engine
[TRT]   device GPU, completed writing engine cache to networks/bvlc_googlenet.caffemodel.1.1.GPU.FP16.engine
[TRT]   device GPU, networks/bvlc_googlenet.caffemodel loaded
[TRT]   device GPU, CUDA engine context initialized with 2 bindings
[TRT]   binding -- index   0
               -- name    'data'
               -- type    FP32
               -- in/out  INPUT
               -- # dims  3
               -- dim #0  3 (CHANNEL)
               -- dim #1  224 (SPATIAL)
               -- dim #2  224 (SPATIAL)
[TRT]   binding -- index   1
               -- name    'prob'
               -- type    FP32
               -- in/out  OUTPUT
               -- # dims  3
               -- dim #0  1000 (CHANNEL)
               -- dim #1  1 (SPATIAL)
               -- dim #2  1 (SPATIAL)
[TRT]   binding to input 0 data  binding index:  0
[TRT]   binding to input 0 data  dims (b=1 c=3 h=224 w=224) size=602112
[TRT]   binding to output 0 prob  binding index:  1
[TRT]   binding to output 0 prob  dims (b=1 c=1000 h=1 w=1) size=4000
device GPU, networks/bvlc_googlenet.caffemodel initialized.
[TRT]   networks/bvlc_googlenet.caffemodel loaded
imageNet -- loaded 1000 class info entries
networks/bvlc_googlenet.caffemodel initialized.
class 0295 - 0.989919  (American black bear, black bear, Ursus americanus, Euarctos americanus)
image is recognized as 'American black bear, black bear, Ursus americanus, Euarctos americanus' (class #295) with 98.991907% confidence
jetson.utils -- freeing CUDA mapped memory
PyTensorNet_Dealloc()

예제 : 카메라를 사용하여 이미지 분류

컴파일

$ cd ~/jetson-inference/build/
$ make imagenet-camera
[100%] Built target imagenet-camera

실행

728x90
728x90

M5Stack Korea인 WIZnet에서 운영하는 메이커 컨텐츠 커뮤니티 사이트의 후원을 받아서 작성되었습니다.

출처

M5Stack : Lego RC CAR (BLE 통신)





배선

M5Stack 아두이노 소스 : BLE 서버, L298N 모터 드라이버 모듈 제어

M5Stack 아두이노 소스

#include <M5Stack.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

// Motor A
int motor1Pin1 = 21; 
int motor1Pin2 = 22; 
int enable1Pin = 26; 

// Motor B
int motor1Pin1B = 16; 
int motor1Pin2B = 17;

//
int defaultDutyCycle = 210;

// Setting PWM properties
const int freq = 10000;
const int pwmChannel = 0;
const int resolution = 8;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;

void clearLCD() {
  M5.Lcd.clear(BLACK);
  M5.Lcd.setCursor(0, 0);
}

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      clearLCD();
      M5.Lcd.println("connect");
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      clearLCD();
      M5.Lcd.println("disconnect");
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
  void onRead(BLECharacteristic *pCharacteristic) {
    M5.Lcd.println("read");
    pCharacteristic->setValue("Hello World!");
  }

  // BLE 클라이언트로 명령르 받았을때 호출
  void onWrite(BLECharacteristic *pCharacteristic) {
    M5.Lcd.println("write");
    std::string value = pCharacteristic->getValue();

    // 정지명령을 받았을 때
    if (value.at(0) == 'S') {
      stopMotor();
      return;
    }
    
    // 속도값 추출
    int dutyCycle = defaultDutyCycle;
    //M5.Lcd.println(value.substr(2).c_str());
    if(sscanf(value.substr(2).c_str(), "%d", &dutyCycle) != 1)
      dutyCycle = defaultDutyCycle;

    if (value.at(0) == 'F') {
      forwardMotor(dutyCycle);
    } else if (value.at(0) == 'B') {
      backwardMotor(dutyCycle);
    }

    if (value.at(1) == 'C') {
      centerMotor();
    } else if (value.at(1) == 'L') {
      leftMotor();
    } else if (value.at(1) == 'R') {
      rightMotor();
    }
    
    M5.Lcd.println(value.c_str());
  }
};

// 뒤바뀌가 정지하고, 앞바퀴가 가운데로 설정
void stopMotor() {
  // Stop the DC motor
  Serial.println("Motor stopped");
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, LOW);
  centerMotor();
}

// 앞바퀴가 가운데로 설정
void centerMotor() {
  // Stop the DC motor
  Serial.println("Motor center");
  digitalWrite(motor1Pin1B, LOW);
  digitalWrite(motor1Pin2B, LOW);
}

// 뒤바뀌가 정방향으로 설정
void forwardMotor(int dutyCycle) {
  digitalWrite(motor1Pin1, HIGH);
  digitalWrite(motor1Pin2, LOW);
  ledcWrite(pwmChannel, dutyCycle);   
}

// 뒤바뀌가 역방향으로 설정
void backwardMotor(int dutyCycle) {
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, HIGH);
  ledcWrite(pwmChannel, dutyCycle);   
}

// 앞바뀌가 오른쪽으로 설정
void rightMotor() {
  digitalWrite(motor1Pin1B, LOW);
  digitalWrite(motor1Pin2B, HIGH); 
}

// 앞바뀌가 왼쪽으로 설정
void leftMotor() {
  digitalWrite(motor1Pin1B, HIGH);
  digitalWrite(motor1Pin2B, LOW); 
}

void setup() {
  Serial.begin(115200);
  M5.begin();
  M5.setWakeupButton(BUTTON_A_PIN);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println("BLE start.");
  m5.Speaker.mute();

  // sets the pins as outputs:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);
  pinMode(motor1Pin1B, OUTPUT);
  pinMode(motor1Pin2B, OUTPUT);
  
  // configure LED PWM functionalitites
  ledcSetup(pwmChannel, freq, resolution);
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(enable1Pin, pwmChannel);

  BLEDevice::init("m5-stack");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE |
                                         BLECharacteristic::PROPERTY_NOTIFY |
                                         BLECharacteristic::PROPERTY_INDICATE
                                       );
  pCharacteristic->setCallbacks(new MyCallbacks());
  pCharacteristic->addDescriptor(new BLE2902());

  pService->start();
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  if(M5.BtnA.wasPressed()) {
    M5.powerOFF();
  } else if(M5.BtnC.wasPressed()) {
    clearLCD();
  }
  
  if (deviceConnected) {
    if(M5.BtnB.wasPressed()) {
      M5.Lcd.println("Button B pressed!");
      pCharacteristic->setValue("Button B pressed!");
      pCharacteristic->notify();
    }
  }
  M5.update(); 
}

App Inventor : 안드로이드 어플 제작

App Inventor 디자인

App Inventor - 전역변수 선언 (BLE 서비스, 특성 UUID은 미리 설정)

App Inventor - BLE로 문자열 전달하는 함수 만들기 (메시지를 받아서 BLE 모듈로 호출)

App Inventor - 버튼을 누르고 있는데 터치 다운, 누리고 있다가 띄었을 때 터치 업 이벤트 발생시 위에서 구현 한 함수 호출

App Inventor 블럭 소스

실행 영상

M5Stack 물품 구매는 <네이버 검색/쇼핑에서 M5StackKorea>를 검색하시거나, M5Stack 공식 파트너인 <위즈네트 쇼핑몰: Shop.wiznet.io> 으로 접속하세요.

728x90
728x90

M5Stack Korea인 WIZnet에서 운영하는 메이커 컨텐츠 커뮤니티 사이트의 후원을 받아서 작성되었습니다.

출처

M5Stack : 레고 Power function 모터 제어(L298N 사용)

L298N 모듈은 아두이노로 RC Car를 만들기 위해서 많이 사용하는 모터 드라이버 모듈로 정방향과 역방향으로 2개의 모터 제어가 가능하고, 속도 조절도 됩니다.

예제에서는 Lego Power function 모터를 L298N으로 제어하고 L298N은 M5Stack으로 명령을 실행하고 있습니다.

M5Go Port

PORT A : GPIO 21, 22 pin
PORT B : GPIO 26, 36 pin
PORT C : GPIO 16, 17 pin

배선

M-Motor의 경우 별도의 전원 연결이 필요없이, L298N에 C1, C2핀만 연결하면 됩니다.

  • ENA     IN1       IN2
  • 26pin   21pin     22pin

Lego Power function 연결 케이블 핀번호

Lego Power function M-Mortor 연결

L298N 연결

Lego Li-Battery Box 연결

M5Go의 Port A와 Port B에 Grove 캐이블 연결

M5Stack 아두이노 소스

예제는 26번 핀을 PWM제어로 속도를 설정하고, 정방향으로 회전시키고, 다시 역방향으로 회전 시켜보았습니다.

#include <M5Stack.h>

// Motor A
int motor1Pin1 = 21; 
int motor1Pin2 = 22; 
int enable1Pin = 26; 

// Setting PWM properties
const int freq = 10000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 150;

void setup() {

  // 초기화
  M5.begin(true, false, true);
  M5.Lcd.setTextFont(4);
  M5.Lcd.setCursor(40, 100);
  M5.Lcd.print("L298N Motor Driver");
  
  // sets the pins as outputs:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);
  
  // configure LED PWM functionalitites
  ledcSetup(pwmChannel, freq, resolution);
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(enable1Pin, pwmChannel);

  Serial.begin(115200);

  // testing
  Serial.print("Testing DC Motor...");
}

void loop() {

  // Stop the DC motor
  Serial.println("Motor stopped");
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, LOW);
  delay(1000);

  // Move DC motor forward with increasing speed
  digitalWrite(motor1Pin1, HIGH);
  digitalWrite(motor1Pin2, LOW);
  while (dutyCycle <= 255){
    ledcWrite(pwmChannel, dutyCycle);   
    Serial.print("Forward with duty cycle: ");
    Serial.println(dutyCycle);
    dutyCycle = dutyCycle + 5;
    delay(500);
  }
  dutyCycle = 255;

  // Stop the DC motor
  Serial.println("Motor stopped");
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, LOW);
  delay(1000);

  // Move DC motor forward with increasing speed
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, HIGH);
  while (dutyCycle > 150){
    ledcWrite(pwmChannel, dutyCycle);   
    Serial.print("Backwards with duty cycle: ");
    Serial.println(dutyCycle);
    dutyCycle = dutyCycle - 5;
    delay(500);
  }
  dutyCycle = 150;
}

실행 영상

M5Stack 물품 구매는 <네이버 검색/쇼핑에서 M5StackKorea>를 검색하시거나, M5Stack 공식 파트너인 <위즈네트 쇼핑몰: Shop.wiznet.io> 으로 접속하세요.

728x90

+ Recent posts