Skip to content

Build your own robot app with MyApp

MyApp is your own web app that controls the PhysiCar. Run it on port 5000 and it appears in the app's MYAPP tab (at /myapp/).

1. A minimal app

Create app.py in /home/physicar/physicar_ws:

# app.py  (install once: pip install flask requests)
import requests
from flask import Flask, Response

app = Flask(__name__)
ROBOT = "http://localhost:8000"   # the robot's local Web API

@app.route("/")
def home():
    return """
      <button onclick="fetch('./forward')">Forward</button>
      <button onclick="fetch('./stop')">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)

Use relative paths

nginx serves your app under /myapp/ and strips the prefix — write links and fetch() as ./..., not /....

2. Control with the Web API

The robot's local Web API (port 8000) drives everything:

requests.post(f"{ROBOT}/speed", json={"value": 0.5})      # m/s
requests.post(f"{ROBOT}/steering", json={"value": 0.2})   # rad (left +)
jpeg  = requests.get(f"{ROBOT}/camera").content           # JPEG bytes
state = requests.get(f"{ROBOT}/states").json()            # speed, battery, etc.

3. Add an AI brain

Call the chat API with the signed-in user's session: when the user signs in to the PhysiCar app, every request to your app carries a physicar_session cookie (AI usage draws on that user's credits):

import base64
from flask import request

@app.post("/ask")
def ask():
    token = request.cookies.get("physicar_session")   # set by signing in to the PhysiCar app
    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": "Is there a person ahead? yes or 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}

Read the token per request

Read the physicar_session cookie from each request — never cache one token globally: on a shared robot, everyone's requests would bill one account.

In the browser too

nginx injects a small helper into every /myapp/ HTML page, so your page's own JavaScript can read the same token with window.physicarSession.token() — no setup.

4. Start it on boot

Put the launch command in /opt/physicar/userdata/myapp.sh:

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

The robot runs this file as a service: if myapp.sh exists at boot, it starts automatically, and output goes to myapp.log next to it. The script does not run from your workspace — use absolute paths inside it. Until your app answers on port 5000, the MYAPP tab shows a "MyApp is not running" page that reloads by itself.

To apply changes without rebooting, use the management API under /settings/myapp (browse it all in /docs — replace the script, delete it, stream the log):

curl -X POST http://localhost:8000/settings/myapp/restart      # also /start, /stop
curl "http://localhost:8000/settings/myapp/log?tail=50"        # read the log

Checklist: app on port 5000, relative paths, launch command in /opt/physicar/userdata/myapp.sh.

🛠 Mission: build a Follow-me or doorway-greeter robot. The same app runs unchanged on a real kit.

Learn more

Robot endpoints → Web API. AI requests → Chat API spec.

AI