콘텐츠로 이동

MyApp으로 나만의 로봇앱 만들기

MyApp은 PhysiCar를 제어하는 나만의 웹 앱입니다. 5000 포트로 실행하면 앱의 MYAPP 탭(/myapp/)에 나타납니다.

1. 최소 앱

/home/physicar/physicar_wsapp.py를 만듭니다:

# app.py  (최초 1회: pip install flask requests)
import requests
from flask import Flask, Response

app = Flask(__name__)
ROBOT = "http://localhost:8000"   # 로봇의 로컬 Web API

@app.route("/")
def home():
    return """
      <button onclick="fetch('./forward')">전진</button>
      <button onclick="fetch('./stop')">정지</button>
      <img src="./photo">
    """

@app.route("/forward")
def forward(): requests.post(f"{ROBOT}/speed", json={"value": 0.5}); return {"ok": True}

@app.route("/stop")
def stop(): requests.post(f"{ROBOT}/speed", json={"value": 0.0}); return {"ok": True}

@app.route("/photo")
def photo(): return Response(requests.get(f"{ROBOT}/camera").content, mimetype="image/jpeg")

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

상대 경로를 쓰세요

nginx는 앱을 /myapp/ 아래에서 서빙하며 접두사를 뗍니다 — 링크·fetch()/...가 아니라 ./...로 쓰세요.

2. Web API로 제어

로봇의 로컬 Web API(8000 포트)가 모든 걸 움직입니다:

requests.post(f"{ROBOT}/speed", json={"value": 0.5})      # m/s
requests.post(f"{ROBOT}/steering", json={"value": 0.2})   # rad (좌 +)
jpeg  = requests.get(f"{ROBOT}/camera").content           # JPEG 바이트
state = requests.get(f"{ROBOT}/states").json()            # 속도·배터리 등

3. AI 두뇌 달기

로그인한 사용자의 세션으로 chat API를 호출합니다. 사용자가 PhysiCar 앱에 로그인하면 내 앱으로 오는 모든 요청에 physicar_session 쿠키가 실려 옵니다(AI 사용량은 그 사용자의 크레딧에서 차감):

import base64
from flask import request

@app.post("/ask")
def ask():
    token = request.cookies.get("physicar_session")   # PhysiCar 앱 로그인 시 심어짐
    b64 = base64.b64encode(requests.get(f"{ROBOT}/camera").content).decode()
    r = requests.post("https://api.physicar.ai/chat",
        headers={"Authorization": f"Bearer {token}"},
        json={"user_message": {"contents": [
                  {"type": "image", "mime": "image/jpeg", "base64": b64},
                  {"type": "text", "text": "앞에 사람 있어? yes 또는 no."}]},
              "prompt": {"model": "gemini-flash"}})
    answer = r.json().get("text") or ""
    if "yes" in answer.lower():
        requests.post(f"{ROBOT}/speed", json={"value": 0.3})
    return {"answer": answer}

토큰은 요청마다 읽으세요

physicar_session 쿠키는 요청마다 읽으세요 — 토큰 하나를 전역으로 캐시하면 공유 로봇에서 모두의 요청이 한 계정으로 과금됩니다.

브라우저에서도

nginx가 모든 /myapp/ HTML 페이지에 작은 헬퍼를 자동 주입하므로, 페이지의 자바스크립트에서도 window.physicarSession.token()으로 같은 토큰을 바로 읽을 수 있습니다 — 별도 설정이 없습니다.

4. 부팅 시 자동 시작

실행 명령을 /opt/physicar/userdata/myapp.sh에 넣습니다:

# /opt/physicar/userdata/myapp.sh
python3 /home/physicar/physicar_ws/app.py

로봇은 이 파일을 서비스로 실행합니다: 부팅 시 myapp.sh가 있으면 자동으로 시작되고, 출력은 바로 옆의 myapp.log에 기록됩니다. 스크립트는 내 작업 폴더에서 실행되지 않으니 안에서는 절대 경로를 쓰세요. 앱이 5000 포트에 응답하기 전까지 MYAPP 탭에는 "MyApp is not running" 페이지가 뜨고, 앱이 뜨면 자동으로 새로고침됩니다.

재부팅 없이 반영하려면 /settings/myapp 아래의 관리 API를 쓰세요(/docs에서 전부 볼 수 있습니다 — 스크립트 교체·삭제, 로그 스트림):

curl -X POST http://localhost:8000/settings/myapp/restart      # /start, /stop 도 있음
curl "http://localhost:8000/settings/myapp/log?tail=50"        # 로그 읽기

점검: 5000 포트, 상대 경로, 실행 명령은 /opt/physicar/userdata/myapp.sh에.

🛠 미션: Follow-me 또는 문 앞 인사 로봇을 만들어보세요. 같은 앱이 실물 키트에서도 그대로 돌아갑니다.

더 알아보기

로봇 엔드포인트 → Web API. AI 요청 → Chat API 규격.

AI