April 26, 2024

디바이스마트 미디어:

[66호] 원하는 색상으로 제어가 가능한 아두이노 IoT 스마트 무드등 키트 -

2021-06-25

★2021 ICT 융합 프로젝트 공모전 결과 발표! -

2021-05-12

디바이스마트 국내 온라인 유통사 유일 벨로다인 라이다 공급! -

2021-02-16

★총 상금 500만원 /2021 ICT 융합 프로젝트 공모전★ -

2021-01-18

디바이스마트 온라인 매거진 전자책(PDF)이 무료! -

2020-09-29

[61호]음성으로 제어하는 간접등 만들기 -

2020-08-26

디바이스마트 자체제작 코딩키트 ‘코딩 도담도담’ 출시 -

2020-08-10

GGM AC모터 대량등록! -

2020-07-10

[60호]초소형 레이더 MDR, 어떻게 제어하고 활용하나 -

2020-06-30

[60호]NANO 33 IoT보드를 활용한 블루투스 수평계 만들기 -

2020-06-30

라즈베리파이3가 드디어 출시!!! (Now Raspberry Pi 3 is Coming!!) -

2016-02-29

MoonWalker Actuator 판매개시!! -

2015-08-27

디바이스마트 레이저가공, 밀링, 선반, 라우터 등 커스텀서비스 견적요청 방법 설명동영상 입니다. -

2015-06-09

디바이스마트와 인텔®이 함께하는 IoT 경진대회! -

2015-05-19

드디어 adafruit도 디바이스마트에서 쉽고 저렴하게 !! -

2015-03-25

[29호] Intel Edison Review -

2015-03-10

Pololu 공식 Distributor 디바이스마트, Pololu 상품 판매 개시!! -

2015-03-09

[칩센]블루투스 전 제품 10%가격할인!! -

2015-02-02

[Arduino]Uno(R3) 구입시 37종 센서키트 할인이벤트!! -

2015-02-02

[M.A.I]Ahram_ISP_V1.5 60개 한정수량 할인이벤트!! -

2015-02-02

[66호]물체탐지 4족 보행로봇

66 ICT_보행로봇 (1)

2020 ICT 융합 프로젝트 공모전 장려상

물체탐지 4족 보행로봇

글 | 선문대학교 곽호권

 

1. 심사평
칩센 개인적으로 더 좋은 하드웨어 적용과 더 많은 시간을 들이면 훨씬 개선된 움직임이 보여질 거라는 생각이 드는데, 작품이 개발자의 초기 기대치가 어느 정도인지가 궁금합니다. 로봇을 통해 사람이 하기에 어렵거나 위험한 일을 대신하게 하는 것은 앞으로도 계속 추구 되어야할 중요한 기술 개발 분야라고 생각됩니다. 공모전을 통해 이번에 시작을 한거라고 보면, 추가로 충분히 개선이 가능할만한 작품으로 보여 기대가 됩니다.
펌테크 아이디어와 실용성을 갖춘 작품이라고 생각이 듭니다. 단 제출된 보고서 내용을 고려하자면 작품에 대한 기획 의도는 우수하다고 생각되지만 계획에 대비해서 출품작의 일부 진행 과정은 확인이 되나 최종적인 완성도를 구체적으로 확인할 수가 없었습니다.
위드로봇 게이트 제어 및 영상 스트리밍 등 높은 난이도 기술을 구현한 작품입니다.

2. 작품개요
2.1. 선정동기
뉴스에서 자연재해로 인한 인명구조를 하기 위해 위험을 무릅쓰고 탐사하는 모습을 보고 물체 탐지 4족 보행로봇을 통해 인명구조를 하면 좋을 것 같다는 생각에 선정하게 되었습니다.
사람이 들어갈 수 없는 덕트 안에 어떠한 물체가 걸리는 현상이 발생하여 한 개의 라인 자체를 중단시키고 위험하게 물체를 꺼내는 모습을 보고 로봇을 통해 그 문제를 해결하면 좋을 것 같다는 영감을 얻어 선정하게 되었습니다.

2.2. 목적

66 ICT_보행로봇 (1)

· 재해로 접근하기 어려운 지역이나 좁은 지역에서 사용할 수 있는 로봇입니다.
· 좁고 어두운 하수관 같은 곳에 사용할 수 있는 자동화 로봇입니다.
· 물체 탐지 4족 보행로봇을 통해 효율적으로 일을 처리할 수 있게 하기 위함입니다.

2.3. 필요성
· 여러 인력을 동원해서 해야 하는 번거로운 일을 혼자서 핸드폰으로 할 수 있으므로 불필요한 인력이 감소됩니다.
· 공장에서 사용시 라인이 중단되는 현상을 막아 시간과 비용이 절감됩니다.
· 사람이 접근하기 위험한 곳에 로봇이 직접 탐사를 진행하기 때문에 안전하고 위험 부담이 감소합니다.

3. 작품 설명
3.1. 주요 동작 및 특징
· 4족 보행로봇 보행
· 적외선 센서 감지 및 DATA 출력
· Application 스트리밍
· Application 조작

3.2. 전체 시스템 구성

66 ICT_보행로봇 (2)
Application을 통한 4족 보행로봇 제어 및 실시간 영상 스트리밍, 센서 DATA값 확인합니다.

3.3. 개발 환경(개발 언어, Tool, 사용 시스템 등)
· CodeVision AVR
· Visual Studio 2017 (C++)
· PADS Logic
· PADS Layout
· Autodesk Inventor
· Simplify 3D Printing with Ultimaker Cura 4.0
· RasberryPi Python
· Android studio

4. 단계별 제작 과정
4.1. 모터 제어 시스템 개발 (CodeVision AVR Tool 사용)

66 ICT_보행로봇 (3)

66 ICT_보행로봇 (2)

4.1.1. 모터 제어 실험 준비
1. PCB Bread Board에 Pinheader를 사용하여 ATmega128를 부착할 수 있도록 설계합니다.

66 ICT_보행로봇 (3)

2. 서보모터를 제어하기 위해 PortA(0~7) 와 PortC(0~3)까지 12개의 포트를 와이어링합니다.

66 ICT_보행로봇 (4)

66 ICT_보행로봇 (5)

66 ICT_보행로봇 (6)

66 ICT_보행로봇 (7)

