카카오톡과 LoRa 기술을 이용한 Pet Feeder

Posted by 카이젠8501 카이젠8501
2017.06.19 17:17 IT 개발/DIY 프로젝트

카카오톡과 LoRa 기술을 이용한 Pet Feeder

구현 아이디어 및 요약

최근 사물인터넷(Internet of Things, IoT)은 차세대 이동통신 서비스의 생태계 구축을 위해 가장 중요한 역할을 수행 할 것으로 예측되고 있으며, 사물인터넷을 위한 LPWAN(Low-Power Wide-Area Network)에 대한 관심이 증가하고 있다.
국내 통신사에서도 LPWAN 기술 및 IoT에 지속적으로 관심을 가지고 있으며, 국내 3사 통신사 중 SKT는 LoRa, LG와 KT는 NB-IoT를 주력 IoT 서비스로 내세우고 있다.

본 프로젝트에서는 SKT의 LoRa 서비스를 이용해 애완동물의 먹이를 원격에서 줄 수 있는 Pet Feeder를 구현 할 예정이며, Pet Feeder Service를 구성하는 컨트롤러 보드, LoRa 모니터링 서버, 스마트폰 구현 방법에 대해 설명한다.

프로젝트 목표

  • 카카오톡을 이용한 먹이 주기 명령 수행
  • 컨트롤러 보드에서 온/습도 정보를 측정해서 LoRa 모니터링 서버에서 모니터링 하기

프로젝트 구성도

프로젝트는 아래 그림과 같이 컨트롤러, SKT LoRa Network, LoRa 모니터링 서버, 카카오톡 서버로 구성된다.
컨트롤러에서 온/습도 데이터를 측정해서 LoRa로 데이터를 송신하면, SKT의 G/W(Gateway)와 N/W(Network)서버를 통해 ThingPlug에 데이터를 전달한다. ThingPlug는 전달 받은 데이터를 LoRa 모니터링 서버에게 다시 전달하고, LoRa 모니터링 서버는 수신한 데이터를 자신의 DB(Database)에 저장한다.

참고로, ThingPlug에 전달된 데이터는 ThingPlug에 DB에 임시적으로 저장되지만, 저장된 데이터는 2일 후에 삭제 된다. 때문에 본 프로젝트와 같이 사용자가 직접 구현한 서버에서 ThingPlug의 데이터를 가져 오는 작업을 해야 한다. ThingPlug에서 데이터를 가져오는 방법은 해당 링크를 참고 하기 바란다.http://docs.thingplug.apiary.io/#reference/data-management

추가로 카카오톡 서버에서는 발생하는 이벤트를 LoRa 모니터링 서버로 Redirection 해서, 사용자가 카카오톡을 이용하여 먹이 주기를 수행 할 수 있는 구조로 설계 하였다.

Contest1

컨트롤러

컨트롤러의 역할은 온/습도 정보를 측정하여 SKT LoRa Network로 전달하는 기능과 카카오톡으로 부터 먹이 주기 명령을 받으면 내부에 있는 스크류를 동작 시켜 애완동물의 먹이를 밖으로 배출한다.

컨트롤러의 구성요소는 아래와 같다.

  • T자형 PVC와 내부 스크류
  • Continuous Rotation Servo ( Parallax )
  • WizArduino Mega Wifi ( WIZnet )
  • LoRa Kit ( WIZnet )
  • LoRa 모듈 (TLT01CS1, 솔루엠)
  • 온습도 센서 ( DHT11 )

