Skip to content

Commit

Permalink
Added tutorial on ThreadedSubscriptionProducer
Browse files Browse the repository at this point in the history
This makes it easier to see how to use sensors and other external things with RTCBot.

Also fixed a couple little bugs in closing data channels that are being used to send data.
  • Loading branch information
dkumor committed Nov 26, 2020
1 parent 0fe6ae6 commit 2d03ed6
Show file tree
Hide file tree
Showing 28 changed files with 513 additions and 52 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async def index(request):
with open("index.html", "r") as f:
return web.Response(content_type="text/html", text=f.read())

async def cleanup(app):
async def cleanup(app=None):
await conn.close()
camera.close()

Expand Down
10 changes: 5 additions & 5 deletions docs/installing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ Then, you can complete the installation with pip::

sudo pip3 install rtcbot

.. warning::
You might need to reboot your Pi for RTCBot to work! If rtcbot freezes on import, it means that you need to start PulseAudio.

.. note::
It is recommended that you use the Pi 4 with RTCBot. While it was tested to work down to the Raspberry Pi 3B, it was observed to have
extra latency, since the CPU had difficulty keeping up with encoding the video stream while processing controller input.
This is because RTCBot currently cannot take advantage of the Pi's hardware acceleration,
meaning that all video encoding is done in software.

.. note::
You might need to reboot your Pi for RTCBot to work!

.. warning::
These instructions were made with reference to Raspbian Buster.
While the library *does* work on Raspbian Stretch,
you'll need to install aiohttp through pip, and avoid installing opencv.
Expand All @@ -50,8 +50,8 @@ Then, you can complete the installation with pip::

sudo pip3 install rtcbot

.. note::
You might need to reboot, or manually start pulseaudio if it was not previously installed.
.. warning::
You might need to reboot, or manually start PulseAudio if it was not previously installed. If RTCBot freezes on import, it means that PulseAudio is not running.

Mac
+++++++++++
Expand Down
2 changes: 1 addition & 1 deletion docs/javascript.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Next, to establish the connection with Python, you include the Python counterpar
return web.json_response(response)


async def cleanup(app):
async def cleanup(app=None):
if conn is not None:
await conn.close()

Expand Down
1 change: 1 addition & 0 deletions examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ The full code for each of the tutorials can be seen in the `examples directory <
remotecontrol/README.md
mobile/README.md
offloading/README.md
threads/README.md
23 changes: 15 additions & 8 deletions examples/mobile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ async def index(request):
</html>
""")

async def cleanup(app):
async def cleanup(app=None):
global ws
if ws is not None:
c = ws.close()
Expand Down Expand Up @@ -171,10 +171,9 @@ finally:

With these two pieces of code, you first start the server, then start the robot, and finally open `http://localhost:8080` in the browser to view a video stream coming directly from the robot, even if the robot has an unknown IP.


## rtcbot.dev

The above example requires you to have your own internet-accessible server at a known IP address to set up the connection, if your remote code is not on your local network. The server's only real purpose is to help *establish* a connection - once the connection is established, it does not do anything.
The above example requires you to have your own internet-accessible server at a known IP address to set up the connection, if your remote code is not on your local network. The server's only real purpose is to help _establish_ a connection - once the connection is established, it does not do anything.

For this reason, I am hosting a free testing server online at `https://rtcbot.dev` that performs the equivalent of the following operation from the above server code:

Expand Down Expand Up @@ -226,11 +225,12 @@ and the local browser's connection code becomes:

```js
let response = await fetch("https://rtcbot.dev/myRandomSequence11", {
method: "POST",
cache: "no-cache",
body: JSON.stringify(offer)
method: "POST",
cache: "no-cache",
body: JSON.stringify(offer),
});
```

With `rtcbot.dev`, you no longer need your local server code to run websockets or a connection service. Its only purpose is to give the browser the html and javascript necessary to establish a connection. We will get rid of the browser entirely in the next tutorial.