4.1.2. 모터 제어 실험
1. 서보모터인 SG90과 MG90s에 PWM신호를 입력하여 원하는 각도로 제어할 수 있도록 변하는 값을 각도는 각도기로 PWM신호는 오실로스코프로 확인합니다.

66 ICT_보행로봇 (8)

2. 1400usec만큼 PWM신호를 입력하였을 때 서보모터가 90도만큼 회전합니다.

66 ICT_보행로봇 (9)

4.2. 4족 보행로봇 3D Modeling 및 3D Print (Inventor Tool 사용)
※ Inventor를 이용한 4족 보행 로봇 부품 설계

66 ICT_보행로봇 (4)

 

4.3. 4족 보행로봇 걸음걸이 연구 (AVR과 MFC 시리얼 통신)

4.3.1. 걸음걸이 알고리즘 연구

66 ICT_보행로봇 (10)

4.3.2. Creep Gait (크립 걸음걸이)
1. 크립 걸음 걸이는 사용하기 가장 쉬운 걸음 걸이입니다. 로봇은 지상에서 3피트를 유지하고 그 3피트가 형성하는 삼각형 안에 무게중심(CoG)을 유지합니다. CoG가 너무 오랫동안 삼각형을 벗어나면 넘어질 것입니다.

66 ICT_보행로봇 (11)

문제점 : 걷는 동안 안정성을 유지하는 방법
1. 이것은 시작 위치이며 한쪽은 두 개의 다리가 밖으로 나오고 다른 두 개의 다리는 안쪽으로 당겨집니다.
2. 오른쪽 상단 다리가 로봇의 앞쪽으로 들어 올려 밖으로 나옵니다.
3. 모든 다리가 뒤로 움직여 몸을 앞으로 움직입니다.
4. 뒷좌석 다리가 몸체와 함께 앞으로 들어 올려집니다. 이 위치는 시작 위치의 대칭 이미지입니다.
5. 왼쪽 상단 다리가 로봇 앞쪽으로 들어 올려 밖으로 나옵니다.
6. 다시 모든 다리가 뒤로 움직여 몸이 앞으로 움직입니다.
7. 뒤 우측 다리가 들어 올려 신체로 다시 들어가서 우리를 시작 위치로 되돌립니다. 모든 시간에 다리의 바닥에 형성된 삼각형에는 무게중심(CoG)이 포함됩니다. 이것은 크립 걸음 걸이의 본질입니다. 이 패턴을 보면, 그것이 본질적으로 두 세트의 미러 된 움직임 임을 알 수 있습니다. 단계, 단계 및 교대, 다른 단계, 단계 및 교대가 뒤 따릅니다.

66 ICT_보행로봇 (12) 66 ICT_보행로봇 (13) 66 ICT_보행로봇 (14)

4.4. 전자회로기판 설계
PADS Logic Tool, PADS Layout Tool 사용

66 ICT_보행로봇 (5)

4.5. 라즈베리파이와 적외선 센서 연동 (Python 사용)

66 ICT_보행로봇 (15)

· 이름 : mini PIR motion sensor
· 크기 : 20mm*20mm*12mm
· 감지거리 : 2m(25°C)
· 감지방법 : 적외선 온열 신체 감지
· 공급전압 : 2.7~3.3V

66 ICT_보행로봇 (16)

· 이름 : analog sensor
· 크기 : 25*10mm
· 감지거리 : 5~15mm
· 감지방법 : 적외선 반사 감지
· 전압 : 5V
· 출력 : 아날로그 전압

66 ICT_보행로봇 (17)

66 ICT_보행로봇 (18) 66 ICT_보행로봇 (19)

4.6. 라즈베리파이와 적외선 카메라 연동 (Python 사용)
4.6.1. 라즈베리 파이 설정

66 ICT_보행로봇 (20)

4.6.2. 인터페이스 옵션 설정(카메라활성화)

66 ICT_보행로봇 (21)

4.6.3. mjpg streamer 패키지 설치

66 ICT_보행로봇 (22)

4.6.4. 편집기를 이용한 옵션사용

66 ICT_보행로봇 (23)

- i뒤에 내용은 파이카메라 옵션
- o뒤에 내용은 스트리밍 출력옵션

4.6.5. 옵션변경

66 ICT_보행로봇 (24)

4.7. 동영상 스트리밍 서버 구현

4.7.1. 라즈베리파이 ip주소 찾기

66 ICT_보행로봇 (25)

4.7.2. 서버접속 후 스트리밍 확인

66 ICT_보행로봇 (26)

4.8. Application 개발 (Android Studio 사용)

66 ICT_보행로봇 (6) 66 ICT_보행로봇 (27)

4.8.1. 버튼 세 개(실시간 영상,센서값, 같이보기)를 만듭니다.
4.8.2. loadData를 이용한 앱 안 동영상 스트리밍과 Toast를 이용한 알림 창 생성합니다.
4.8.3. 안드로이드 앱 안 동영상 스트리밍합니다.

66 ICT_보행로봇 (28)

66 ICT_보행로봇 (29)

66 ICT_보행로봇 (30)

4.8.4. 라즈베리파이 센서 데이터 값 App에 전송

66 ICT_보행로봇 (31)

5. 회로도

66 ICT_보행로봇 (32)

6. 참고문헌
· App 개발 때 사용한 문헌 : http://blog.naver.com/PostView.nhn?blogId=juke45ef&logNo=220827583111
· https://webnautes.tistory.com/995
· https://tony2012.tistory.com/category/Develop/IT

7. 소스코드

Android Studio – Application 개발

* 버튼 세개만들기
<Button
android:id=”@=id/btn_video”
android:layout_width=”295dp”
android:layout_height=”217dp”
android:text=”실시간 영상”
android:layout_gravity=”center”/>

<Button
android:id=”@=id/btn_sensor”
android:layout_width=”296dp”
android:layout_height=”217dp”
android:text=”실시간 영상”
android:layout_gravity=”center”/>

<Button
android:id=”@=id/btn_video”
android:layout_width=”295dp”
android:layout_height=”217dp”
android:text=”실시간 영상”
android:layout_gravity=”center”/>

1. AndroidManifest.xml에 추가
<uses-permission android:name=”android.permission.BLUETOOTH” />
<uses-permission android:name=”android.permission.BLUETOOTH_ADMIN” />

2. 디바이스에서 블루투스를 지원하는지 체크
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
showErrorDialog(“This device is not implement Bluetooth.”);
return;
}

