๊ธ€ ์ž‘์„ฑ์ž: ์ด์ง€์›๐ŸŒฉ๏ธ

๐Ÿ’ก ์ดˆ๊ธฐ ์„ค์ •(OS ์„ค์น˜, ์„ค์ • ๋“ฑ)์€ ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฐ€์ • ํ•˜์— ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

์ค€๋น„๋ฌผ

  1. ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด3 B+
  2. DC๋ชจํ„ฐ (ํ˜น์€ ๊ธฐํƒ€ ์„ผ์„œ ๋“ฑ)
  3. Android Studio
  4. (์„ ํƒ) ํ…Œ์ŠคํŠธ ๊ธฐ๊ธฐ

 

Flask ์„ค์น˜

pi@raspberrypi:~ $ sudo pip install flask

์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ

pi@raspberrypi:~ $ mkdir workspace

pi@raspberrypi:~ $ cd workspace

๋ชจํ„ฐ ์ œ์–ด ์ฝ”๋“œ ์ž‘์„ฑ

vi ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํŒŒ์ผ ์ƒ์„ฑ. ํŒŒ์ผ ์ด๋ฆ„์€ ์ ๋‹นํžˆ ์ง€์–ด๋„ ๋ฌด๊ด€ํ•จ.

pi@raspberrypi:~/workspace $ vi motor.py

motor.py

# -*- coding: utf-8 -*-

# ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด GPIO ํŒจํ‚ค์ง€ 
import RPi.GPIO as GPIO
from time import sleep

# PIN ์ž…์ถœ๋ ฅ ์„ค์ •
OUTPUT = 1
INPUT = 0

# PIN ์„ค์ •
HIGH = 1
LOW = 0

# ์‹ค์ œ ํ•€ ์ •์˜
#PWM PIN
ENA = 26  #37 pin
ENB = 0   #27 pin

#GPIO PIN
IN1 = 19  #37 pin
IN2 = 13  #35 pin
IN3 = 6   #31 pin
IN4 = 5   #29 pin

# ํ•€ ์„ค์ • ํ•จ์ˆ˜
def setPinConfig(EN, INA, INB):        
    GPIO.setup(EN, GPIO.OUT)
    GPIO.setup(INA, GPIO.OUT)
    GPIO.setup(INB, GPIO.OUT)
    # 100khz ๋กœ PWM ๋™์ž‘ ์‹œํ‚ด 
    pwm = GPIO.PWM(EN, 100) 
    # ์šฐ์„  PWM ๋ฉˆ์ถค.   
    pwm.start(0) 
    return pwm

# ๋ชจํ„ฐ ์ œ์–ด ํ•จ์ˆ˜
def setMotorContorl(pwm, INA, INB, speed, stat):

    #๋ชจํ„ฐ ์†๋„ ์ œ์–ด PWM
    pwm.ChangeDutyCycle(speed)  

    if stat == FORWARD:
        GPIO.output(INA, HIGH)
        GPIO.output(INB, LOW)

    #๋’ค๋กœ
    elif stat == BACKWORD:
        GPIO.output(INA, LOW)
        GPIO.output(INB, HIGH)

    #์ •์ง€
    elif stat == STOP:
        GPIO.output(INA, LOW)
        GPIO.output(INB, LOW)


# ๋ชจํ„ฐ ์ œ์–ดํ•จ์ˆ˜ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•œ๋ฒˆ๋” ๋ž˜ํ•‘(๊ฐ์Œˆ)
def setMotor(ch, speed, stat):
    if ch == CH1:
        #pwmA๋Š” ํ•€ ์„ค์ • ํ›„ pwm ํ•ธ๋“ค์„ ๋ฆฌํ„ด ๋ฐ›์€ ๊ฐ’์ด๋‹ค.
        setMotorContorl(pwmA, IN1, IN2, speed, stat)
    else:
        #pwmB๋Š” ํ•€ ์„ค์ • ํ›„ pwm ํ•ธ๋“ค์„ ๋ฆฌํ„ด ๋ฐ›์€ ๊ฐ’์ด๋‹ค.
        setMotorContorl(pwmB, IN3, IN4, speed, stat)