컨트롤러는 아래와 같은 단계로 제작 되었다.

  1. Thingiverse에서 해당 프로젝트에서 사용할 수 있는 3D 모델링 파일들을 검색하고, 이를 3D 프린터로 출력. (모델링 파일의 원본 주소: https://www.thingiverse.com/thing:34100 )
  2. 출력된 스크류와 서보 모터를 연결하고, 이를 50파이 짜리 T자형 PVC에 장착
  3. WizArduino MEGA WIFI와 Wiznet Lora Kit 연결 ( WizArduino와 LoRa Kit간에는 Software UART(RX:10,TX:11)를 사용 함 )
  4. WizArduino의 9번 핀을 이용하여 Servo Motor 제어

Contest4

본 프로젝트를 위해 SoluM 모듈을 Arduino 에서 사용 할 수 있도록 라이브러리 작업을 진행 하였으며, 해당 라이브러리는 아래 주소에서 다운 받을 수 있다.
https://github.com/kaizen8501/solum_lora_library

컨트롤러 역할을 하는 아두이노 보드의 코드는 아래와 같다.

#include "Arduino.h"
#include <SKT_LoRa.h>
#include <SoftwareSerial.h>
#include <Servo.h>

SoftwareSerial LoRaSerial(10, 11); // RX, TX
Servo servo;
int servoPin = 9;

void setup()
{
    servo.attach(servoPin);
    servo.write(90);

    Serial.begin(38400);
    LoRaSerial.begin(38400);
    LoRa.init(&LoRaSerial);
    LoRa.begin();
}

void loop()
{
    char str[100];
    if( LoRa.available() )
    {
        LoRa.read((uint8_t*)str,100);
        if( strcmp(str,"1000\r\n") == 0 )
        {
            Serial.println("Start Feed");
            servo.write(120);
            delay(5000);
            servo.write(90);
        }
    }
}

LoRa 모니터링 서버

로라 모니터링 서버는 Django 플랫폼을 이용하여 구현 하였으며, 컨트롤러와 같이 SKT LoRa Network에 연결되어 있는 디바이스들의 정보를 모니터링 하거나 제어 할 수 있는 기능을 가지고 있다. 또한 본 프로젝트를 위한 용도 이외에 SKT LoRa를 위한 범용 웹 서버로 사용 가능 하다.

Contest5

카카오톡 플러스 친구 설정 및 연동 방법

카카오톡 플러스 친구를 설정하기 위해서는 https://center-pf.kakao.com/에 접속하고 아래와 같은 절차를 수행 해야 한다.

새 플러스 친구 만들기 버튼 클릭 후 정보 기입

Contest6-0

Contest6-1

스마트 채팅 설정

아래 그림과 같이 스마트 채팅 탭을 클릭하고 API형에 대한 설정 버튼을 눌러 API에 대한 설정을 진행 한다.
자동응답형은 노출되는 버튼을 선택해서 제어 하는 방식으로 사용 할 수 있으며, 본 프로젝트는 대화형으로 제어 명령을 보내기 위해 API 형을 사용 하였다.

Contest6

API형 설정

API형 설정에서 가장 중요한 부분은 앱 URL 이다. 앱 URL에 기입 란에 LoRa 모니터링 서버의 URL 혹은 IP 주소를 입력하고 카카오톡을 위한 keyboard와 message가 구현되어 있는 URL 주소를 입력한다.
본 프로젝트는 아래와 같이 http://IP주소/thingplug/device/kakao 로 설정되어 있다.

urlpatterns = [
    url(r'^device/kakao/keyboard/', views.pet_feeder_kakao_keyboard),
    url(r'^device/kakao/message', views.pet_feeder_kakao_message),
    ]

Contest7

카카오톡 연동을 위한 설정이 정상적으로 완료 되었다면, API 테스트 버튼을 눌렀을 때 아래와 같이 keyboard OK 응답을 받아야 한다.

Contest8

카카오톡 연동을 위한 Python 코드는 아래와 같다.

def pet_feeder_kakao_keyboard(request):
    return JsonResponse({
            'type':'text',
            })


kakao_user = ''
kakao_device = ''

@csrf_exempt
def pet_feeder_kakao_message(request):
    global  kakao_user
    global  kakao_device

    json_str = ((request.body).decode('utf-8'))
    received_json_data = json.loads(json_str)
    command = received_json_data['content']

    user_obj = User.objects.all()
    user_info = ''

    if command.find('계정') != -1:
        for user in user_obj:
            user_info += '- ' + user.username + '\r\n'
        return JsonResponse({
            'message':{
                'text': '등록된 계정은 아래와 같습니다.\r\n' + user_info
            },
        })
    elif command.find('헬프') != -1 or command.find('help') != -1:
        return JsonResponse({
            'message': {
                'text': '명령어 리스트\r\n' +
                        '- 계정\r\n' +
                        '- 장치 리스트\r\n' +
                        '- 밥줘\r\n'
            },
        })
    elif command.find('재접속') != -1:
        pass

    elif command.find('장치리스트') != -1 or command.find('장치 리스트') != -1:
        command_list = command.split(' ')
        for command in command_list:
            for user in user_obj:
                if command.find(user.username) != -1:
                    kakao_user = user.username
                    #device_info = ''
                    device_list = []
                    tp_info_obj = ThingplugInfo.objects.get(user=user)
                    dev_obj = DeviceInfo.objects.filter(thingpluginfo=tp_info_obj)
                    for device in dev_obj:
                        #device_info += device.device_id + "\r\n"
                        device_list.append(device.device_id+' 장치 등록')

                    return JsonResponse({
                        'message':{
                            #'text': '등록된 장치는 아래와 같습니다.\r\n' + device_info
                            'text': '등록된 장치는 아래와 같습니다.'
                        },
                        'keyboard':{
                            'type': 'buttons',
                            'buttons':device_list
                        }
                    })
        return JsonResponse({
            'message':{
                'text': '계정 정보를 포함해서 질문 해 주세요.'
            }
        })

    elif command.find('장치 등록') != -1:
        try:
            user = User.objects.get(username=kakao_user)
        except User.DoesNotExist:
            return JsonResponse({
                'message': {
                    'text': '[장치 리스트]를 요청해 주세요.'
                }
            })
        try:
            tp_info_obj = ThingplugInfo.objects.get(user=user)
            dev_obj = DeviceInfo.objects.filter(thingpluginfo=tp_info_obj)
        except:
            return JsonResponse({
                'message': {
                    'text': 'ThingPlug 정보 확인 바람'
                }
            })

        command_list = command.split(' ')
        for command in command_list:
            for device in dev_obj:
                if command.find(device.device_id) != -1:
                    kakao_device = device.device_id
                    return JsonResponse({
                        'message': {
                            'text': kakao_device + ' 등록 완료'
                        }
                    })

        return JsonResponse({
            'message': {
                'text': '디바이스 정보가 없습니다.'
            }
        })

    elif command.find('밥') != -1:
        node_id = kakao_device
        mgmt_cmd = '1000'
        result, cmd_inst = g_thingplug.createMgmtInstance(node_id, "extDevMgmt", mgmt_cmd)
        time.sleep(3)
        result, exe_status, exe_result = g_thingplug.retrieveMgmtResult(node_id, "extDevMgmt", cmd_inst)
        if result == True:
            message = node_id + ' 동작 성공'
        else:
            message = node_id + ' 동작 실패'

        return JsonResponse({
            'message': {
                'text': message
            },
        })

    return JsonResponse({
        'message': {
            'text': '명령이 없습니다.'
        },
    })

카카오톡 데모

스마트폰에서 카카오톡 플러스 친구를 추가 하고, 아래 그림과 같이 명령을 수행하면 컨트롤러를 제어 할 수 있다.

Contest9

웹페이지 데모

LoRa 모니터링 서버에서는 웹 서버 기능도 지원하고 있으며, 아래와 같은 페이지를 이용하여 컨트롤러에게 제어를 내리거나 컨트롤러가 송신하는 데이터를 로그 및 차트 형태로 확인 할 수 있다.

Contest10

동작 데모


저작자 표시
신고
이 댓글을 비밀 댓글로

DIY Projects using WizFi250 or WizFi210

Posted by 카이젠8501 카이젠8501
2016.10.10 10:50 IT 개발/DIY 프로젝트

본 포스팅은 WIZnet의 Wi-Fi Module인 WizFi250과 WizFi210을 활용한 DIY 프로젝트들을 소개한다.

To Make Canon DSLR’s Remote controller using  WizFi250

본 프로젝트에서는 Canon Camera를 제어하기 위한 Wi-Fi Remote Controller를 만드는 방법에 대해 설명한다.

 해당 장치를 위해서는 아래와 같은 구성 요소가 필요하다.

  • Camera
    • Receiver와 2.5pi Audio Cable을 이용하여 연결
  • Receiver
    • Arduino Uno(MCU)+WizFi250 (Wi-Fi Module)
    • WizFi250의 AP 기능을 사용 ( 별도의 유/무선 공유기 없이 스마트폰과 다이렉트로 연결 )
  • Remote Controller
    • Smart Phone
    • Simple Android App

Wiznet Museum : http://wiznetmuseum.com/portfolio-items/to-make-canon-dslrs-remote-controller-using-wizfi250/

Author’s Blog(KOR) : http://kaizen8501.tistory.com/86

Author’s Blog(ENG) : http://www.life4iot.com/2015/01/18/to-make-canon-dslrs-remote-controller-using-wizfi250/?lang=en

 

WiFi Electric Skateboard using WIZwiki-W7500ECO + WizFi250

본 프로젝트에서는 WIZwiki-W7500ECO MCU Board와 WizFi250 Wi-Fi Module을 이용하여 전동 스케이트 보드를 만드는 방법에 대해 설명한다.

필요한 구성 요소는 아래와 같다. 해당 구성 요소에 대한 구입을 원하는 경우, 아래 구성 요소들의 이름을 클릭하여 구매 사이트로 이동하면 된다.

 

Wiznet Museum : http://wiznetmuseum.com/portfolio-items/to-make-canon-dslrs-remote-controller-using-wizfi250/

Author’s Blog(KOR) :

http://kaizen8501.tistory.com/112

http://kaizen8501.tistory.com/113

http://kaizen8501.tistory.com/114

Author’s Blog(ENG) :

- http://www.life4iot.com/2015/10/29/electric-skateboard-1-material/

http://www.life4iot.com/2015/10/29/electric-skateboard2-servo-motor-test/

http://www.life4iot.com/2015/10/29/electric-skateboard3-wi-fi-receiver-and-controller/

 

Hedgehog - Educational Robotics Controller

Hedgehog는 Robot을 이용하여 교육 및 연구를 하기 원하는 사람들을 위한 프로젝트이다. 본 프로젝트는 2015년에 KickStarter에 게시 되었지만 펀딩에는 실패 하였다. 하지만 로봇 동작 원리 및 임베디드 디바이스의 동작 원리를 쉽고 간단하게 학습 하기 좋은 프로젝트로 판단 되어 본 포스팅에서 소개 하게 되었다. 참고로 Hedgehog의 Wi-Fi 통신에는 WizFi210 Wi-Fi Module이 탑재되어 있다.

본 프로젝트의 자세한 내용은 아래 링크를 참고 하기 바란다.

Wiznet Museum : http://wiznetmuseum.com/portfolio-items/hedgehog-educational-robotics-controller-2/

KickStarter : https://www.kickstarter.com/projects/priarobotics/hedgehog-educational-robotics-controller


Drainage tank of water purifier IoT

본 프로젝트는 정수기를 사용하면서 한번 쯤 필요하다고 생각한 아이디어를 실제로 구현하고 구현 방법을 정리 하였다.
저자는 Arduino와 WizFi250(Wi-Fi Module)을 이용하여, 정수기 배수통에 물을 비워야 하는지 확인하고 배수통에 물이 일정 높이 이상 차면 등록된 E-mail로 알려주는 장치를 구현하였다.

해당 장치에 대한 자세한 설명이 필요하면 아래 링크를 참고 하기 바란다.
Wiznet Museum : http://wiznetmuseum.com/portfolio-items/drainage-tank-of-water-purifier-iot/





신고
이 댓글을 비밀 댓글로

DIY Smart Home Projects 소개

Posted by 카이젠8501 카이젠8501
2016.09.05 11:06 IT 개발/DIY 프로젝트

DIY Smart Home Projects

사물인터넷의 발전과 함께 스마트 홈 으로 주거문화가 바뀌고 있다. 최근 모 통신사의 광고와 같이 집 밖에서 냉/난방기의 온도를 조절하고 집에 있는 기기를 제어 한 다거나, 웹캠을 이용하여 집 안을 모니터링 하는 일은 이미 우리에게 낯익은 풍경이 되어 가고 있다.

이와 더불어, 인터넷 상에서는 아두이노와 라즈베리파이와 같은 오픈소스하드웨어의 영향으로 메이커(Maekr)들이 직접 설계하고 구현한 스마트 홈 프로젝트들을 공유 하고 있다.

본 포스팅에서는 메이커(Maker)들이 직접 만든 스마트 홈 프로젝트를 종류 별로 분류하고 소개 한다.

Aquarium

Arduino Fish Tank Controller

이 프로젝트는 Arduino와 Ethernet Shield를 사용해서 웹 서버를 구현하고, 구현한 웹 서버를 이용해서 물고기 밥을 주는 장치와 조명 장치를 제어 한다. 그리고 온도 센서를 이용해서 수족관 안의 온도 및 외부 온도를 모니터링 하는 장치를 구현 하였다.

Feeder

CatFeeder

본 프로젝트의 저자는 고양이 먹이를 자동으로 주기 위한 장치를 개발 하였다.

장치에는 버튼이 부착되어 있어, 이 버튼을 이용하여 고양이 먹이를 줄 수 있다. 또한 이더넷을 위한 장치를 연결하여 외부에서도 스마트 폰을 이용하여 고양이 먹이를 줄 수 있다.

Twitter Controlled Pet Feeder

본 프로젝트는 Twitter와 연동하여 애완 동물의 먹이를 Twitter Message로 제어 할 수 있는 장치를 구현 하였다. 앞에서 소개한 CatFeeder는 자체 웹 서버를 구현하여 스마트폰이 웹 브라우저를 통해 제어 하였다면 이 프로젝트는 Twitter라는 범용 SNS 툴을 이용하여 제어 할 수 있다는 점이 특징이다.

Garden

SmartGarden

본 프로젝트의 저자는 본인이 키우는 화분의 온/습도를 측정하고 물을 원격에서 줄 수 있는 시스템을 구축 하였다. 프로젝트는 Paraimpu(https://www.paraimpu.com) 라는 클라우드 서비스를 이용하였으며 Paraimpu를 통해 측정된 온도 값을 Tweeter로 보내고 Tweeter로 부터 받은 제어 신호를 가지고 자동 급수기를 On/Off 할 수 있다.

CloudCooker

본 프로젝트의 저자는 바베큐 그릴의 온도 및 음식의 온도를 측정하고 온도를 조절 할 수 있는 스마트 그릴를 만드는 것을 목표로 하였다.

이 프로젝트는 Microsoft에서 만든 Azure 클라우드 서비스의 기능을 이용하여 프론트엔드(Front-end)에서 더 다양한 형태로 데이터를 출력하고 제어 하는 기능을 제공 할 수 있다는 특징이 있다.

http://www.codeproject.com/KB/AzureIoT/882552/egg2.jpg


지금까지 메이커(Maker)들이 직접 만든 Smart Home Project들을 소개 하였다. 각 프로젝트에 있는 링크를 따라가면, 프로젝트에서 사용한 보드,클라우드 시스템 및 구축 방법이 자세히 설명되어 있고 심지어는 소스코드 까지 공유 되어 있다.

이런 자료들을 이용하여 한개 혹은 두가지 프로젝트를 튜토리얼 식으로 따라 하다 보면 필요한 기술을 쉽게 습득 할 수 있다. 더불어 습득한 기술에 아이디어를 추가하면 여러분 만의 독창적인 프로젝트를 만드는 것도 어렵지 않을 것으로 판단 한다.

저작자 표시
신고
이 댓글을 비밀 댓글로
    • 박지수
    • 2017.04.26 22:06 신고
    우와.. 진짜 멋지시네요!

[전동 Skateboard 만들기]#3 Wi-Fi 모듈 연결 및 Control 어플 구현

Posted by 카이젠8501 카이젠8501
2015.11.03 09:58 IT 개발/DIY 프로젝트

[전동 Skateboard 만들기]#3 Wi-Fi 모듈 연결 및 Control 어플 구현

Hardware of Wi-Fi Receiver

Wi-Fi 수신기는 스마트폰에서 데이터를 수신하여 스케이트 보드의 속도를 조절하는 장치이며, 하드웨어 구성은 아래와 같다.

20151029_143029

아래 사진은 완성된 하드웨어 사진이다. 배터리나 다른 보드들과의 circuit short를 방지하기 위해 절연 테이트를 부착하여 조금 부족해 보이지만 동작에는 문제가 없다.

오른쪽에 3핀, 2핀이 나와 있는데, 위에 3핀은 PWM,3.3V VCC,GND 핀이고, 아래 2핀은 배터리에서 받아 올 5V VCC, GND 핀이다.

20151030_082315

Wi-Fi Receiver Firmware

Source Code

Wi-Fi Receiver firmware는 아래 그림과 같은 구조로 동작된다. 스마트폰에서 Speed Up 명령을 주면 Wi-Fi Receiver는 속도를 5% 올리고 Speed Down 명령을 주면 속도를 5% 내린다.

20151030_084225

예외 상황에서는 아래 그림과 같이 Motor를 정지 한다. 단 Motor가 정지 되어도 가속도 때문에 스케이트 보드는 계속 움직일 수는 있다.

20151030_085505

Wi-Fi 수신기에 대한 소스코드는 아래 경로에서 다운로드 할 수 있다.
https://developer.mbed.org/users/kaizen/code/Wifi_Electric_Skateboard/

#include "mbed.h"
#include "Servo.h"
#include "WizFi250Interface.h"

#define SECURE WizFi250::SEC_WPA2_MIXED
#define SSID "Kaizen_Skate"
#define PASS "qwertyuiop"

#define SERVER_PORT    5000
#define STOP_MOTOR     50


#if defined(TARGET_WIZwiki_W7500P)
    WizFi250Interface wizfi250(PC_2,PC_3,PC_13,PC_14,PC_12,NC,115200);
    Serial pc(USBTX, USBRX);
    Servo motor_speed(PC_8);      // it used to percentage value ( 0 ~ 1 )
    DigitalOut green_led(LED2);    
    DigitalOut red_led(LED1);
    DigitalOut blue_led(LED3);
#endif

#define START_MSG       "START"
#define END_MSG         "END\n"
#define CONTROL_UP      "UPXX"
#define CONTROL_DOWN    "DOWN"
#define CONTROL_CRUISER "CRUI"
#define CONTROL_STOP    "STOP"

#define STATUS_CMD_OK   "OKXX"
#define STATUS_CMD_FAIL "FAIL"

#define CONTROL_MSG_SIZE    19

// Control Pkt Format : START,CONTROL,SPEED_VALUE,END
//                      START,UPXX,500,END
// Status Pkt Format : START,CONTROL,SPEED_VALUE,STATUS,END

struct control_pkt{
    char start_msg[6];
    char control_msg[5];
    char speed_msg[4];
    char end_msg[4];
};
void parse(char buffer[], int *j, char *string);

int main() {    
    int recv_cnt,j;
    volatile float speed_value = 0.5;
    char recv_control_msg[100];
    char status_msg[100];
    control_pkt control;

    pc.baud(115200);
    green_led = 1; red_led = 1; blue_led = 1;

    wizfi250.init();
    wizfi250.setAntMode(WizFi250::PCB);
    wizfi250.setAddress("192.168.100.2","255.255.255.0","192.168.100.1");
    if ( wizfi250.connect(SECURE, SSID, PASS, WizFi250::WM_AP))
    {
        red_led = 0;
        return -1;
    }
    printf("IP Address is %s\r\n", wizfi250.getIPAddress());
    green_led = 0; red_led = 0; blue_led = 0;

    TCPSocketServer server;
    TCPSocketConnection client;

    while(true)
    {
        if( client.is_connected() == false )
        {
            green_led = 1; red_led = 1; blue_led = 0;            
            client.close();
            server.close();

            if(speed_value == 0.5)
            {
                server.bind(SERVER_PORT);
                server.listen();

                printf("\nWait for new connection...\r\n");
                server.accept(client);
                client.set_blocking(false, 1500);
            }
            else if(speed_value <= 0.4)
            {
                printf("Speed decrease +\r\n");

                speed_value = 0.5;
                motor_speed = speed_value;
            }
            else
            {
                printf("Speed decrease -\r\n");
                speed_value = 0.5;  motor_speed = speed_value;
            }
        }
        else
        {
            motor_speed = speed_value;

            green_led = 0; red_led = 1; blue_led = 1;
            //recv_cnt = client.receive_all((char*)recv_control_msg, sizeof(control)-1);
            recv_cnt = client.receive_all((char*)recv_control_msg, sizeof(control));

            j=0;
            parse(recv_control_msg, &j, control.start_msg);
            parse(recv_control_msg, &j, control.control_msg);
            parse(recv_control_msg, &j, control.speed_msg);
            parse(recv_control_msg, &j, control.end_msg);

            if(recv_cnt > 0)
            {
                if( (strncmp(control.start_msg,START_MSG,sizeof(control.start_msg)) != 0) || 
                    (strncmp(control.end_msg,END_MSG,sizeof(control.end_msg)) != 0) )
                {
                    printf("TEST Error\r\n");
                    sprintf(status_msg,"%s,%03d,%s,%s\n",START_MSG,int(speed_value*100),STATUS_CMD_FAIL,END_MSG);
                    client.send_all((char*)status_msg,strlen(status_msg));
                    continue;
                }

                if( strncmp(control.control_msg,CONTROL_UP,sizeof(control.control_msg)) == 0 )
                {
                    speed_value += 0.05; 
                    motor_speed = speed_value;
                    printf("TEST UP %f\r\n",speed_value); 
                }
                else if( strncmp(control.control_msg,CONTROL_DOWN,sizeof(control.control_msg)) == 0)
                {
                    speed_value -= 0.05; 
                    motor_speed = speed_value;
                    printf("TEST DOWN %f\r\n",speed_value);
                }
                else if( strncmp(control.control_msg,CONTROL_CRUISER,sizeof(control.control_msg)) == 0)
                {
                    printf("TEST CRUISER\r\n"); 
                    speed_value = (float)(atoi(control.speed_msg)) / 100;
                    motor_speed = speed_value;
                }
                else if( strncmp(control.control_msg,CONTROL_STOP,sizeof(control.control_msg)) == 0)
                {
                    printf("TEST STOP\r\n"); 
                    speed_value = 0.5;
                    motor_speed = speed_value;
                }
                else
                {
                    printf("TEST Error 1-2\r\n");
                    sprintf(status_msg,"%s,%03d,%s,%s\n",START_MSG,int(speed_value*100),STATUS_CMD_FAIL,END_MSG);
                    client.send_all((char*)status_msg,strlen(status_msg));
                    continue;
                }

                sprintf(status_msg,"%s,%03d,%s,%s\n",START_MSG,int(speed_value*100),STATUS_CMD_OK,END_MSG);
                client.send_all((char*)status_msg,strlen(status_msg));
            }
            else
            {
                sprintf(status_msg,"%s,%03d,%s,%s\n",START_MSG,int(speed_value*100),STATUS_CMD_OK,END_MSG);
                client.send_all((char*)status_msg,strlen(status_msg));
            }
        }
    }// while
}

void parse(char buffer[], int *j, char *string) {
//extracts next location string data item from buffer
    int i=0;
    for (i=0; i<=strlen(buffer); i++) {  //TOTAL SIZE OF RETURNED DATA
        if ((buffer[*j+i] == ',')||(buffer[*j+i] == '\0' )) { //IF comma or end of string
            //comma is the string field delimiter
            string[i]=0; //SETS END OF SRTRING TO 0
            *j=*j+i+1; //UPDATES to 1 after comma seperated value
            break;
        } else string[i]=buffer[*j+i]; //Keep adding to the string
    }
}

스마트폰 어플

Screenshot_2015-10-29-16-20-25

Source Code

https://github.com/kaizen8501/WiFi_Skateboard

Demo Video


저작자 표시
신고
이 댓글을 비밀 댓글로
    • ㅇㅇ
    • 2016.12.17 21:51 신고
    너무 어렵다.........
    • 안녕하세요^^

      어느 부분이 어려우신지 말씀해 주시면 제가 아는 한도 내에서 자세히 설명 해 드리도록 하겠습니다^^

전동 Skateboard 만들기 #2

Posted by 카이젠8501 카이젠8501
2015.11.03 09:57 IT 개발/DIY 프로젝트

전동 Skateboard 만들기 #2

Mortor Test

Hardware 구성

다들 아시겠지만, 서보모터는 MCU의 PWM 파형을 이용하여 구동한다. PWM 파형을 제어하기 위해 Cortex-M0 계열의 WIZwiki-W7500ECO 보드를 이용하였으며, 하드웨어 구성은 아래 그림과 같다.

20151029_143257

Test Software

Software는 mbed 환경에서 구현하였다. 서보 모터를 제어하기 위해, mbed에서는 Servo 라이브러리를 제공하며 사용방법은 아래 주소를 참고 하기 바란다. (Servo Library)

내 스케이트 보드에 장착되어 있는 보드의 모터에 어떤 값을 입력하였을 때, 전진하고 후진하는지 알아 보기 위해 아래와 같은 테스트 코드를 작성하였다. mbed Servo는 0 ~ 1 사이의 값으로 PWM 파형을 생성하며, 스케이트 보드에 장착된 모터는 0.4 ~ 0.55 값에서 중립 상태를 보인다.

#include "mbed.h"
#include "Servo.h"

int main() {    
    uint8_t ch;
    volatile float speed_value = 0.5;

    Servo myservo(PC_8);
    Serial pc(USBTX,USBRX);

    pc.baud(115200);
    wait(1);
    pc.printf("TEST Start\r\n");

    while(1)
    {
        pc.printf("speed : %f\r\n",speed_value);
        myservo = speed_value;

        ch = pc.getc();

        if(ch == 'u')
        {
            speed_value += 0.001;
        }
        else if(ch == 'd')
        {
            speed_value -= 0.001;
        }

        else if(ch == 's')
        {
            myservo = 0.5;
            wait(0.5);

            speed_value = 0.41;
            myservo = speed_value;
            wait(5);

            speed_value = 0.5;
            myservo = speed_value;

        }
    }
}

위 코드는 https://developer.mbed.org/users/kaizen/code/Servo_HelloWorld/에서 확인 및 다운로드 할 수 있다.


저작자 표시
신고
이 댓글을 비밀 댓글로

전동 Skateboard 만들기 #1

Posted by 카이젠8501 카이젠8501
2015.11.03 09:56 IT 개발/DIY 프로젝트

전동 Skateboard 만들기 #1

Skateboard Meterial

기본적인 스케이트보드 구동을 위해서는 아래와 같은 재료들이 필수적으로 필요 하다. 보드에 대해서 잘 알지는 못하지만, 라이딩용으로 만들기 위해 90mm Wheel과 34” Longboard Deck를 구매 하였다. 아래 링크를 이용하면 각 부품에 대한 자세한 설명과 구매 정보를 확인 할 수 있다.

34” Cruiser Longboard Deck

30-inch-Electric-Longboard-325x127

Trucks

20151029_091514

90mm Wheels

90mm-longboard-wheels-epower-neon-green

Bearings 8mm

longboard-bearings-322x215

Electrick Meterial

Motor

Electric-Skateboard-Motor2
50mm RC Brushless Motor, 2200 Watts / 2.95HP Motor, 200KV, 80Amp, 50mm x 65mm, 8mm shaft

Motor Mount

50mm-motor-mount

44T Drive Wheel Pulley Adapter

44T-Electric-Skateboard-Drive-Wheel-Pulley

16t-htd5-motor-pulley-322x215

12S 120A ESC

TorqueBoards-12S-120A-ESC-OPTO1

TorqueBoards ESC Programming Card

torqueboards-esc-programming-card

12S UBEC

12s-ubec-322x215

On/Off Anti-Spark Power Switch

antispark-highvoltage-blue-led-switch

Assembly

위 부품들은 전동 스케이트 보드를 만들기 위해 필요한 부품들이다. RC를 많이 해본 사람이라면 친숙한 부품일 수 있지만, RC에 입문하는 입장에서 처음 접하는 부품들이 많이 있었고 각 부품들을 받았을 때는 어떻게 해야 할지 막막하기도 했었다.

Wheel Adapter 조립

20151023_115720 20151023_115744

Wheel 및 Trucks 조립

20151021_204931

20151021_204910

20151021_204924 20151029_134552

저작자 표시
신고
이 댓글을 비밀 댓글로
    • 정성엽
    • 2017.05.16 00:12 신고
    안녕하세요^^ 정말 멋있어요!! 학교 프로젝트때문에 BLDC모터랑 아두이노랑 연결하려고 하는데 혹시 질문좀 드려도 될까요??
    • 2017.07.17 09:14
    비밀댓글입니다
    • 해당 부품들의 제목을 클릭하시면, 구매 하실 수 있는 사이트로 이동 합니다.
      http://diyelectricskateboard.com/diy-electric-skateboard-kits-parts/electric-skateboard-on-off-power-switch/

How to make Geo-location Watch

Posted by 카이젠8501 카이젠8501
2015.10.08 14:54 IT 개발/DIY 프로젝트

How to make Geo-location watch

System Diagram

본 포스팅에서는 WizFi250과 WIZwiki-W7500을 이용하여 Geolocation Server에 접속해서 현재 내 위치를 알아 확인하고, NTP Server를 통해 시간을 가져오는 예제를 설명한다. 시스템 구성은 아래 그림과 같다.

20150626_171106

Materials

WIZwiki-W7500 ( MCU Platform)

wizwiki-w7500_main

WizFi250-EVB ( Wi-Fi Module )

ShopDtl_1203_20140918154919

Sensor Shield

TB2wSGHaFXXXXcLXXXXXXXXXXXX_!!33841454

SSD1306 OLED

  • Features
    • Resolution: 128 x 64 dot matrix panel
    • Power supply
      • VDD = 1.65V to 3.3V for IC logic
      • VCC = 7V to 15V for Panel driving
    • For matrix display
      • OLED driving output voltage, 15V maximum
      • Segment maximum source current: 100uA
      • Common maximum sink current: 15mA
      • 256 step contrast brightness current control
    • Embedded 128 x 64 bit SRAM display buffer
    • Pin selectable MCU Interfaces:
      • 8-bit 6800/8080-series parallel interface
      • 3 /4 wire Serial Peripheral Interface
      • I2C Interface
    • Screen saving continuous scrolling function in both horizontal and vertical direction
    • RAM write synchronization signal
    • Programmable Frame Rate and Multiplexing Ratio
    • Row Re-mapping and Column Re-mapping
  • On-Chip Oscillator
  • Chip layout for COG & COF
  • Wide range of operating temperature: -40°C to 85°C

Hardware Configuartion

WIZwiki-W7500 Board는 UART0 RX/TX/CTS/RTS 핀들로 WizFi250을 제어하고, I2C SDA/SCL 핀을 이용하여 SSD1306 OLED를 제어 한다.

20150626_204959

WizFi250-EVB Sensor Shield WIZwiki-W7500 SSD1306
RX-TX RXD TXD
TX-RX TXD RXD
CTS-RTS CTS D8
RTS-CTS RTS D7
WizFi250-RESET JP10-2 PA12
I2C SCL SCL PA9 SCL
I2C SDA SDA PA10 SDA
VCC VCC VCC
GND GND

Compile WizFi250 Geolocation_NTP Example

아래 주소에 접속하면 WizFi250 Geolocation_NTP Example를 이용할 수 있으며, Example에서 사용하는 라이브러리들은 아래와 같다.

WizFi250 Geolocation_NTP Example

SSD1306 Library

SSD1306 OLED를 사용하기 위해 Adarfruit GFX Library를 사용하였다. 이 라이브러리를 사용하는 중, Display() 함수에 약간의 버그가 있는 거 같아서 수정 후, 원작자에게 Pull Request를 보낸 상태이다. ( 원작자가 반영 해 줄 지는 모르겠다. )

Adafruit_GFX 수정
Adafruit GFX 원본

HTTP Client

HTTP Client Library는 이름에서도 알 수 있듯이, 외부에 있는 웹 서버에 Request와 Response를 송/수신 하기 위해 사용된다.
본 예제에서는 ip-api.com 서버에 접속해서 Geolocation(지리적 위치 코드)를 얻기 위해 사용되며, ip-api.com/csv 주소로 접속하면 csv 형태로 국가 이름, 주소, 위도(latitude), 경도(longitude), TimeZone 등의 정보를 얻을 수 있다.

아래 주소를 클릭하면 HTTP Client Library를 다운로드 할 수 있다.
HTTP Client

NTP Client

NTP Client Library는 UDP 통신을 이용하여 Network Time Server에서 UTC(협정 세계 시각)을 얻기 위해 사용된다. 본 예제에서는 한국의 NTP Server Domain인 kr.pool.ntp.org를 이용한다. NTP Server로 받은 정보는 UTC(협정 세계 시각)이므로, 9시간을 더해야 한국 시간을 알 수 있다.

NTP Client

Example Source Code

WizFi250-Geolocation_NTP

#include "mbed.h"
#include "Adafruit_SSD1306.h"
#include "WizFi250Interface.h"
#include "NTPClient.h"
#include "HTTPClient.h"


#define SECURE WizFi250::SEC_AUTO
#define SSID "wizohp"
#define PASS "wiznet218"


#if defined(TARGET_WIZwiki_W7500)
    #define SDA                  PA_10
    #define SCL                  PA_9
    WizFi250Interface wizfi250(D1,D0,D7,D8,PA_12,NC,115200);
    Serial pc(USBTX,USBRX);
#endif


// an SPI sub-class that provides a constructed default
class I2CPreInit : public I2C
{
public:
    I2CPreInit(PinName sda, PinName scl) : I2C(sda, scl)
    {
        frequency(100000);
        start();
    };
};

I2CPreInit gI2C(SDA,SCL);
Adafruit_SSD1306_I2c gOled(gI2C,NC,0x78,64,128);
NTPClient ntpClient;
HTTPClient httpClient;
void parse(char buffer[], int *j, char *string); //FUNCTION TO PARSE HTTP GET DATA
char httpGetData[200]; //BUFFER TO HOLD DATA FROM HTTP GET REQUEST


int main()
{
    time_t ctTime; //system time structure
    char success[10]={0};  //success first
    char countryFull[20]={0}; //Full Country Name
    char countryAbrv[5]={0}; //Abbreviated Country Name or country Code
    char stateAbrv[5]={0}; //Abbreviated State or region code
    char stateFull[15]={0}; //Full State Name
    char city[15]={0}; //City Name
    char zip[6]={0}; //ZIP CODE
    char latitude[10]={0}; //latitude
    char longitude[10]={0}; //longitude
    char timeZone[30]={0}; //timeZone
    int j=0, returnCode;

    pc.baud(115200);
    gOled.begin();
    gOled.clearDisplay();

    wizfi250.init();
    returnCode = wizfi250.connect(SECURE, SSID, PASS);

    if ( returnCode == 0 )
    {
        printf(" - WiFi Ready\r\n");
        printf("IP Address is %s\r\n", wizfi250.getIPAddress());
    }
    else
    {
        printf(" - Could not initialize WiFi - ending\r\n");
        return 0;
    }

    //HANDLES THE HTTP GET REQUEST THE WAY THE FUNCTION IS CALLED HERE IS THE FOLLOWING
    // get(DOMAIN_NAME,BUFFER,TIMEOUT_VAL)
    //DOMAIN_NAME= domain name that get request is sent to
    //BUFFER= buffer to store data returned from the server
    //TIMEOUT_VAL= Time before the request times out
    HTTPResult r = httpClient.get("http://ip-api.com/csv",httpGetData,128); //GET GEOLOCATION DATA (CSV)

    if (r==HTTP_OK) { //IF THE DATA WAS RECIEVED
        j=0;
        //parse and display each of the API's location information strings on the LCD
        parse(httpGetData, &j, success); 
        parse(httpGetData,&j,countryFull);
        parse(httpGetData,&j,countryAbrv);
        parse(httpGetData,&j,stateAbrv);
        parse(httpGetData,&j,stateFull);
        parse(httpGetData,&j,city);
        parse(httpGetData,&j,zip);
        parse(httpGetData,&j,latitude);
        parse(httpGetData,&j,longitude);
        parse(httpGetData,&j,timeZone);
        gOled.printf("HTTP Data Received\r\n");
        gOled.display();
    } 
    else { //HTTP GET REQUEST ERRORED
        gOled.printf("HTTP Error %d\r\n", r);
        gOled.display();
        return -1;
    }
    printf("Reading Time...\r\n");
    char* domainName="kr.pool.ntp.org"; //SET TO DOMAIN NAME OF SERVER GETTING TIME FROM
    //GETS THE TIME FROM THE SERVER
    //setTime(DOMAIN_NAME,PORT_NUMBER,TIME_OUT)
    //DOMAIN_NAME= domain name
    //PORT NUMBER=port number (123 for NTP)
    //TIME_OUT= timeout value for request
    ntpClient.setTime(domainName,123,0x00005000);
    printf("Time Set\r\n");
    //Delay for human time to read LCD display
    wait(3.0);

    char buffer[80]; //BUFFER TO HOLD FORMATTED TIME DATA
    gOled.printf("%s, %s %s, %s\r\n",city,stateAbrv,zip,countryAbrv); //PRINT CITY STATE AND ZIP INFORMATION AND COUNTRY
    gOled.printf("LAT:%s\r\nLONG:%s\r\n",latitude,longitude); //PRINT LATITUDE AND LONGITUDE 
    gOled.printf("Timezone:%s\r\n",timeZone); //PRINT TIMEZONE

    wizfi250.disconnect(); //DISCONNECT FROM THE NETWORK 
    while (1) {
        //ctTime = time(NULL)-(3600*4);  //TIME with offset for eastern time US
        ctTime = time(NULL)+(3600*9);  //TIME with offset for eastern time KR
        //FORMAT TIME FOR DISPLAY AND STORE FORMATTED RESULT IN BUFFER
        strftime(buffer,80,"%a %b %d\r\n%T %p %z\r\n %Z\r\n",localtime(&ctTime));
        gOled.printf("Univ Time Clock\r\n%s\r\n", buffer);
        gOled.display();
        gOled.setTextCursor(0,40);
        wait(1);
    }      
}

//SET FOR CSV FORMAT: NEEDS TO BE EDITED IF DIFFERENT FORMAT
void parse(char buffer[], int *j, char *string) {
//extracts next location string data item from buffer
    int i=0;
    for (i=0; i<=strlen(buffer); i++) {  //TOTAL SIZE OF RETURNED DATA
        if ((buffer[*j+i] == ',')||(buffer[*j+i] == '\0' )) { //IF comma or end of string
            //comma is the string field delimiter
            string[i]=0; //SETS END OF SRTRING TO 0
            *j=*j+i+1; //UPDATES to 1 after comma seperated value
            break;
        } else string[i]=buffer[*j+i]; //Keep adding to the string
    }
}

Demo Video


저작자 표시
신고
이 댓글을 비밀 댓글로

How to make Wi-Fi oil checker using Axeda

Posted by 카이젠8501 카이젠8501
2015.10.08 14:50 IT 개발/DIY 프로젝트

How to make WiFi oil check using Axeda cloud

Axeda

Axeda는 세계 각지의 기계와 센서 데이터를 수집하고 체계화하기 위한 IoT 솔루션을 제공하는 기업이다. 150개 이상의 고객사를 향해 매일 수억 개의 규모의 데이터를 처리하고 있으며, 크게 3가지 서비스를 제공하고 있다.

  1. ‘Axeda Machine Cloud Service’는 기기간 통신(M2M) 및 IoT 연결 서비스 소프트웨어 에이전트 툴킷으로 구성되어 있으며, 기업의 제품과 클라우드 보안 연결을 거의 모든 통신 방법(이동통신 네트워크, 인터넷, 무선 LAN, 위선통신 등)에서 제공한다.
  2. ‘Axeda Connected Content Application’은 대량의 연결된 제품에 콘텐츠 전송을 안전하고 확실하고 효율적으로 실현하고 소프트웨어 업데이트 및 보안 패치의 원격 설치를 자동화 한다.
  3. ‘Axeda Connected Service Application’은 PTC의 서비스 라이프 사이클 관리(SLM) 솔루션을 보완하고 Axeda 플랫폼에 연결된 장치의 문제를 원격으로 확인, 진단, 수리하는 다양한 툴과 Web 기반의 그래픽 인터페이스를 현장 서비스 및 기술 지원 부서에 제공한다.

참고 PTC, 액세다(Axeda) 인수 완료…사물인터넷 사업 강화

Go to the staging page on your Axeda Toolbox account

toolbox.axeda.com에 회원 가입 후, 아래 그림과 깉이 AXEDA READY 아이콘을 선택하고 mbed LPC1768 Device를 선택한다.

toolbox_landing_page mbedselect

본 포스팅 예제에서는 WIZwiki-W7500 Board를 사용하지만, 아직 Axeda에는 WizWik-W7500 Board가 없는 관계로 LPC1768의 ToolBox를 사용한다.

원하는 Device Name을 입력하고 Go 버튼을 누르면 아래 그림과 같은 화면을 볼수 있다.
Serial Number는 Axeda Example Code를 수행 할 때 필요하므로 메모장 같은 곳에 복사 해두길 바란다.

yourdevicepage

Materials

아래 하드웨어에 대한 자세한 내용은 아래 링크를 참고 하기 바란다.
Link

WIZwiki-W7500 ( MCU Platform)

wizwiki-w7500_main

WizFi250-EVB ( Wi-Fi Module )

ShopDtl_1203_20140918154919

Sensor Shield

TB2wSGHaFXXXXcLXXXXXXXXXXXX_!!33841454

Hardware Configuartion

20150626_151253

WizFi250-EVB Sensor Shield WIZwiki-W7500
RX-TX RXD TXD
TX-RX TXD RXD
CTS-RTS CTS D8
RTS-CTS RTS D7
WizFi250-RESET JP10-2 PA12

Compile AxedaGo-WizFi250 Example onto Wizwiki-W7500 Board

아래 주소에 접속하면 WizFi250 Axeda Example Code를 이용 할 수 있다.
Link for AxedaGo-WizFi250 Example

20150626_151744

AxedaGo-WizFi250 Example을 컴파일 하기 전, Axeda Tool box 에서 얻은 Serial Number를 아래 코드에 추가한다.

line19serial

코드를 컴파일 한 후, 생성된 바이너리를 WIZwiki-W7500 Board에 Upload 한다.

Source Code

#include <stdio.h>
#include "mbed.h"
#include "WizFi250Interface.h"

#define SECURE WizFi250::SEC_AUTO
#define SSID "ssid"
#define PASS "key"


#if defined(TARGET_WIZwiki_W7500)
    WizFi250Interface wizfi250(D1,D0,D7,D8,PA_12,NC,115200);
    Serial pc(USBTX,USBRX);
#endif

AnalogIn pot1(A0);
TCPSocketConnection sock;

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

int main() 
{
    char *MODEL = "mbed";
    char *SERIAL_NUM = "serial number"; 
    float DEADBAND = 0.03;

    int http_cmd_sz=800;
    char http_cmd[http_cmd_sz];
    int buffer_sz=300;  
    char buffer[buffer_sz];  
    int returnCode = 0;

    led1 = 1;
    led2 = 1;
    led3 = 1;
    led4 = 1;

    pc.baud(115200);

    wizfi250.init();
    returnCode = wizfi250.connect(SECURE, SSID, PASS);

    if ( returnCode == 0 )
    {
        printf(" - WiFi Ready\r\n");
        printf("IP Address is %s\r\n", wizfi250.getIPAddress());
        led1 = returnCode;
    }
    else
    {
        printf(" - Could not initialize WiFi - ending\r\n");
        return 0;
    }

    float oil_level = 0.0;
    float oldPotVal = -2.0;

    while(1) {
        oil_level = pot1.read();

        if ( abs(oil_level - oldPotVal) < DEADBAND)
        {
            continue;   
        }
        else
        {
            oldPotVal = oil_level;
            printf("Sending Value for well1 %.2f\n\r", oil_level);
            sock.connect("toolbox-connect.axeda.com", 80);

            snprintf(http_cmd, http_cmd_sz,  "POST /ammp/data/1/%s!%s HTTP/1.1\r\nContent-Type: application/json\r\nContent-Length: 65\r\n\r\n{\"data\":[{\"di\":{\"oil_level\":%.2f}}]}\r\n\r\n", MODEL, SERIAL_NUM, oil_level);
            sock.send_all(http_cmd, http_cmd_sz-1);

            while ( (returnCode = sock.receive(buffer, buffer_sz-1)) > 0)
            {
                buffer[returnCode] = '\0';
                printf("Received %d chars from server:\n\r%s\n", returnCode, buffer);
            }

            sock.close();
        }
     }
}

Test Result

Send data to the demo application

위 코드를 수행하면, WIZwiki-W7500은 WizFi250을 이용하여 Axeda Tool box에 센싱된 데이터를 송신한다. Axeda Tool box는 Device가 송신한 데이터를 가지고 아래 그림과 같이 Mbed Widget을 만들어 준다. Sensor Shield의 A0의 Switch를 돌리면 Axeda의 mbed Widget도 변하는 것을 확인 할 수 있다.

20150626_16013820150626_154710

Log message on Serial Terminal

[WizFi250: INFO]AT+MMAC=?
[WizFi250: INFO][OK]

[WizFi250: INFO]AT+WSET=0,wizohp
[WizFi250: INFO][OK]

[WizFi250: INFO]AT+WSEC=0,,wiznet218
[WizFi250: INFO][OK]

[WizFi250: INFO]AT+WJOIN
[WizFi250: INFO][OK]

[WizFi250: INFO]AT+WSTATUS
[WizFi250: INFO][OK]

[WizFi250: INFO]IP      : 192.168.13.29
[WizFi250: INFO]Gateway : 192.168.13.1
[WizFi250: INFO]WizFi250 is successfully join to AP
 - WiFi Ready
IP Address is 192.168.13.29
Sending Value for well1 0.54
[WizFi250: INFO]AT+FDNS=toolbox-connect.axeda.com,1000
[WizFi250: INFO][OK]

[WizFi250: DBG]216.34.120.52
[WizFi250: INFO]AT+SCON=O,TCN,216.34.120.52,80,,0
[WizFi250: INFO][OK]

[WizFi250: INFO]AT+SSEND=0,,,799
[WizFi250: INFO][OK]

[WizFi250: INFO]POST /ammp/data/1/mbed!nlr__kaizen8501_gmail_com___6245114 HTTP/1.1
Content-Type: application/json
Content-Length: 65

{"data":[{"di":{"oil_level":0.54}}]}



[WizFi250: DBG]receive readable : 1

Received 36 chars from server:
HTTP/1.1 200 
Content-Length: 0

Demo Video


저작자 표시
신고
이 댓글을 비밀 댓글로

Remote Temperature/Humidity Checker using TTS

Posted by 카이젠8501 카이젠8501
2015.10.08 14:44 IT 개발/DIY 프로젝트

Remote Temperature/Humidity Checker & LED controller

앞에서 설명한 mbed RPC Library와 Python Interface를 활용한 예제를 만들어 보려고 하다 보니 제목이 거창해 진거 같다.

간단하게 말하자면, 본 예제는 아래와 같은 기능을 수행한다.

  • mbed platform의 3색 LED 제어 ( On/Off )
  • mbed platform의 현재 LED 상태 확인 ( Smartphone의 TTS 기능을 이용하여 Green,Blue,Red 인지 상태 확인 기능 )
  • mbed platform으로 부터 온도, 습도 정보를 확인 ( Smartphone의 TTS 기능을 이용하여 온/습도 정보를 확인 가능)

본 예제에서는 mbed RPC를 이용하여 스마트폰에서 mbed platform을 제어하고 있으며, 스마트폰의 Application은 python 기반의 kivy 라이브러리를 사용하였다.

20150727_132817

mbed HTTP RPC Server

본 장에서는 위에서 설명한 동작을 수행하기 위한 mbed code를 구현하는 방법에 대해 설명한다. 아래 코드는 mbed rpc와 HTTP Server 등을 구동하기 위한 코드이며, 사용된 라이브러리는 아래와 같다. mbed platform에 아래 코드를 컴파일해서 Upload 하면, 외부에서 HTTP Data를 이용하여 mbed platform을 제어 할 수 있다.

  • DHT : 온/습도 센서를 제어 하기 위한 라이브러리
  • HTTPServer : HTTP Server를 위한 라이브러리
  • mbed-rpc : mbed RPC를 위한 라이브러리
  • WIZnetInterface : 별도의 Software stack 없이 Ethernet을 사용하기 위한 라이브러리

Example Code는 아래 경로에서 다운로드 할 수 있다.
RPC_HTTP_WIZnetInterface

#include "mbed.h"
#include "EthernetInterface.h"
#include "HTTPServer.h"
#include "mbed_rpc.h"
#include "DHT.h"

RpcDigitalOut led1(D9,"led1");
RpcDigitalOut led2(D10,"led2");
RpcDigitalOut led3(D11,"led3");

//RPCVarialbe<float> RPCTemperature(&GetTemperature, "Temperature");
//RPCVarialbe<float> RPCHumidity(&GetHumidity, "Humidity");
void Get_Temp_and_Humidity(Arguments * input, Reply * output);

RPCFunction Temp_and_Humidity_Finder(&Get_Temp_and_Humidity, "Temp_and_Humidity_Finder");

EthernetInterface eth;  
HTTPServer svr;

DHT sensor(D4, DHT11);

void Get_Temp_and_Humidity(Arguments * input, Reply *output){
    int error = 0;
    float h = 0.0f, c = 0.0f;
    char arg[100];

    error = sensor.readData();
    if (0 == error) {
        c   = sensor.ReadTemperature(CELCIUS);
        h   = sensor.ReadHumidity();
        sprintf(arg,"Temperature in Celcius: %4.2f, Humidity is %4.2f",c, h);

        output->putData(arg);
    }
}

int main() {
  //Turn the LEDs off
  uint8_t mac_addr[6] = {0x00, 0x08, 0xDC, 0x32, 0x23, 0x42}; 
  led1.write(0);
  led2.write(0);
  led3.write(0);

  RPC::add_rpc_class<RpcDigitalOut>();

  printf("Setting up...\n");
  eth.init(mac_addr);
  int ethErr = eth.connect();
  if(ethErr < 0)
  {
    printf("Error %d in setup.\n", ethErr);
    return -1;
  }
  svr.addHandler<HTTPRpcRequestHandler>("/rpc");

  //attach server to port 80
  printf("Listening...\n");
  svr.start(80, &eth);

  Timer tm;
  tm.start();
  //Listen indefinitely
  while(true)
  {
    svr.poll();
    if(tm.read()>.5)
    {
      tm.start();
    }
  }
}
  • 7~8 : 3색 LED를 위한 GPIO를 RPC에 등록
  • 15 : 온/습도를 얻어 오기 위한 Custom 함수를 RPC에 등록
  • 22~35 : Custom 함수의 구현 부
    • mbed RPC client로 부터 요청이 들어오면 온/습도를 추출한 후, Temperature in Celcius : … “ 데이터를 RPC client에게 송신 한다.
  • 54 : HTTPRPC Request 등록

Smartphone Simple Application

본 장에서는 Smartphone에서 mbed device를 제어하기 위한 간단한 Application을 만드는 방법을 설명한다. 본 예제는 python으로 구현 하였으며, UI를 위해 kivy 라이브러리를 사용하였다. 본 예제를 구현 및 구동하기 위해서는 아래와 같은 절차를 수행 해야 한다.

Download Qpython

Android 폰에서 python을 구동하기 위해서는 Qpython 이라는 프로그램이 필요 하며, 다운로드 경로는 아래와 같다.
QPython Download

20150727_140513

앞에서 설명한 것과 같이 python으로 UI를 만들기 위해서는 kivy 라이브러리가 필요하며, 스마트폰의 TTS(Text to Speach) 기능을 사용하기 위해서는 AndroidHelper 라이브러리가 있어야 한다. 각각의 라이브러리는 아래 그림과 같은 절차를 수행하면 설치 할 수 있다.

20150727_140920 20150727_141000 20150727_141026

20150727_141051 20150727_141110 20150727_141151 20150727_141247

Edit Source Code

스마트폰 앱으로 소스코드를 작성하는 일은 매우 불편하다. 다행히도 QPython은 미리 작성한 코드를 FTP로 핸드폰에 저장하는 기능을 지원하고 있다.
나는 이 기능을 이용해서 PC에서 미리 구현해 놓은 프로그램을 스마트폰에 복사 한 후 실행하는 절차로 코드를 구현 및 디버깅 했다. ( 이 또한 매우 불편 하였다. )

Setting for FTP

아래 그림과 같은 절차를 수행하면 Qpython의 FTP 기능을 사용 할 수 있다.

20150727_143112 20150727_143133 20150727_143156

Upload Source Code to Smartphone

아래 그림들은 PC에서 QPython의 FTP Server에 접속해서 미리 작성한 코드를 업로드 하는 방법을 나타낸다.

20150727_143344

FTP 접속에 성공하면 아래와 같이 Qpython의 폴더 트리를 볼 수 있다. 폴더 트리에 나오는 폴더를 하나 선택하여 미리 작성한 코드를 업로드 하면 된다.

20150727_143413

나는 project3/RPC_TTS 폴더를 만들고 kivy.py와 mbedRPC.py를 복사 해서 사용한다.
mbedRPC.py는 앞에서 설명한 mbed python RPC library이며, kivy.py는 Application의 UI 및 동작을 구현한 파일이다.

20150727_143443

Source code of kivy.py

#-*-coding:utf8;-*-
#qpy:2
#qpy:kivy

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from mbedRPC import *
import androidhelper

class CommandScreen(GridLayout):
    def __init__(self, **kwargs):
        super(CommandScreen, self).__init__(**kwargs)
        self.cols = 2
        self.row = 2
        self.row_force_default=True
        self.row_default_height=200

        self.add_widget(Label(text='Device IP'))
        self.m_text_device_ip = TextInput(multiline=False,text="192.168.18.121")
        self.add_widget(self.m_text_device_ip)

        self.m_button_init = Button(text="Init")
        self.m_button_init.bind(on_press=self.mbedInit)
        self.add_widget(self.m_button_init)

        self.m_button_GetTemp = Button(text="Get Temp")
        self.m_button_GetTemp.bind(on_press=self.GetTemp)
        self.add_widget(self.m_button_GetTemp)

        self.btn_onLed1 = Button(text="Turn On",background_color=(1,0,0,1))
        self.btn_onLed1.bind(on_press=self.TurnOnLed1)
        self.add_widget(self.btn_onLed1)

        self.btn_offLed1 = Button(text="Turn Off",background_color=(1,0,0,1))
        self.btn_offLed1.bind(on_press=self.TurnOffLed1)
        self.add_widget(self.btn_offLed1)

        self.btn_onLed2 = Button(text="Turn On",background_color=(0,1,0,1))
        self.btn_onLed2.bind(on_press=self.TurnOnLed2)
        self.add_widget(self.btn_onLed2)

        self.btn_offLed2 = Button(text="Turn Off",background_color=(0,1,0,1))
        self.btn_offLed2.bind(on_press=self.TurnOffLed2)
        self.add_widget(self.btn_offLed2)

        self.btn_onLed3 = Button(text="Turn On",background_color=(0,0,1,1))
        self.btn_onLed3.bind(on_press=self.TurnOnLed3)
        self.add_widget(self.btn_onLed3)

        self.btn_offLed3 = Button(text="Turn Off",background_color=(0,0,1,1))
        self.btn_offLed3.bind(on_press=self.TurnOffLed3)
        self.add_widget(self.btn_offLed3)

        self.btn_getLedStatus = Button(text="LED Status")
        self.btn_getLedStatus.bind(on_press=self.GetLedStatus)
        self.add_widget(self.btn_getLedStatus)

        self.btn_getA0Status = Button(text="Get A0 Status")
        self.btn_getA0Status.bind(on_press=self.GetA0Status)
        self.add_widget(self.btn_getA0Status)


    def mbedInit(self,event):
        self.droid = androidhelper.Android()

        self.mbed = HTTPRPC(self.m_text_device_ip.text)
        self.led1 = DigitalOut(self.mbed,"led1")
        self.led2 = DigitalOut(self.mbed,"led2")
        self.led3 = DigitalOut(self.mbed,"led3")
        self.temp_humidity = RPCFunction(self.mbed,"Temp_and_Humidity_Finder")

        box = BoxLayout(orientation='vertical')
        box.add_widget(Label(text='Init Complete'))
        button_close = Button(text='Close me!')
        box.add_widget(button_close)

        popup = Popup(title='message', content=box,
                      size_hint=(None,None),size=(400,400), auto_dismiss=False)

        button_close.bind(on_press=popup.dismiss)
        popup.open()


    def GetTemp(self,event):
        resp = self.temp_humidity.run("")
        self.droid.ttsSpeak(resp)

    def TurnOnLed1(self,event):
        self.led1.write(1)

    def TurnOffLed1(self,event):
        self.led1.write(0)

    def TurnOnLed2(self,event):
        self.led2.write(1)

    def TurnOffLed2(self,event):
        self.led2.write(0)

    def TurnOnLed3(self,event):
        self.led3.write(1)

    def TurnOffLed3(self,event):
        self.led3.write(0)

    def GetLedStatus(self,event):
        if( self.led1.read()[0] == '1' ): self.droid.ttsSpeak("Turn on red.")
        if( self.led2.read()[0] == '1' ): self.droid.ttsSpeak("Turn on green.")
        if( self.led3.read()[0] == '1' ): self.droid.ttsSpeak("Turn on blue.")

    def GetA0Status(self,event):
        print ''

class MyApp(App):
    def build(self):
        return CommandScreen()        

if __name__ == '__main__':
    MyApp().run()
  • 15 ~ 65 : App Button 및 UI 초기화
  • 68 ~ 86 : mbed RPC library 초기화
  • 89 : mbed platform으로 부터 온/습도 데이터를 수신 후 TTS로 출력
  • 93 ~ 109 : LED1/2/3 On/Off
  • 111 ~ 114 : 현재 mbed platform의 LED 색깔을 확인 후 TTS로 출력

Result after run

20150727_130822

Demo Video

저작자 표시
신고
이 댓글을 비밀 댓글로

DIY 캐논 카메라 리모컨 및 수신기 만들기

Posted by 카이젠8501 카이젠8501
2014.11.26 19:08 IT 개발/DIY 프로젝트

DIY 캐논 카메라 리모컨 및 수신기 만들기

본 포스팅에서는 원격에서 캐논 카메라를 제어하기 위한 리모컨과 수신기를 만드는 방법을 설명한다.
리모컨은 Focus와 Shutter 기능을 지원하며 수신기와 스마트폰은는 Wi-Fi 통신을 사용한다.

시스템 구성

본 프로젝트의 구성 요소는 아래와 같다.

  • Camera

    • Receiver와 2.5pi Audio Cable을 이용하여 연결
  • Receiver

    • Arduino Uno(MCU) + WizFi250 (Wi-Fi Module)
    • WizFi250의 AP 기능을 사용 ( 별도의 유/무선 공유기 없이 스마트폰과 다이렉트로 연결 )
  • Remote Controller

    • Smart Phone ( LG G2 )
    • Simple Android App 구현

Camera + Receiver H/W 구성

캐논 카메라를 제어 할 수 있는 방법은 두가지가 있다.

  1. 2.5파이 오디오 잭을 이용하는 방법
  2. USB를 이용하는 방법

2번 방법은 캐논 카메라의 SD Card에 있는 사진을 불러 온다거나 설정 값들을 변경 할 수 있는 다양한 기능을 제어 할 수 있다.
하지만 내가 필요한 기능은 사진을 찍는 간단한 동작만 되면 되기 때문에 1번 방법을 사용하여 구현 하였다.

1번 방법은 아래 그림과 같이 오디오 잭의 모서리 금속과 마지막 금속을 접지 시키면 캐논 카메라의 Shutter가 눌려지는 동작을 하는 원리 이다.
또한 두번째 금속과 마지막 금속을 접지 하면 캐논 카메라가 포커스를 잡는다.

오디오 잭의 피복을 벗기면 빨강, 흰색, 금색 선을 볼 수 있다. ( 이 부분은 오디오 잭에 따라 다를 수 있으니 테스터기를 가지고 어느 선과 연결되어 있는지 확인 하는 것을 추천 한다.)

본 프로젝트에 사용된 오디오 잭은 빨간 석은 Shutter, 흰색 선은 Focus로 사용 할 수 있으며, 각각 Arduino Board의 D7번과 D6번에 연결 하였다.
아래는 Arduino Board와 WizFi250-EVB를 결합한 보드에 오디오 잭을 연결한 사진이다.

위와 같은 구성을 마치고 오디오 잭을 캐논 카메라에 연결하면 Camera와 Receiver의 H/W 구성은 끝이다.
(아래 사진과 같이 표시된 부분에 오디오 잭을 연결)

Receiver S/W 구성

본 프로젝트에서는 WizFi250의 AP 기능을 사용하려고 한다. WizFi250은 일반적인 유/무선 공유기에 접속하여 통신하는 Station 모드 이외에 AP 기능을 지원한다. WizFi250이 지원하는 AP 기능은 제한적이기 하지만 Device 2~3대 정도가 통신하기에는 적합하다.

아래는 Recevier S/W 구현으로 설정한 네트워크 환경을 나타내는 그림이다.

구현한 Arduino Code는 아래와 같다. 스마트폰과의 통신은 TCP를 이용하였고 프로토콜은 보는 것과 같이 아주 간단하다.
스마트폰으로 부터 ‘S’를 받으면 사진을 찍고 ‘F’를 받으면 Focus를 잡는다.

#include <Arduino.h>
#include <SPI.h>
#include <IPAddress.h>
#include "WizFi250.h"
#include "WizFi250_tcp_server.h"


#define SSID    "600D_AP"
#define KEY        "123456789"
#define AUTH    "WPA2"

#define FOCUS        6
#define SHUTTER        7
#define REMOTE_PORT    5000
#define LOCAL_PORT    5000

WizFi250    wizfi250;
IPAddress    ip(192,168,12,1);
IPAddress    subnet(255,255,255,0);
IPAddress    gateway(192,168,12,1);

void pinSetup();
void PushFocus();
void ReleaseFocus();
void PushShutter();
void ReleaseShutter();

boolean Wifi_setup = false;
WizFi250_TCP_Server myServer(LOCAL_PORT);

String str;

void setup()
{
    Serial.begin(9600);
    Serial.println("\r\nSerial Init");

    wizfi250.init();
    wizfi250.setDebugPrint(4);
    wizfi250.hw_reset();
    pinSetup();

    wizfi250.sync();

    wizfi250.setDhcp(ip,subnet,gateway);

    if( wizfi250.begin(SSID,KEY,AUTH,1) == RET_OK )
    {
        Wifi_setup = true;
    }

}

void loop()
{
    char cmd;

    if( Wifi_setup )
    {
        wizfi250.RcvPacket();

        if( myServer.isListen() != true )
        {
            myServer.listen();
        }

        if( myServer.available() )
        {
            cmd = myServer.recv();

            if( cmd == (uint8_t)'S')
            {
                ReleaseFocus();
                PushShutter();
                delay(500);
                ReleaseShutter();
            }
            else if( cmd == (uint8_t) 'F')
            {
                ReleaseShutter();
                PushFocus();
            }
            cmd = NULL;
        }
    }
}

void pinSetup()
{
    pinMode(FOCUS, OUTPUT);
    pinMode(SHUTTER, OUTPUT);

    digitalWrite(FOCUS, HIGH);
    digitalWrite(SHUTTER, HIGH);
}

void PushFocus()
{
    digitalWrite(FOCUS, LOW);
}

void ReleaseFocus()
{
    digitalWrite(FOCUS, HIGH);
}

void PushShutter()
{
    digitalWrite(SHUTTER, LOW);

}

void ReleaseShutter()
{
    digitalWrite(SHUTTER, HIGH);
}

스마트폰 S/W

스마트 폰 역시 Shutter 버튼과 Focus 버튼만 있는 아주 간단한 형태로 구현하였으며, 아래는  소스 코드 이다.

package com.example.canonremotecontrol;

import android.support.v7.app.ActionBarActivity;
import android.os.*;
import android.util.Log;
import android.view.*;
import android.widget.*;

import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.*;


public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnFocus = (Button)findViewById(R.id.focus_btn);
        btnFocus.setOnClickListener(new Button.OnClickListener(){
            public void onClick(View v){

                ConnectThread thread = new ConnectThread("192.168.12.1");
                thread.SetAction("F");
                thread.start();
            }
         });

        Button btnTake = (Button)findViewById(R.id.shutter_btn);
        btnTake.setOnClickListener(new Button.OnClickListener(){
            public void onClick(View v){
                ConnectThread thread = new ConnectThread("192.168.12.1");
                thread.SetAction("S");
                thread.start();
            }
        });
    }


    class ConnectThread extends Thread{
        String hostname;
        String m_action;

        public ConnectThread(String addr){
            hostname = addr;
        }

        public void SetAction(String action){
            m_action = action;
        }

        public void run(){
            try{
                int port = 5000;

                Socket sock = new Socket(hostname, port);
                OutputStream out = sock.getOutputStream();
                out.write(m_action.getBytes());
                out.flush();
                sock.close();
            } catch(Exception ex){
                ex.printStackTrace();
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
} 








저작자 표시
신고
이 댓글을 비밀 댓글로
    • Dude
    • 2017.06.30 14:56 신고
    선풍기를 핸드폰으로 조작되게 만들려고 찾아봤는데
    이런 좋은 글이.. 참고하겠습니다