3. 사용자에게 블루투스를 켜도록 요청
if (!mBluetoothAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_BLUETOOTH_ENABLE);
}

4. 블루투스 활성화시 showPairedDevicesListDialog() 메소드를 호출
if (!mBluetoothAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_BLUETOOTH_ENABLE);
}
else {
Log.d(TAG, “Initialisation successful.”);

showPairedDevicesListDialog();
}

5. 페어링 되어 있는 블루투스 장치들의 목록을 보여준다.
public void showPairedDevicesListDialog()
{
Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
final BluetoothDevice[] pairedDevices = devices.toArray(new BluetoothDevice[0]);

if ( pairedDevices.length == 0 ){
showQuitDialog( “No devices have been paired.\n”
+”You must pair it with another device.”);
return;
}

String[] items;
items = new String[pairedDevices.length];
for (int i=0;i<pairedDevices.length;i++) {
items[i] = pairedDevices[i].getName();
}

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(“Select device”);
builder.setCancelable(false);
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();

// Attempt to connect to the device
ConnectTask task = new ConnectTask(pairedDevices[which]);
task.execute();
}
});
builder.create().show();
}
6. 블루투스 페어링 확인
pi@raspberrypi:~ $ bluetoothctl

7. 라즈베리파이 센서 데이터 값 APP에 전송

7-1) 기본 ExampleFragment 에 버튼을 추가
<span style=”font-size: 12pt;”><Button
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”put”
android:id=”@+id/button1″
android:layout_marginTop=”120dp”
android:layout_centerHorizontal=”true” /><#textarea></span></p><div class=”autosourcing-stub-extra”></div></blockquote><div style=”color: rgb(161, 161, 161); line-height: 1.5; margin: 25px 0px 10px; font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; font-size: 11px; font-family: Dotum, sans-serif; background-color: rgb(255, 255, 255);”>
</div>
</div>
<p></p><p><br /></p></div><p></p><p><br /></p></span>
7-2) ExampleFragemnt 파일에 Activity 로 콜백해주는 함수를 선언하고 button 클릭시 만든 함수를 호출하는 이벤트를 작성

<span style=”font-size: 12pt;”>package com.hardcopy.btctemplate.fragments;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.hardcopy.btctemplate.R;

public class ExampleFragment extends Fragment {

private Context mContext = null;
private IFragmentListener mFragmentListener = null;
private Handler mActivityHandler = null;
Button button1;
String message = “%Swif^”;
public ExampleFragment(){}

@SuppressLint(“ValidFragment”)
public ExampleFragment(Context c, IFragmentListener l, Handler h) {
mContext = c;
mFragmentListener = l;
mActivityHandler = h;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy, container, false);

//버튼 클릭이벤트
button1 = (Button) rootView.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(message != null && message.length() > 0)
sendMessage(message); //아래 함수에 message를 전달하여 호출
}
});

return rootView;
}

//*****************************************

// Activity 에 데이터를 전달하는 콜백하는 함수

//*****************************************
private void sendMessage(String message) {
if(message == null || message.length() < 1)
return;
// send to remote
if(mFragmentListener != null)
mFragmentListener.OnFragmentCallback(IFragmentListener.CALLBACK_SEND_MESSAGE, 0, 0, message, null,null);
else
return;
}
}
<#textarea></span></font></strong></span></p><div class=”autosourcing-stub-extra”></div><p></p></blockquote></div></div><p><br /></p></span>

7-3) MainActivity.java 파일에 해당 콜백에 얻어오는 데이터를 가지고 블루투스에 전송
public void OnFragmentCallback(int msgType, int arg0, int arg1, String arg2, String arg3, Object arg4) {
switch(msgType) {
case IFragmentListener.CALLBACK_RUN_IN_BACKGROUND:
if(mService != null)
mService.startServiceMonitoring();
break;
case IFragmentListener.CALLBACK_SEND_MESSAGE:
if(mService != null && arg2 != null)
mService.sendMessageToRemote(arg2);

//sendMessageToRemote()함수는 BTCTempleteService.java에서 구성된 블루투스 송신메서드.
default:
break;
}
}
<#textarea></span></font></strong></p>
<p style=”list-style: none; margin: 0px; padding: 0px; font-family: inherit; font-size: inherit;”><strong><font color=”rgb(0,0,0)” style=”background-color: rgb(228, 255, 117);”><br /></font></strong></p></blockquote></div></div><p><br /></p>

출처: https://tony2012.tistory.com/?page=28 [Useless]

CodeVision AVR_4족보행로봇 제어

#include <mega128.h> //codevision에서 Atmega128사용시
#include <string.h> //string 관련 함수 , sprintf
#include <stdlib.h>
#include <stdio.h>
#include <delay.h>
#include <math.h>

// 시리얼통신에서 입력한 명령을 담아두는 곳
//예: m00123(enter) -> string[0]=’m’ string[1]=’0′ … string[6]=0x0d=‘\r’(enter에 해당하는 ASCII Code값;
char string[64];

int iTimer0,iTimer2; //타이머 초기화 카운트 값
int cmd_count;
//cmd_count: command counting, 키보드입력시 입력 횟수
int count_10usec;
//count_10usec; 10usec마다 카운팅되는 변수 timer2 overflow 시
//DegMotor:각 모터의 회전 각도,
//CntMotor:각모터의 PWM Pulse 폭
int DegMotor[12],CntMotor[12];
int OffsetDegMotor[12]={0,-5,10,5,-5,-10,13,-5,-20,-3,-2,15};
//Leg Length
float La=55,Lb=77.5,Lc=27.5;
float pi=3.141592;
/*———————————–
data를 시리얼 포트로 1 바이트 송신하기
————————————*/
void sendChar(char data)
{
int i = 0;
// To send data with the USART put the data in the USART data register
UDR0 = data;

// Check to see if the global interrupts are enabled
if(SREG & 0×80)
{
// Wait until the byte is sent or we count out
while ( !(UCSR0A&0×40) && (i<10000) )
{
i++;
}
}
else // Wait until the byte is sent
while( !(UCSR0A&0×40) ); //송신완료시까지 대기

// Clear the TXCflag
UCSR0A=UCSR0A|0×40;
}

/*—————————————————
문자열 str을 문자열 맨뒤 NULL이 나올떄 까지 한바이트씩 보내기
—————————————————-*/

