DuckieTown - Lab 1

"Sleeping Duckies" by Justin Valentine. All rights reserved

Week 2&3 - First lab

After spending a lot of time with the network, Akemi threw in the white flag and overwrote an old MacbookAir6,1 with ubuntu. So the ssh setup is now like:

MacMini8,1 <--- MacbookAir8,2 ---> MacbookAir6,1 ---> duckiebot

Boting around

I’ll be using csc22927 as a hostname, since that was my bot’s hostname

SSH

I started by playing around with the bot over ssh. Even if mDNS isn’t up, we can use the LAN address of the duckiebot to ssh in. For example, something like

ssh [email protected]

Password is quackquack by default, which is shocking hard to type

Using ssh allows us to control docker directly! See the docker section for more on that, though in general it’s far less buggy than dts’s poor python code

DTS

dts proved consistently to be a barrier in the whole process, with some awfully importable code. systemd-networkd’s approach to configuring the networking interfaces prevented SOME dts commands from not working, such as the intrinsics calibration, despite others like the extrinsics calibration working perfectly fine

The first command I learned was a litmus test to determine if mDNS is working (it wasn’t)

dts fleet discover

As a hack around things, if this works for someone else, let them find the ip. Then you can just use the ip address directly… unless dts starts getting in the way. Luckily docker doesn’t care, so generally the ip works just as well

ssh [email protected] ip a

Then came shutting down, which can use the ip address from above, instead of the hostname

dts duckiebot shutdown csc22927

If this doesn’t work, then use the button on the top. When that decides not to work, pull out all 3 micro-usb cables from the main board. That’ll hard-cut the power, so it’s best to not use this method

We can also access gui stuff like the camera with the command below. Note that this actually pulls up a docker container on YOUR laptop, which communicates with the docker container on the bot… There’re a lot of containers… However, this means that it’ll still pull up the container, even if it can’t actually connect to the bot! Make sure you can connect using some other dts command first to not spend minutes instructing a disconnected container to do things

dts start_gui_tools csc22927
rqt_image_view  # This one should pull up a live camera feed

The live camera feed can be configured to show other ros topics, such as the line detector included in the old lane-following demo. You can see it at the end of this video. Notice how the lane following is actually closer to white-line-avoidance, which was the case for the lane following demo prior to updating

BTW, gui tools is an example of a dts command that doesn’t work with the ip address. It also doesn’t work with mDNS enabled, if the network interface was configured by systemd-networkd

Here’s a complete reference of every dts command I ran in the past 3 weeks! It served as my live-updating cheatsheet while working on this lab, through a clever .inputrc trick with fzf and an unlimited bash_history file size

Driving around

Before getting the MacbookAir6,1, I could only use the cli version of movement keys. The command looked like

dts duckiebot keyboard_control --cli csc22927

Interestingly, in the cli mode, the correct way to stop is <enter> not e<enter>. I found this by accident, though it’s certainly accurate. Here’s my bot traveling forward for a bit, using the cli mode

With the MacbookAir6,1 booting ubuntu, I was able to get the cli working! Just drop the --cli above

After an update, launching a separate container, and the graphical joystick on the MacbookAir6,1, I was in the first duckies in the class to get a proper lane-following demo running!

dts duckiebot update csc22927  # This takes ~30min
dts duckiebot demo --demo_name lane_following --duckiebot_name csc22927.local --package_name duckietown_demos
ssh [email protected] docker container list  # Just to check if it's acc running the container
dts duckiebot keyboard_control --cli csc22927

Dashboard

There’s a dashboard! Connect to it at http://csc22927.local or the ip directly in a browser. It has a live camera feed and sensor signals. Here’s a dashboard with my bot driving forward in a straight line

Motors of duckiebot driving forward, as seen from the dashboard

Notice how the angular speed is 0. That’s since it’s not turning. Below is a picture of it spinning in a circle, now with no forward velocity

Motors of duckiebot spinning in a circle, as seen form the dashboard

You can also login using your duckietown account

  1. Login @ https://www.duckietown.org/pm_login
  2. Navigate to https://www.duckietown.org/site/your-token and login with that

Then a lot more tabs pop up. One of them is for browsing files, though ssh already let us do that. The new one is a VNC server. Click into the desktop tab and wait a minute or so for it to launch. This is a full desktop running on the duckiebot! Of course things like the gui joystick work there, even on my Waybook that could only use the cli version otherwise

Docker

Docker keeps making new containers, nearly daily. These can end up polluting the system. Use docker container list -a to view them and docker-system-prune(1) to remove them

docker system df
docker image ls
docker image prune -a

In general, it’s better to use docker-compose with docker, since it’s so clean

docker compose up -d

Alternatively you can just run the container and ^p^q to detach it