# GPIO ๋ชจ๋“œ ์„ค์ • 
GPIO.setmode(GPIO.BCM)

#๋ชจํ„ฐ ํ•€ ์„ค์ •
#ํ•€ ์„ค์ •ํ›„ PWM ํ•ธ๋“ค ์–ป์–ด์˜ด 
pwmA = setPinConfig(ENA, IN1, IN2)
pwmB = setPinConfig(ENB, IN3, IN4)

# ์ข…๋ฃŒ
GPIO.cleanup()

์ถœ์ฒ˜: https://blog.naver.com/chandong83/221156273595

 

Flask ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ

vi ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํŒŒ์ผ ์ƒ์„ฑ. ํŒŒ์ผ ์ด๋ฆ„์€ ์ ๋‹นํžˆ ์ง€์–ด๋„ ๋ฌด๊ด€ํ•จ.

pi@raspberrypi:~/workspace $ vi app.py

app.py

from flask import Flask
from time import sleep
import RPi.GPIO as GPIO
import motor

GPIO.setwarnings(False)

# ๋ชจํ„ฐ ์ƒํƒœ
STOP  = 0
FORWARD  = 1
BACKWORD = 2

# ๋ชจํ„ฐ ์ฑ„๋„
CH1 = 0
CH2 = 1

app = Flask(__name__)

# index ํŽ˜์ด์ง€๋Š” ๋ชจํ„ฐ์ œ์–ด์™€๋Š” ๊ด€๊ณ„ ์—†์Œ
@app.route('/')
def index():
    return 'Hello World!'

@app.route('/left')
def left():
    motor.setMotor(CH1, 100, FORWARD)
    # 15์ดˆ ๋Œ€๊ธฐ
    sleep(15)
    motor.setMotor(CH1, 100, STOP)
    # return ๊ฐ’์€ ์˜๋ฏธ ์—†์Œ
    return 'Sucess!'

@app.route('/right')
def right():
    motor.setMotor(CH2, 100, FORWARD)
    # 15์ดˆ ๋Œ€๊ธฐ
    sleep(15)
    motor.setMotor(CH2, 100, STOP)
    # return ๊ฐ’์€ ์˜๋ฏธ ์—†์Œ
    return 'Sucess!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

์™ธ๋ถ€์—์„œ Flask ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ ‘์†ํ•˜๋ ค๋ฉด

  • app.run()์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ host='0.0.0.0' ๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.
  • Flask ์˜ ๊ธฐ๋ณธ ํฌํŠธ๋Š” 5000์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ณต์œ ๊ธฐ๋ฅผ ์‚ฌ์šฉ์ค‘์ด๋ผ๋ฉด ํฌํŠธํฌ์›Œ๋”ฉ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด 5000 ํฌํŠธ๋ฅผ ์—ด์–ด์•ผ ํ•œ๋‹ค.

Flask ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰

pi@raspberrypi:~/workspace $ python3 app.py

๋งŒ์•ฝ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด & ๋ฅผ ๋ถ™์—ฌ์„œ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

pi@raspberrypi:~/workspace $ python3 app.py &

์ด๋งˆ์ €๋„ ๊ท€์ฐฎ๊ณ  ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด๊ฐ€ ๋ถ€ํŒ…์ด ๋  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์‹คํ–‰์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด

pi@raspberrypi:~/workspace $ sudo vi /etc/rc.local

rc.local

...(์ƒ๋žต)...

# exit 0 ๋ฐ”๋กœ ์œ— ์ค„์— ์ž‘์„ฑํ•ด์•ผ ํ•จ!
# ๊ถŒํ•œ์ด ํ•„์š”์—†๋Š” ์ฝ”๋“œ์ง€๋งŒ ํ˜น์‹œ ๋ชจ๋ฅผ ์ผ์— ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ ์—ˆ์Œ
sudo pyhon3 /home/pi/workspace/app.py &