void sendString(char* str)
{
while(*str) sendChar(*str++);
}
/*
만일 str[ ] = “rs232c”라면
str[0]=’r'=0×72
str[1]=’s’
str[2]=’2′=0×32
str[3]=’3′
str[4]=’2′=0×32
str[5]=’c’
str[6]=”
‘ ‘:char
” “:string
str: str이라는 문자열이 저장된 주소
*str:str에 저장된 내용
step1:while(*str) => while(‘r’); ->while(true)
step2:sendChar(*str); =>sendChar(‘r’);
step3: str++; //주소증가
step4:while(*str) => while(‘s’); ->while(true)
step5:sendChar(*str); =>sendChar(‘s’);
step6: str++;
….
stepn:while(*str) => while(”); ->while(false)
*/

/*————————————————–
시리얼 포트 초기화
8비트 데이터, 1 stop 비트,non parity, 9600 보레이트
————————————————–*/
void rs232c_initialize(void)
{
DDRE=DDRE|0×02; //포트 E의 입출력 설정 ,PE0:0 Rx0,PE1:1 Tx0
//USART Register Init
UCSR0A=0×00;
UCSR0B=0×98; //1001 1000 //7 bit : RX Complete Interrupt Enable
//4 bit : Receiver Enable. Writing this bit to one enables the USARTn Receiver.
//3 bit : Transmitter Enable. Writing this bit to one enables the USARTn Transmitter.
//2 bit : UCSR0C 2,1 bit와 연결사용

UCSR0C=0×06; //0000 0110 //6 bit : USART Mode Select. Asynchronous Operation
//5,4 bit : Parity Mode. Disabled
//3 bit : Stop Bit Select. 1-bit
//2,1 bit : Character Size. 8-bit
//0 bit : Clock Polarity. Transmitted Data : Rising XCKn Edge
// Received Data : Falling XCKn Edge

UBRR0H=0×00; //USARTn Baud Rate Register
UBRR0L=0×67; //USARTn Baud Rate Register 9600
//UBRR0L=0×8; //USARTn Baud Rate Register 115200
}

void init_Timer()
{
//prescale=1024, input frequency=16MHz/1024=64KHz T=1/64usec
//Overflow시 timing 간격은 256/64msec=16.348msec
iTimer0=0;
//Timer2, input f=16MHz, 160count=10sec is TCNT2=256-160=96
//but from tunning process, the timer2 initialzed variable is 113
iTimer2=113;
DDRC=DDRA=0xff; //Set PORTA all output
PORTC=PORTA=0×00; //Set All PortA Low

TCCR0=0×07; //oc0 not enable, normal, 분주비 1024, pb4 일반포트로 사용
TCCR2=0×01; //0b00000101 //oc2 not enable, normal, 분주비 1, pb7 일반포트로 사용
// 0 0 00 0 010
TIMSK=0×41; //timer 0and 2 overflow interrupt enable
TCNT0=iTimer0; //time 0 초기값
TCNT2=iTimer2;
}

//Deg로 입력된 것을 Pulse Width로 변환하기
void ConvertDeg2Cnt()
{
int i;
for(i=0;i<12;i++)
CntMotor[i]=(10.58*(DegMotor[i]+OffsetDegMotor[i])+459.4)/10+3;
}

interrupt [TIM0_OVF] void timer_int0()
{
PORTC=PORTA=0xff;
count_10usec=0;
TIMSK = TIMSK | 0×40; //Timer 2 Interrupt Enable
}
interrupt [TIM2_OVF] void timer_int2()
{

TCNT2=iTimer2; //the initialzed variable for 10usec timer2 overflow interrupt
count_10usec++;
if(count_10usec == CntMotor[0] ) PORTA.0=0;
if(count_10usec == CntMotor[1] ) PORTA.1=0;
if(count_10usec == CntMotor[2]) PORTA.2=0;
if(count_10usec == CntMotor[3]) PORTA.3=0;
if(count_10usec == CntMotor[4]) PORTA.4=0;
if(count_10usec == CntMotor[5]) PORTA.5=0;
if(count_10usec == CntMotor[6]) PORTA.6=0;
if(count_10usec == CntMotor[7]) PORTA.7=0;
if(count_10usec == CntMotor[8]) PORTC.0=0;
if(count_10usec == CntMotor[9]) PORTC.1=0;
if(count_10usec == CntMotor[10]) PORTC.2=0;
if(count_10usec == CntMotor[11]) PORTC.3=0;
if(count_10usec > 300)
{
TIMSK = TIMSK & 0xbf; //Timer 2 Interrupt disable
}

}

/*———————————–
수신 받은 문자열 s[]데이터 분석
————————————*/
void parseInput(char * s)
{
int imotor;
// parse first character
switch (s[0])
{
//xx축 motor 개별 제어
//m+XX(motor no.)+xxx+’\r’
case ‘m’:
case ‘M’:
//if m11135 이면 s[1]=’1′=0×31, s[2]=’1′=0×31
//아스키코드값으로 표현된 연속된 두 숫자를 10진수로 변환 하기 imotor->1*10+1=11
imotor=(s[1]-’0′)*10+(s[2]-’0′);
//s+3부터 문자열을 ascii to integer변환
/*
s[0]=’m’
s[1]=’1′
s[2]=’1′
s[3]=’1′
s[4]=’3′
s[5]=’5′
s[6]=”
이므로 s[3[부터 끝까지 ascii로되어있는 문자를 정수로 변환하시오
DegMotor[imotor]=135;
*/
DegMotor[imotor]=atoi(s+3);
ConvertDeg2Cnt();
break;

//12개의 모터 제어 데이터 열
//d+xxxxxxxxxxxx+’\r’, x는 unsigned char data
case ‘d’:
case ‘D’:
for(imotor=0;imotor<12;imotor++)
DegMotor[imotor]=(unsigned char)s[imotor+1];
ConvertDeg2Cnt();
break;

case ‘c’:
sendString(“Your command input is ..!\r\n”);
sendString(s);
sendString(“\r\n”);
break;
case ‘e’:
sendString(“Your message input is ..!\r\n”);
sendString(s);
sendString(“\r\n”);
break;
default:
break;
}
//앞에서 받은 명령을 초기화하기
s[0] = ”;
}