docker run --rm -it <container-name>

You can then execute commands using new terminal connections on the running container

docker exec <container-id> ip a
docker exec <container-id> -it bash

I generally find these commands useful too

systemctl start docker.service
docker ps
docker image ls
docker image rm <image>
docker container ls
docker container attach <container>

Docker vision system

Found in section B-5 this was undoubtedly the hardest part of this project

The instructions skip over the obvious fact that we’ll need a virtual environment for this

python3 -m venv .

Next we need some packages in our requirements.txt

source bin/activate
pip install numpy opencv-python
pip freeze > requirements.txt

Then we use docker to build and run on the duckiebot. Note that since this isn’t dts we could just as easily use the duckiebot’s ip directly instead of relying on an mDNS server

docker -H csc22927.local build -t colordetector:v4 .
docker -H csc22927.local run -it --privileged -v /tmp/argus_socket:/tmp/argus_socket colordetector:v4

Either way, despite 26 iterations of the code and a lot of debugging by many members in the class, the duckiebot’s camera refused to connect, even with a fixed gst pipeline

gst_pipeline = f'''nvarguscamerasrc ! \\
    sensor-mode={camera_mode}, exposuretimerange="100000 80000000" ! \\
    video/x-raw(memory:NVMM), width={res_w}, height={res_h}, format=NV12, framerate={fps}/1 ! \\
    nvjpegenc ! \\
    appsink'''

Thanks to Steven Tang who discovered there’s a cli tool to verify if our gst-pipeline is correct. I verified the following pipeline, which claimed to work, though wasn’t able to communicate with the duckiebot’s camera in python. You’ll need to use escapes to prevent bash from interpreting things, though the codeblock below escaped the \", \(, and \)

gst-launch-1.0 nvarguscamerasrc sensor-mode=3 exposuretimerange="100000 80000000" \\
    ! video/x-raw\(memory:NVMM\), width=1280, height=720, \
    format=NV12, framerate=30/1 \
    ! nvjpegenc ! appsink

Networking adventures

Continued from the previous post

Breakthrough 2 - Use NetworkManager instead

dts fleet discover and .local resoultion fails with the systemd-networkd + iwd combo. mDNS appears broken again. Instead use NetworkManager… except NetworkManager doesn’t see DuckieNet, so the steps look like:

  1. Boot with NetworkManger configing the device
  2. Start both systemd-networkd and iwd
  3. Restart systemd-networkd to give iwd configuration permissions
  4. Scan for DuckieNet
  5. Connect to DuckieNet
  6. Send a stop signal to systemd-networkd and iwd twice
  7. Start NetworkManager

Or in short

systemctl stop NetworkManager.service
systemctl start systemd-networkd iwd
systemctl restart systemd-networkd
iwctl station wlan0 scan && sleep 3
iwctl station wlan0 connect DuckieNet
systemctl stop systemd-networkd iwd
systemctl stop systemd-networkd iwd
systemctl start NetworkManager.service

Breakthrough 3 - Give systemd-networkd full control

For the third time, there may be another issue. NetworkManager seems to start up wpa_supplicant.service, regardless of it being disabled in systemd. However, it still appears to run after NetworkManager is stopped. This means when we start up both systemd-networkd and iwd, there are 3 programs attempting to configure wlan0 at the same time. Stopping wpa_supplicant explicitly appears to have brought back mDNS support through systemd-networkd, only if systemd-networkd is allowed to configure the device itself

Also, using systemd-networkd for the connection is a lot more stable than NetworkManager, which would drop the connection every few minutes and require a restart to fix

Breakthrough 4 - Give systemd-resolved full DNS control

OMG. Okay, following the archwiki’s article for resolved, it’s clear:

  1. Avahi will fight with systemd-resolved for mDNS control, so disable Avahi
  2. MulticastDNS under wlan0’s [Network] needs to be enabled. I used =resolve

I further found:

  1. It’s helpful to throw Multicast=true in the [Link] section of wlan0
  2. Run dhcpc.service… tho still let iwd configure the device. Not sure why
  3. In /var/lib/iwd/*.* put AutoConnect=true under [Settings]. Otherwise it guesses the network

We expect networkctl to say wlan0 is “routable” and “configuring”. Journalctl states dhcpcd only acquired the carrier for wlan0 4s after loading, while iwd doesn’t mention anything about wlan0, though finished all its confings 4s prior to dhcpcd’s acquisition

When booting with all 3 services enabled, restart systemd-networkd. networkctl should now show both “routable” and “configured”

For some commands it works, like dts start_gui_tools and dts duckiebot shutdown, though others are just not happy, like dts duckiebot calibrate_intrinsics and dts duckiebot keyboard_control. I’m now borrowing a MacbookAir6,1 from the university to get around these issues