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 myapp/ in your workspace (~/physicar_ws) with these files — or ask the Agent to build it (HTML/CSS/JS go in template and static files, not in Python strings):

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

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

@app.route("/")
def home(): return render_template("myapp.html")

@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)
<!-- myapp/templates/myapp.html -->
<link rel="stylesheet" href="./static/style.css">
<button id="forward">Forward</button> <button id="stop">Stop</button>
<p><img src="./photo"></p>
<script src="./static/app.js"></script>
// myapp/static/app.js   (Flask serves myapp/static/ at ./static/)
document.getElementById("forward").onclick = () => fetch("./forward", { method: "POST" });
document.getElementById("stop").onclick = () => fetch("./stop", { method: "POST" });

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. Start it on boot

The startup script /opt/physicar/userdata/startup.sh runs at boot with ~/physicar_ws as the working directory. It starts empty — put your launch command in it:

exec python3 ~/physicar_ws/myapp/app.py

The panel's System tab opens the script (Edit) and its output (Log). A change applies at the next boot — or ask the Agent to restart it. The script runs once: if it exits with code 0 it stays stopped until the next boot; if it exits with an error or dies it is started again (the simulator's supervisord uses autorestart=unexpected with a few retries, the real robot's systemd unit Restart=on-failure after 2 s). That is why the line above says exec — the app is the script, so it stays up as long as it runs. There is no separate setting. Until your app answers on port 5000, the MYAPP tab shows the robot's face — a page that reacts to speed, turning, what the lidar sees and a touch — and reloads into your app by itself.

Checklist: app on port 5000, relative paths, launch command in the startup script.

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

Learn more

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

AI