/*———————————————–
하이퍼터밀널에서 입력을 하고 엔터키를 입력하면
입력 데이터 뒤에 /n 이 연이어 붙는다.
/r:Carriage Return 0x0D
/n:new line , line feed 0x0A
———————————————–*/
//카보드로 입력이 들어오면 인터럽트 발생
interrupt [USART0_RXC] void usart0_rx_isr(void) //USART0 수신 완료 인터럽트
{
string[cmd_count++] = UDR0; //rx로 받은 값을 data에 저장
// “m11135+/r”=>motor 2 angle 135
/*
string[0]=‘m’
string[1]=‘1′
string[2]=‘1′
string[3]=‘1′
string[4]=‘3′
string[5]=‘5′
string[6]=‘\r’=0x0d
cmd_count->7
*/
if(string[cmd_count-1] == ‘\r’)
{
string[cmd_count-1] = ”;
//convert to a string. 문자로 하나하나 모았다가 문자열로 변환하기위해서 뒤에 NULL()로 변경
/*
string[0]=‘m’
string[1]=‘1′
string[2]=‘1′
string[3]=‘1′
string[4]=‘3′
string[5]=‘5′
string[6]=‘’=0×00
문자열로 변경된 상태
*/

parseInput(string); //명령 분석
cmd_count = 0;
}
else if(string[cmd_count-1] == ‘c’)// ‘c’+/r
{
string[1]=”; //convert to a string
parseInput(string);
cmd_count = 0;
}
else if(string[cmd_count-1] == ‘e’)// ‘e’+/r
{
string[1]=”; //convert to a string
parseInput(string);
cmd_count = 0;
//EnableTimer0Interrupt();
}
}

void Leg1(int x,int y,int z, int * theta0,int * theta1,int * theta2)
{
int w,v;
float t0,t1,t2;

w=sqrt(x*x+y*y);
v=w-Lc;
t1=atan2(v,z)+acos((La*La+z*z+v*v-Lb*Lb)/(2*La*sqrt(z*z+v*v)));
t2=acos((La*La+Lb*Lb-z*z-v*v)/(2*La*Lb));
t0=atan2(x,y);

*theta0=t0*180/pi+90;
*theta1=90-t1*180/pi;
*theta2=t2*180/pi;
}

void main(void)
{
int i;
char buff[20];

rs232c_initialize();

cmd_count=0;

for(i=0;i<12;i++) DegMotor[i]=90;
ConvertDeg2Cnt();

init_Timer();

sendString(“rs232c connected….\r\n”);

SREG=0×80; //1000 0000 //7 bit : Global Interrupt Enable

Leg1(80,40,-15,&DegMotor[0],&DegMotor[1],&DegMotor[2]);
ConvertDeg2Cnt();
itoa(DegMotor[0],buff);
sendString(buff);
sendString(“\r\n”);
itoa(DegMotor[1],buff);
sendString(buff);
sendString(“\r\n”);
itoa(DegMotor[2],buff);
sendString(buff);
sendString(“\r\n”);
while(1)
{
}
}

 CodeVision AVR (모터제어)

#include <mega128.h> //For Atmega128 in Code Vision
#include <delay.h> //For dalay_ms, delay_us

int iTimer0,iTimer2; //Timer initialized variable
int count; //count timer2 overflow interrupt
int Degree,Motor;

interrupt [TIM0_OVF] void timer_int0()
{
PORTC=PORTA=0xff;
count=0;
TIMSK = TIMSK | 0×40; //Timer 2 Interrupt Enable
}

interrupt [TIM2_OVF] void timer_int2()
{
TCNT2=iTimer2; //the initialzed variable for 10usec timer2 overflow interrupt
count++;
if(count == Motor ) PORTA.0=0;
if(count == Motor ) PORTA.1=0;
if(count == Motor) PORTA.2=0;
if(count == Motor) PORTA.3=0;
if(count == Motor) PORTA.4=0;
if(count == Motor) PORTA.5=0;
if(count == Motor) PORTA.6=0;
if(count == Motor) PORTA.7=0;
if(count == Motor) PORTC.0=0;
if(count == Motor) PORTC.1=0;
if(count == Motor) PORTC.2=0;
if(count == Motor) PORTC.3=0;
if(count > 300)
{
TIMSK = TIMSK & 0xbf; //Timer 2 Interrupt disable
}
}
void main(void)
{
iTimer0=0;
//Timer2, input f=16MHz, 160count=10sec is TCNT2=256-160=96
//but from tunning process, the timer2 initialzed variable is 113
iTimer2=113;
DDRC=DDRA=0xff; //Set PORTA all output
PORTC=PORTA=0×00; //Set All PortA Low

TCCR0=0×07; //oc0 not enable, normal, 분주비 1024, pb4 일반포트로 사용

TCCR2=0×01; //0b00000101 //oc2 not enable, normal, 분주비 1, pb7 일반포트로 사용
// 0 0 00 0 010
//TIMSK=0xC3; //timer 0 oVerflow interrupt enable
TIMSK=0×41; //timer 0and 2 overflow interrupt enable

TCNT0=iTimer0; //time 0 초기값
TCNT2=iTimer2;

SREG=0×80; //인터럽트 인에이블

Degree=90;
while(1)
{
Motor=(10.58*Degree+459.4)/10+3;
}
}

 Python – 라즈베리파이와 적외선 카메라 연동
1. SUDO RASPI-CONFIG 접속
sudo raspi-config

2. 인터페이스 옵션 설정(카메라활성화)

3. mjpg-streamer 소스 코드를 다운로드 받을 디렉토리를 생성
pi@raspberrypi:~ $ mkdir project
pi@raspberrypi:~ $ cd project
pi@raspberrypi:~/project $

4. 소스 코드를 다운로드 받기위해서 git가 필요
pi@raspberrypi:~/project $ sudo apt-get install git

5. mjpg-streamer 소스 코드를 다운로드
pi@raspberrypi:~/project $ git clone https://github.com/jacksonliam/mjpg-streamer.git

6. mjpg-streamer 소스 코드를 컴파일하기 위해 필요한 패키지를 설치
pi@raspberrypi:~/project $ sudo apt-get install cmake python-imaging libjpeg-dev build-essential