## If it doesn't work over 4G
Expand All @@ -255,6 +255,7 @@ There are two options through which to setup a TURN server: [coTURN](https://git
The Pion server is easy to set up on Windows,Mac and Linux - all you need to do is [download the executable](https://github.com/pion/turn/releases/tag/1.0.3), and run it from the command line as shown.

**Linux/Mac**:

```bash
chmod +x ./simple-turn-linux-amd64 # allow executing the downloaded file
export USERS='myusername=mypassword'
Expand All @@ -264,6 +265,7 @@ export UDP_PORT=3478
```

**Windows**: You can run the following from powershell:

```powershell
$env:USERS = "myusername=mypassword"
$env:REALM = "my.server.ip"
Expand All @@ -272,6 +274,7 @@ $env:UDP_PORT = 3478
```

With the Pion server running, you will need to let both Python and Javascript know about it when creating your `RTCConnection`:

```python
from aiortc import RTCConfiguration, RTCIceServer

Expand All @@ -286,7 +289,7 @@ myConnection = RTCConnection(rtcConfiguration=RTCConfiguration([
var conn = new rtcbot.RTCConnection(true, {
iceServers:[
{ urls: ["stun:stun.l.google.com:19302"] },
{ urls: "turn:my.server.ip:3478?transport=udp",
{ urls: "turn:my.server.ip:3478?transport=udp",
username: "myusername", credential: "mypassword", },
]);
```
Expand All @@ -296,6 +299,7 @@ var conn = new rtcbot.RTCConnection(true, {
Setting up a coTURN server takes a bit more work and is only supported on Linux and Mac. The following steps will assume a Linux system running Ubuntu.
Install coTURN and stop the coTURN service to modify config files with
```bash
sudo apt install coturn
sudo systemctl stop coturn
Expand All @@ -304,6 +308,7 @@ sudo systemctl stop coturn
Edit the file `/etc/default/coturn` by uncommenting the line `TURNSERVER_ENABLED=1`. This will allow coTURN to start in daemon mode on boot.
Edit another file `/etc/turnserver.conf` and add the following lines. Be sure to put your system's public facing IP address in place of `<PUBLIC_NETWORK_IP>`, your domain name in place of `<DOMAIN>`, and your own credentials in place of `<USERNAME>` and `<PASSWORD>`.
```
listening-port=3478
tls-listening-port=5349
Expand All @@ -323,13 +328,15 @@ lt-cred-mech
```
Restart the coTURN service, check that it's running, and reboot.
```bash
sudo systemctl start coturn
sudo systemctl status coturn
sudo reboot
```
With the coTURN server running, you will need to let both Python and Javascript know about it when creating your `RTCConnection`:
```python
from aiortc import RTCConfiguration, RTCIceServer

Expand All @@ -344,7 +351,7 @@ myConnection = RTCConnection(rtcConfiguration=RTCConfiguration([
var conn = new rtcbot.RTCConnection(true, {
iceServers:[
{ urls: ["stun:stun.l.google.com:19302"] },
{ urls: "turn:<PUBLIC_NETWORK_IP:3478?transport=udp",
{ urls: "turn:<PUBLIC_NETWORK_IP:3478?transport=udp",
username: "myusername", credential: "mypassword", },
]);
```
Expand Down
2 changes: 1 addition & 1 deletion examples/mobile/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
global ws
if ws is not None:
c = ws.close()
Expand Down
5 changes: 1 addition & 4 deletions examples/offloading/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ and an average desktop.

The ideal situation would be if you could strap an entire desktop to your robot. With RTCBot, we can do the next best thing: we can stream the robot's inputs to a desktop, which can then perform computation, and send back commands.

In this tutorial, we will go back to a single file for both server and robot for simplicitly. The tutorial is split into two parts. In the first part, we set up a connection to the robot from Python, allowing you to control the robot with an xbox controller without a browser.

The second part of the tutorial adds a neural network into the mix, which tries to imitate the xbox controller's controls.
In this tutorial, we will go back to a single file for both server and robot for simplicitly. We set up a connection to the robot from Python, allowing you to control the robot with an xbox controller without a browser.

```eval_rst
.. note::
Expand Down Expand Up @@ -130,4 +128,3 @@ Control message: {'timestamp': 1553379217.004892, 'code': 'ABS_X', 'state': -125
.. warning::
The output for the `Gamepad` object is currently different in Javascript and in Python. Make sure you don't mix them up!
```

2 changes: 1 addition & 1 deletion examples/offloading/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async def connect(request):
return web.json_response(serverResponse)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()
cam.close()

Expand Down
6 changes: 3 additions & 3 deletions examples/remotecontrol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async def index(request):
</html>
""")

async def cleanup(app):
async def cleanup(app=None):
await conn.close()

app = web.Application()
Expand Down Expand Up @@ -152,7 +152,7 @@ We now add keyboard support. This is done with the `rtcbot.Keyboard` javascript
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()

app = web.Application()
Expand Down Expand Up @@ -349,7 +349,7 @@ async def index(request):
</html>
""")

async def cleanup(app):
async def cleanup(app=None):
await conn.close()

app = web.Application()
Expand Down
2 changes: 1 addition & 1 deletion examples/remotecontrol/gamepad.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()


Expand Down
2 changes: 1 addition & 1 deletion examples/remotecontrol/keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()


Expand Down
2 changes: 1 addition & 1 deletion examples/remotecontrol/rc.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()


Expand Down
2 changes: 1 addition & 1 deletion examples/remotecontrol/skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()


Expand Down
6 changes: 3 additions & 3 deletions examples/streaming/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async def index(request):
</html>
""")

async def cleanup(app):
async def cleanup(app=None):
await conn.close()

app = web.Application()
Expand Down Expand Up @@ -161,7 +161,7 @@ All you need is to add a couple lines of code to the skeleton to get a fully-fun
</html>
""")

async def cleanup(app):
async def cleanup(app=None):
await conn.close()
+ camera.close() # Singletons like a camera are not awaited on close

Expand Down Expand Up @@ -295,7 +295,7 @@ async def index(request):
</html>
""")

async def cleanup(app):
async def cleanup(app=None):
await conn.close()
display.close()
speaker.close()
Expand Down
2 changes: 1 addition & 1 deletion examples/streaming/audiovideo.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()
mic.close()
camera.close()
Expand Down
1 change: 0 additions & 1 deletion examples/streaming/browser_audiovideo.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ async def index(request):


async def cleanup(app=None):
print("CLEANUP")
await conn.close()
display.close()
speaker.close()
Expand Down
2 changes: 1 addition & 1 deletion examples/streaming/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async def index(request):
)


async def cleanup(app):
async def cleanup(app=None):
await conn.close()
camera.close()

Expand Down
Loading

0 comments on commit 2d03ed6

Please sign in to comment.