exit 0

์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•ด์•ผํ•  ์ ์€ app.py ํŒŒ์ผ์ด ์žˆ๋Š” ๊ฒฝ๋กœ๊นŒ์ง€ ์ ˆ๋Œ€๊ฒฝ๋กœ๋กœ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค.

์ €์žฅ ํ›„ ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด๋ฅผ reboot ํ•˜๋ฉด ์œ„์—์„œ ๋งŒ๋“  Flask ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰๋œ๋‹ค. ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋Š” ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

pi@raspberrypi:~ $ top | grep 'python'

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ฃฝ์ด๊ณ  ์‹ถ๋‹ค๋ฉด ์œ„์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด PID๋ฅผ ์•Œ์•„๋‚ธ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

pi@raspberrypi:~ $ kill -9 PID
  • PID ๋Š” ์ˆซ์ž ๊ฐ’.

์ด์ œ ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ดIP:5000/left ํ˜น์€ ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ดIP:5000/right ๋กœ ์ ‘์†ํ•˜๋ฉด DC ๋ชจํ„ฐ๊ฐ€ 15์ดˆ ๋™์•ˆ ๋Œ์•„๊ฐ„๋‹ค.

์•ˆ๋“œ๋กœ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ œ์ž‘

in Android Studio

  1. ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

  2. Empty Activity๋ฅผ ์„ ํƒํ•œ๋‹ค.

  3. activity_main.xml์— Button์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

     <Button
         android:id="@+id/leftBtn"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="์™ผ์ชฝ ๋ชจํ„ฐ" />
  4. ์•ˆ๋“œ๋กœ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ†ตํ•ด ์ธํ„ฐ๋„ท์„ ์ ‘์†ํ•˜๋ ค๋ฉด Manifest ํŒŒ์ผ์—์„œ ๊ถŒํ•œ์„ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค. Manifest ํŒŒ์ผ์„ ์—ด์–ด ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

     <uses-permission android:name="android.permission.INTERNET" />
  5. Volley ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด build.gradle ์— ์ถ”๊ฐ€ํ•œ๋‹ค.

     dependencies {
         implementation 'com.android.volley:volley:1.1.1'
     }
  6. MainActivity.java ์— ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

    package com.example.test;
        
    import androidx.appcompat.app.AppCompatActivity;
        
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.View;
    import android.widget.Button;
    
    import com.android.volley.Request;
    import com.android.volley.RequestQueue;
    import com.android.volley.Response;
    import com.android.volley.VolleyError;
    import com.android.volley.toolbox.StringRequest;
    import com.android.volley.toolbox.Volley;
        
        
    public class MainActivity extends AppCompatActivity {
        private static final int LEFT_TAG = 567;
        
        Button leftBtn;
        RequestQueue queue;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        
            leftBtn = findViewById(R.id.leftBtn);
            queue = Volley.newRequestQueue(this);
        
            leftBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    leftBtn.setEnabled(false);
                    sendRequest(LEFT_TAG);
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            leftBtn.setEnabled(true);
                        }
                    }, 15000);
                }
            });
        }
        
        
        private void sendRequest(int TAG) {
            StringRequest stringRequest;
            switch (TAG) {
                case LEFT_TAG:
                    stringRequest = new StringRequest(Request.Method.GET, "http://๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ดIP:5000/left",
                            new Response.Listener<String>() {
                                @Override
                                public void onResponse(String response) {
                                }
                            },
                            new Response.ErrorListener() {
                                @Override
                                public void onErrorResponse(VolleyError error) {
                                }
                            });
                    queue.add(stringRequest);
                    break;
        		default:
        			break;
            }
        
        
        }
        
    }

-

์ž‘๋…„์— ๋…ธ์…˜์œผ๋กœ ์ž‘์„ฑํ–ˆ๋˜ ๋ฌธ์„œ๋ฅผ ๋ธ”๋กœ๊ทธ๋กœ ์˜ฎ๊น€.

๋ฐ˜์‘ํ˜•