7. mjpg-streamer 소스 디렉토리로 이동하여 컴파일 및 설치를 진행
pi@raspberrypi:~/project $ cd mjpg-streamer/mjpg-streamer-experimental/
pi@raspberrypi:~/project/mjpg-streamer/mjpg-streamer-experimental $ make CMAKE_BUILD_TYPE=Debug
pi@raspberrypi:~/project/mjpg-streamer/mjpg-streamer-experimental $ sudo make install
pi@raspberrypi:~/project/mjpg-streamer/mjpg-streamer-experimental $ cd
pi@raspberrypi:~ $

8. 캠으로부터 캡처한 영상을 HTTP 포트 8090으로 스트리밍
pi@raspberrypi:~ $ mjpg_streamer -i “input_uvc.so” -o “output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www/”

 Python – 라즈베리파이와 적외선센서연동

터미널창에서 state_Value 라는 파이썬 파일 만들기
nano state_Value.py

소스 코드 입력하기(sensor 값 최소 최대설정)
import Rpi.GPIO as GPIO
import time

IR = 7
GPIOIN = 17
GPIOOUT = 27

GPOI.setmode(GPIO.BCM)
print (” motion detection start”)

GPIO.setup(IR, GPIO.IN)
try:

저장후 명령어 python state_Value.py 로 코드 실행
nano state Value.py
python state_Value.py

Visaul Studio 2017(4족 보행로봇 제어)
// QuadrupedRobotControlDlg.cpp: 구현 파일
//

#include “stdafx.h”
#include “QuadrupedRobotControl.h”
#include “QuadrupedRobotControlDlg.h”
#include “afxdialogex.h”

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 응용 프로그램 정보에 사용되는 CAboutDlg 대화 상자입니다.

class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();

// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.

// 구현입니다.
protected:
DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

// CQuadrupedRobotControlDlg 대화 상자

CQuadrupedRobotControlDlg::CQuadrupedRobotControlDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_QUADRUPEDROBOTCONTROL_DIALOG, pParent)
, m_str_comport(_T(“”))
, m_str_baudrate(_T(“”))
, m_Motor0(90)
, m_Motor1(90)
, m_Motor2(90)
, m_Motor3(90)
, m_Motor4(90)
, m_Motor5(90)
, m_Motor6(90)
, m_Motor7(90)
, m_Motor8(90)
, m_Motor9(90)
, m_Motor10(90)
, m_Motor11(90)
, m_Motion_Sleep(0)
, m_iExecIndex(0)
, m_StepDelay(0)
, m_MotionCommand(_T(“”))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CQuadrupedRobotControlDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_COMBO_COMPORT, m_combo_comport_list);
DDX_Control(pDX, IDC_COMBO_BAUDRATE, m_combo_baudrate_list);
DDX_CBString(pDX, IDC_COMBO_COMPORT, m_str_comport);
DDX_CBString(pDX, IDC_COMBO_BAUDRATE, m_str_baudrate);
DDX_Control(pDX, IDC_EDIT_RCV_VIEW, m_edit_rcv_view);
DDX_Control(pDX, IDC_EDIT_RCV_DATA, m_edit_rcv_data);
DDX_Text(pDX, IDC_MOTOR0, m_Motor0);
DDX_Text(pDX, IDC_MOTOR1, m_Motor1);
DDX_Text(pDX, IDC_MOTOR2, m_Motor2);
DDX_Text(pDX, IDC_MOTOR3, m_Motor3);
DDX_Text(pDX, IDC_MOTOR4, m_Motor4);
DDX_Text(pDX, IDC_MOTOR5, m_Motor5);
DDX_Text(pDX, IDC_MOTOR6, m_Motor6);
DDX_Text(pDX, IDC_MOTOR7, m_Motor7);
DDX_Text(pDX, IDC_MOTOR8, m_Motor8);
DDX_Text(pDX, IDC_MOTOR9, m_Motor9);
DDX_Text(pDX, IDC_MOTOR10, m_Motor10);
DDX_Text(pDX, IDC_MOTOR11, m_Motor11);
DDX_Control(pDX, IDC_EDIT_MOTION_COMMAND, m_Edit_Motion_Command);
DDX_Text(pDX, IDC_MOTION_SLEEP, m_Motion_Sleep);
DDX_Text(pDX, IDC_INDEX, m_iExecIndex);
DDX_Text(pDX, IDC_EDIT_STEPDELAY, m_StepDelay);
DDX_Text(pDX, IDC_EDIT_MOTION_COMMAND, m_MotionCommand);
}

BEGIN_MESSAGE_MAP(CQuadrupedRobotControlDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_MYCLOSE, &CQuadrupedRobotControlDlg::OnThreadClosed)
ON_MESSAGE(WM_MYRECEIVE, &CQuadrupedRobotControlDlg::OnReceive)
ON_BN_CLICKED(IDC_BT_CONNECT, &CQuadrupedRobotControlDlg::OnBnClickedBtConnect)
ON_BN_CLICKED(IDC_BT_CLEAR, &CQuadrupedRobotControlDlg::OnBnClickedBtClear)
ON_CBN_SELCHANGE(IDC_COMBO_COMPORT, &CQuadrupedRobotControlDlg::OnCbnSelchangeComboComport)
ON_CBN_SELCHANGE(IDC_COMBO_BAUDRATE, &CQuadrupedRobotControlDlg::OnCbnSelchangeComboBaudrate)
ON_BN_CLICKED(IDC_BT_SEND, &CQuadrupedRobotControlDlg::OnBnClickedBtSend)
ON_BN_CLICKED(IDC_BT_MOTION, &CQuadrupedRobotControlDlg::OnBnClickedBtMotion)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_MOTION, &CQuadrupedRobotControlDlg::OnDeltaposSpinMotion)
ON_BN_CLICKED(IDC_BT_EXECUTION, &CQuadrupedRobotControlDlg::OnBnClickedBtExecution)
ON_BN_CLICKED(IDC_BT_CONT_EXECUTION, &CQuadrupedRobotControlDlg::OnBnClickedBtContExecution)
ON_BN_CLICKED(IDC_BT_SEND2, &CQuadrupedRobotControlDlg::OnBnClickedBtSend2)
ON_BN_CLICKED(IDC_OPEN, &CQuadrupedRobotControlDlg::OnBnClickedOpen)
ON_BN_CLICKED(IDC_LOAD, &CQuadrupedRobotControlDlg::OnBnClickedLoad)
END_MESSAGE_MAP()

// CQuadrupedRobotControlDlg 메시지 처리기

BOOL CQuadrupedRobotControlDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();

