Donkey Car — Part Three: The Noob’s Guide to Configuring the Nano for Headless Operation

Cyrus Beh
5 min readJun 2, 2019

--

In the previous posts, I discussed the plan to develop a Donkey Car that can be trained on the Jetson Nano, and also discussed how to install the components needed for the Jetson Nano to run the project (Update on May 1st 2019: Now with more detailed instructions). In this post, I want to discuss something that I neglected until these past two days — How to set up the Jetson for a training or driving session.

Headless Operation

I had some prior experience with so-called headless operation — running a computer without input devices or a monitor. My previous project on the security PiCam did exactly that. However, this was pretty straightforward since the Raspberry Pi OS (Raspbian) perfectly streamlined the process, making it very painless. While the Ubuntu distro on the Nano is no slouch, it is a more conventional Linux OS installation, making the process a bit more cumbersome.

The first step was to install VNC server onto the Nano. To do that, simply use

sudo apt-get install tightvncserver

After this, calling vncserver will create an instance of the workspace, denoted by a single number (i.e. workspace 1, 2, etc). To kill an instance, simply execute

vncserver -kill :X

where X is the workspace number you want to kill. There are some options for setting the geometry of the workspace, but I will skip those here. If interested, do read up!

Typically, connecting to a workspace is a simple matter of looking up the host IP address using ifconfig, and logging on using a client in the format, for example, 192.168.0.15:1 to connect to workspace #1 on a computer with the local IP 192.168.0.15. Attempting to connect to the Nano in this fashion resulted in a screen, without any menus or taskbars. After a few hours of struggling, I guessed that perhaps the GNOME desktop is not loading properly. I installed the lightweight Xfce instead, using the following command:

sudo apt-get install -y xfce4 xfce4-goodies

After this, the workspace loaded correctly on the client. Phew!

Configuring the IP Address

In order for a connection to be perpetually accessible, the IP address must not change. However, a normal connection to a router involves the DHPC, which assigns IP addresses randomly. To get a fixed, or static IP, one can simply log on to the router, and fix the IP for a given MAC address (which is the unique identifier for each network adapter). However, in this case, I mean for the Nano to be trained outdoors, where an active WiFi network may not be available. This meant that I had to create a wireless network using the wireless network adapter. I created an ad hoc network and connected my iPad to it. Now, a word on how amazing this is: just 10–15 years ago, getting a wireless adapter to work with Linux may have taken the better part of a week, since there was never any guarantee that a driver would exist. What invariably happened was a series of back and forth, checking forums for possible clues, figuring out the actual chipset manufacturer for a particular adapter, etc. Now, I just plugged my cheap WiFi adapter on, and voilà! A simple GUI interface to set everything up.

Except it wasn’t that simple. After setting up the connection, and forcing a static IP on the Nano (i.e. host), my iPad refused to connect to the Nano. I spent two days trying to figure this out, trying all sorts of combinations. The only time a connection worked was when I set the thing to “Link-Local Only”, which did not allow me to specify the IP address, and which I suspect will randomly assign one after some time (I only tested this for a few hours at a time). Finally, after exhausting all my other options, a thought came to my mind — when assigning IP addresses to computers on the local network, it is normal for the IP address to be the same except for the least significant octet. Checking the setting on the iPad, I realized that the ad hoc network was automatically assigning addresses to the iPad, and that the entire four-octet set was different. So, I proceeded to re-configure the network with manual IPs for both the host and client, and finally, we have lift-off. I put all of this down to the fact that I have never configured an ad hoc connection before, and would not be an issue to anyone with even an ounce of experience.

Starting up VNC Automagically

The last piece of this puzzle was to get VNC to start up automatically. I’d done this with the Security PiCam before, so I know this can be done. However, for the life of me, I couldn’t get it to work with Ubuntu. For example, probably due to the way different distros handle their files and start-up procedures, there were many dead-ends in the forums, such as “edit /etc/rc.local”, where the file does not exist (possibly due to the use of systemd in Ubuntu). Ultimately, I found this suggestion for Ubuntu:

  1. Install the VNC server.
  2. Launch vncserver for the first time to set up a password.
  3. Add the following file as /etc/init.d/vncserver (be sure to modify the USER, GEOMETRY, NAME, etc. to your liking).
#!/bin/sh -e
### BEGIN INIT INFO
# Provides: vncserver
# Required-Start: networking
# Default-Start: S
# Default-Stop: 0 6
### END INIT INFO

PATH="$PATH:/usr/X11R6/bin/"

# The Username:Group that will run VNC
export USER="mythtv"
#${RUNAS}

# The display that VNC will use
DISPLAY="1"

# Color depth (between 8 and 32)
DEPTH="16"

# The Desktop geometry to use.
#GEOMETRY="<WIDTH>x<HEIGHT>"
#GEOMETRY="800x600"
GEOMETRY="1024x768"
#GEOMETRY="1280x1024"

# The name that the VNC Desktop will have.
NAME="my-vnc-server"

OPTIONS="-name ${NAME} -depth ${DEPTH} -geometry ${GEOMETRY} :${DISPLAY}"

. /lib/lsb/init-functions

case "$1" in
start)
log_action_begin_msg "Starting vncserver for user '${USER}' on localhost:${DISPLAY}"
su ${USER} -c "/usr/bin/vncserver ${OPTIONS}"
;;

stop)
log_action_begin_msg "Stoping vncserver for user '${USER}' on localhost:${DISPLAY}"
su ${USER} -c "/usr/bin/vncserver -kill :${DISPLAY}"
;;

restart)
$0 stop
$0 start
;;
esac

exit 0

4. sudo update-rc.d vncserver defaults

5. sudo chmod +x /etc/init.d/vncserver

Which did not work. Apparently this approach has been deprecated (?), and when the following command

systemctl status vncserver

is run after boot-up, it returns that the service is loaded, generated, but Inactive (dead). If I were to run the service at the terminal, after entering the password the server would start correctly. I even tried to rename the service, convinced as I was that the name may have been used for the TightVNC Server itself. No dice.

Finally, I came across a single post that indicated that this way of initiating the service is obsolete, and may face problem since the root privileges require password entry, which does not happen at startup. Instead, one was to create a service, by running

sudo nano /etc/systemd/system/vncserver@.service

which contains the following lines:

[Unit]
Description=Start TightVNC server at startup
After=syslog.target network.target
[Service]
Type=forking
User=sammy
Group=sammy
WorkingDirectory=/home/sammy
PIDFile=/home/sammy/.vnc/%H:%i.pid
ExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1
ExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 :%i
ExecStop=/usr/bin/vncserver -kill :%i
[Install]
WantedBy=multi-user.target

(replacing “sammy” with the user name). Enabling the service as below (where “1” is the workspace identifier) makes it run on bootup:

sudo systemctl enable vncserver@1.service

And just like that, we have ourselves a headless Nano. Works every time.

Conclusion

This part is probably more difficult that it needed to be, since I am unfamiliar with Linux. However, I will say that every time I use Linux, my understanding of how computers work increases. So, despite all the frustration, in retrospect, this was a rather enriching experience. In the next part, I will talk about getting data from sensors. Stay tuned!

--

--

Cyrus Beh

I’m a biomedical engineer who dabbles in hobbyist electronics, programming, crafting, woodworking, and photography. I write stuff for absolute noobs like myself