// 시스템 메뉴에 “정보…” 메뉴 항목을 추가합니다.

// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
// 프레임워크가 이 작업을 자동으로 수행합니다.
SetIcon(m_hIcon, TRUE); // 큰 아이콘을 설정합니다.
SetIcon(m_hIcon, FALSE); // 작은 아이콘을 설정합니다.

// TODO: 여기에 추가 초기화 작업을 추가합니다.
m_combo_comport_list.AddString(_T(“COM1″));
m_combo_comport_list.AddString(_T(“COM2″));
m_combo_comport_list.AddString(_T(“COM3″));
m_combo_comport_list.AddString(_T(“COM4″));
m_combo_comport_list.AddString(_T(“COM7″));
m_combo_comport_list.AddString(_T(“COM9″));
m_combo_comport_list.AddString(_T(“COM10″));
m_combo_comport_list.AddString(_T(“COM13″));
m_combo_comport_list.AddString(_T(“COM14″));
m_combo_comport_list.AddString(_T(“COM16″));

m_combo_baudrate_list.AddString(_T(“1200″));
m_combo_baudrate_list.AddString(_T(“9600″));
m_combo_baudrate_list.AddString(_T(“19200″));
m_combo_baudrate_list.AddString(_T(“38400″));
m_combo_baudrate_list.AddString(_T(“115200″));

comport_state = false;
GetDlgItem(IDC_BT_CONNECT)->SetWindowText(_T(“OPEN”));
m_str_comport = _T(“COM7″);
m_str_baudrate = _T(“9600″);
m_iExecIndex=iExecindex = 0;
m_StepDelay = 500;

UpdateData(FALSE);

return TRUE; // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}

void CQuadrupedRobotControlDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}

// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
// 아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
// 프레임워크에서 이 작업을 자동으로 수행합니다.

void CQuadrupedRobotControlDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() – cxIcon + 1) / 2;
int y = (rect.Height() – cyIcon + 1) / 2;

// 아이콘을 그립니다.
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}

// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
// 이 함수를 호출합니다.
HCURSOR CQuadrupedRobotControlDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}

LRESULT CQuadrupedRobotControlDlg::OnThreadClosed(WPARAM length, LPARAM lpara)
{
// overlapped i/o 핸들을 닫는다
((Ccomm*)lpara)->HandleClose();
delete ((Ccomm*)lpara);

return 0;
}

LRESULT CQuadrupedRobotControlDlg::OnReceive(WPARAM length, LPARAM lpara)
{
CString str;
char data[20000];
if (m_comm)
{
m_comm->Receive(data, length); // length 길이 만큼 데이터를 받는다.
data[length] = _T(”);

for (int i = 0; i < length; i++)
{
str += data[i];
}
m_edit_rcv_view.ReplaceSel(str); // 에디터 박스에 표시하기 위함
str = _T(“”);
m_edit_rcv_view.LineScroll(m_edit_rcv_view.GetLineCount()); // 화면이 넘어가면 우측 스크롤을 맨 아래로 내려 주는 역할
}
return 0;
}
void CQuadrupedRobotControlDlg::OnBnClickedBtConnect()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
if (!comport_state) // Comport가 없다면..
{
m_comm = new Ccomm(_T(“\\\\.\\”) + m_str_comport, m_str_baudrate,
_T(“None”), _T(“8 Bit”), _T(“1 Bit”)); // initial Comm port

if (m_comm->Create(GetSafeHwnd()) != 0) // 통신 포트를 열고 윈도우의 핸들을 넘긴다.
{
AfxMessageBox(_T(“COM 포트열림”));
comport_state = true;
GetDlgItem(IDC_BT_CONNECT)->SetWindowText(_T(“CLOSE”));
GetDlgItem(IDC_BT_SEND)->EnableWindow(true);
}
else
{
AfxMessageBox(_T(“ERROR!”));
}
}
else
{
if (m_comm) // Comport가 존재하면..
{
m_comm->Close();
m_comm = NULL;
AfxMessageBox(_T(“COM 포트닫힘”));
comport_state = false;
GetDlgItem(IDC_BT_CONNECT)->SetWindowText(_T(“OPEN”));
GetDlgItem(IDC_BT_SEND)->EnableWindow(false);
}
}

}
void CQuadrupedRobotControlDlg::OnBnClickedBtClear()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
GetDlgItem(IDC_EDIT_RCV_VIEW)->SetWindowText(_T(” “));
}
void CQuadrupedRobotControlDlg::OnCbnSelchangeComboComport()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData();
}
void CQuadrupedRobotControlDlg::OnCbnSelchangeComboBaudrate()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData();
}
void CQuadrupedRobotControlDlg::OnBnClickedBtSend()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
CString str;
int i;

GetDlgItem(IDC_EDIT_RCV_DATA)->GetWindowText(str);
str += _T(“\r”);; //문장 뒤에 ’\r’ carriage return 을 붙여 명령 끝을 알린다.
//m_comm->Send(str, str.GetLength());

char* ss = LPSTR(LPCTSTR(str)); //CString을 char 형으로 변환
/*마이콤에서 해독하는 데 일정 시간이 소요되어 마치 키보드 입력처럼 명령사이에
지연시간을 준다.
또한 CString을 char로 변환시 하나의 문자가 2바이트로 변환되며 두번쨰는 비어있다.
예로
CString “2345: -> “2″,”",”3″,”",”4″,”",”5″,”"
*/

for (i = 0; i < str.GetLength(); i++)
{
m_comm->Send(ss, 1);
ss = ss + 2; //2 byte offset
Sleep(5);
}

}
void CQuadrupedRobotControlDlg::OnBnClickedBtSend2()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
CString str;
int i;

GetDlgItem(IDC_EDIT_RCV_DATA)->GetWindowText(str);

char* ss = LPSTR(LPCTSTR(str)); //CString을 char 형으로 변환
for (i = 0; i < str.GetLength(); i++)
{
m_comm->Send(ss, 1);
ss = ss + 2; //2 byte offset
Sleep(5);
}
}
void CQuadrupedRobotControlDlg::OnBnClickedBtMotion()
{
int i;
char buf[30];
char * ss;
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData(true); //read parameter

if (m_Motion_Sleep == 0) //Motion Command
{
buf[0] = ‘d’;
buf[1] = m_Motor0;
buf[2] = m_Motor1;
buf[3] = m_Motor2;
buf[4] = m_Motor3;
buf[5] = m_Motor4;
buf[6] = m_Motor5;
buf[7] = m_Motor6;
buf[8] = m_Motor7;
buf[9] = m_Motor8;
buf[10] = m_Motor9;
buf[11] = m_Motor10;
buf[12] = m_Motor11;
buf[13] = ‘\r’;

ss = buf;
for (i = 0; i < 14; i++)
{
m_comm->Send(ss, 1);
ss++;
Sleep(5); //실험으로 정함 매우중요
}
}
else //Sleep Command
{
buf[0] = ‘s’;
buf[1] = m_Motion_Sleep;
buf[2] = ‘\r’;
ss = buf;
for (i = 0; i < 3; i++)
{
m_comm->Send(ss, 1);
ss++;
Sleep(5);
}
}
//m_comm->Send((char *)buf, strlen((char *)buf));
}

void CQuadrupedRobotControlDlg::OnDeltaposSpinMotion(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
if (pNMUpDown->iDelta > 0)
{
iExecindex–;
if (iExecindex < 0) iExecindex = 0;
}
else
{
iExecindex++;
}
m_iExecIndex = iExecindex;
UpdateData(false);
*pResult = 0;
}
/*
CString -> int 변환, int->CString 변환
CString → int
int형 = _ttoi(CString형);
int → CString
CString형.Format(_T(“%d”), int형);
*/

void CQuadrupedRobotControlDlg::OnBnClickedBtExecution()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
CString str, strBuff;
CString mCode;
CString mMotor0, mMotor1, mMotor2, mMotor3, mMotor4, mMotor5, mMotor6, mMotor7, mMotor8, mMotor9, mMotor10, mMotor11, mSleep;

UpdateData(true); //read parameter

GetDlgItem(IDC_EDIT_MOTION_COMMAND)->GetWindowText(str);
if (AfxExtractSubString(strBuff, str, m_iExecIndex, ‘\n’))
{
mCode = strBuff.Left(1);
if (mCode.Compare(_T(“d”)) == 0)
{
AfxExtractSubString(mMotor0, strBuff, 1, ‘,’);
AfxExtractSubString(mMotor1, strBuff, 2, ‘,’);
AfxExtractSubString(mMotor2, strBuff, 3, ‘,’);
AfxExtractSubString(mMotor3, strBuff, 4, ‘,’);
AfxExtractSubString(mMotor4, strBuff, 5, ‘,’);
AfxExtractSubString(mMotor5, strBuff, 6, ‘,’);
AfxExtractSubString(mMotor6, strBuff, 7, ‘,’);
AfxExtractSubString(mMotor7, strBuff, 8, ‘,’);
AfxExtractSubString(mMotor8, strBuff, 9, ‘,’);
AfxExtractSubString(mMotor9, strBuff, 10, ‘,’);
AfxExtractSubString(mMotor10, strBuff, 11, ‘,’);
AfxExtractSubString(mMotor11, strBuff, 12, ‘,’);
m_Motor0 = _ttoi(mMotor0);
m_Motor1 = _ttoi(mMotor1);
m_Motor2 = _ttoi(mMotor2);
m_Motor3 = _ttoi(mMotor3);
m_Motor4 = _ttoi(mMotor4);
m_Motor5 = _ttoi(mMotor5);
m_Motor6 = _ttoi(mMotor6);
m_Motor7 = _ttoi(mMotor7);
m_Motor8 = _ttoi(mMotor8);
m_Motor9 = _ttoi(mMotor9);
m_Motor10 = _ttoi(mMotor10);
m_Motor11 = _ttoi(mMotor11);
m_Motion_Sleep = 0;
}
else if (mCode.Compare(_T(“s”)) == 0)
{
AfxExtractSubString(mSleep, strBuff, 1, ‘,’);
m_Motion_Sleep = _ttoi(mSleep);
}
else
{
}
m_iExecIndex++;
}
UpdateData(false);

OnBnClickedBtMotion();

//출처: https://bigmark.tistory.com/11 [마크의 맥시멈 라이프]

}
void CQuadrupedRobotControlDlg::OnBnClickedBtContExecution()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
CString str, strBuff;
m_iExecIndex = 0;
UpdateData(true); //read parameter

GetDlgItem(IDC_EDIT_MOTION_COMMAND)->GetWindowText(str);
while(AfxExtractSubString(strBuff, str, m_iExecIndex, ‘\n’))
{
OnBnClickedBtExecution();
Sleep(m_StepDelay);
}
m_iExecIndex = 0;
UpdateData(false);

}
void CQuadrupedRobotControlDlg::OnBnClickedOpen()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
CString m_strStatus,tmp;
CString m_strPath;
CStdioFile file;
// CFile file;
CFileException ex;
CFileDialog dlg(TRUE, _T(“*.txt”), NULL, OFN_FILEMUSTEXIST | OFN_OVERWRITEPROMPT, _T(“Motion Files(*.txt)|*.txt|”), NULL);
if (dlg.DoModal() == IDOK)
{
m_strPath = dlg.GetPathName();
if (m_strPath.Right(4) != “.txt”)
{
m_strPath += “.txt”;
}
file.Open(m_strPath, CFile::modeRead, &ex);

while (file.ReadString(tmp))
m_MotionCommand += tmp + _T(“\n”);
file.Close();
//http://blog.naver.com/PostView.nhn?blogId=kan0909&logNo=90138161650
UpdateData(false);
}
}
void CQuadrupedRobotControlDlg::OnBnClickedLoad()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
CString m_strStatus;
CString m_strPath;
CStdioFile file;

// CFile file;
CFileException ex;
CFileDialog dlg(FALSE, _T(“*.txt”), NULL, OFN_FILEMUSTEXIST | OFN_OVERWRITEPROMPT, _T(“Motion Files(*.txt)|*.txt|”), NULL);
if (dlg.DoModal() == IDOK)
{
m_strPath = dlg.GetPathName();
if (m_strPath.Right(4) != “.txt”)
{
m_strPath += “.txt”;
}
file.Open(m_strPath, CFile::modeCreate | CFile::modeReadWrite | CFile::modeRead, &ex);

GetDlgItem(IDC_EDIT_MOTION_COMMAND)->GetWindowText(m_strStatus);

file.WriteString(m_strStatus);
file.Close();
}
}

 

Leave A Comment

*