Raspberry + QEMU – Bash scripts to manage Virtual and SDCard OS images

Raspberry

Introduction:

Raspberry Pi is a very popular development platform based on ARM processors. Recently a fantastic IMU/GPS combo shield was released for such platform by EMLID. While source code of several components is available by their git-hub, additional software components (for example ROS) could be interesting to develop your robotic application… As first step, to get confident with the Raspberry environment, my personal suggestion consists into running the Raspbian (the Raspberry operating system) through an emulator, for example QEMU.

In this article, we are going to show how to download, setup and manage Raspbian images with Ubuntu and QEMU. For your convenience, all the steps are combined into bash scripts. You may download freely and without any warranty.

Because the robotic platform developed by our group is named CalaTronics you may find some reference to this name in the script logs 🙂

1) Downloading the EMLID image of Raspbian: getRTRpi.sh


#!/bin/bash

echo "Downloading kernel-qemu"
wget http://xecdesign.com/downloads/linux-qemu/kernel-qemu

echo "Downloading image"
wget http://emlid.com/files/Raspbian-SEP-2014-RT-B+.img.tar.bz2 -c

echo "Unzipping image"
tar jxvf Raspbian-SEP-2014-RT-B+.img.tar.bz2

echo "Renaming image"
mv Raspbian-SEP-2014-RT-B+.img ccrpi.img

echo "Cleaning up"
rm -f Raspbian-SEP-2014-RT-B+.img.tar.bz2

Once that this file is executed, you should find two new files named ccrpi.img and kernel-qemu.

Note that you may want to adjust some of the links in case are corrupted or updated.

2) Initialize the image by adjusting some of the default params: initrpi.sh

#!/bin/bash
echo -en "\ec"
echo
echo "CalaTronics Init RPi Firmware Manager"
echo

if [ -z $1 ];
then
	echo
	echo "Use initrpi.sh file.img"
	echo
	echo "    file.img is the RPi image"
	echo
	exit
fi	

if [ ! -f $1 ];
then
	echo "Invalid image file."
	echo
	exit
fi

IMG_DEV="$1"
MEMORY="256"

echo "Selected Image : ${IMG_DEV}"

echo "Login/Password should be pi/raspberry"
echo
echo "a) /etc/ld.so.preload"
echo "   comment #/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so"
echo
echo "b) /etc/udev/rules.d/90-qemu.rules"
echo "   KERNEL==\"sda\", SYMLINK+=\"mmcblk0\""
echo "   KERNEL==\"sda?\", SYMLINK+=\"mmcblk0p%n\""
echo "   KERNEL==\"sda2\", SYMLINK+=\"root\""
echo
echo "c) /etc/network/interfaces"
echo "	 auto eth0"
echo "   iface eth0 inet static"
echo "         address 10.0.0.2"
echo "         network 10.0.0.0"
echo "         netmask 255.255.255.0"
echo "         broadcast 10.0.0.255"
echo "         gateway 10.0.0.1"

echo
echo "Running initial"
echo
sudo qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m ${MEMORY} -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw init=/bin/bash" -hda ${IMG_DEV} 

echo

All the necessary steps and instructions required to adjust the default parameters will be displayed on the screen. Just do it…

In case you are not familiar with these instructions, we are going to comment out a library link, change some udev options and fix the ethernet address to 10.0.0.2.

3) Manage the images: ccrpi.sh

One important, sometime required, step during development is to make periodic updates. You may consider to develop on your emulator or directly on the Raspberry… it is your choice. But how to keep this two deviced (virtual/real) synchronized?

A possible solution is to run the SD card image of the Raspberry through the emulator. Then each modification will be done on the SD card and the Raspberry will use the fresh image.

Another possibility is to work without SD card and flash it when necessary (for example using dd).

We made a simple script which will provide you all these options: the ccrpi.sh.

#!/bin/bash
echo -en "\ec"
echo
echo "CalaTronics RPi Firmware Manager"
echo

if [ -z $1 ];
then
	echo
	echo "Use ccrpi.sh file.img [/dev/sdX]"
	echo
	echo "    file.img is the RPi image"
	echo "    /dev/sdX is the (optional) device to perform firmware operations"
	echo
	exit
fi	

if [ ! -f $1 ];
then
	echo "Invalid image file."
	echo
	exit
fi

IMG_DEV="$1"
MEMORY="256"
HOST_IP="10.0.0.1"
HOST_NET="10.0.0.0/8"
HOST_PORT="2222"
GUEST_PORT="22"
GUEST_IP="10.0.0.2"

echo "Selected Image : ${IMG_DEV}"

if [ -z $2 ];
then
	echo
	echo "Pure simulation mode active"
	echo "Running CalaTronics SD (Firmware) [${HOST_IP}:${HOST_PORT}->${GUEST_IP}:${GUEST_PORT}]"
	echo
	sudo qemu-system-arm \
		-kernel kernel-qemu -cpu arm1176 -m ${MEMORY} -M versatilepb -no-reboot -serial stdio \
		-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda ${IMG_DEV} -net nic -net user,net=${HOST_NET},host=${HOST_IP},hostfwd=tcp:127.0.0.1:${HOST_PORT}-${GUEST_IP}:${GUEST_PORT}
        exit
fi	

echo "Device: ${SD_CARD} SELECTED"

echo "Device: $2"
if [[ $2 =~ (/dev/.+) ]]; then
	echo "Device: $1 PATH OK"
else
	echo "Device: $1 PATH INVALID"
	echo "Use ccrpi.sh /dev/sdX"
	exit;
fi

if [[ $2 =~ .*[^0-9]$ ]]; then
	echo "Device: $1 DEVICE OK"
else
	echo "Device: $1 DEVICE INVALID"
	echo "Use ccrpi.sh /dev/sdX"
	exit;
fi

SD_CARD="$2"

echo
echo "Check SD Card: ${SD_CARD}"

sudo fdisk -l ${SD_CARD} | grep ${SD_CARD}

echo
echo "Choosing the wrong HD could cause data loss."
echo
read -p "Continue (y/n)? " choice
case "$choice" in
  y|Y ) ;;
  n|N ) echo "If the device is wrong, select a new one."
	exit;;
    * ) echo "No option was selected, aborting."
	exit;;
esac

echo
echo "Select the operation:"
echo
echo "1) IMG -> SD  (Flash)"
echo "2) SD  -> IMG (Backup)"
echo "3) Run    IMG (Simulator)"
echo "4) Run    SD  (Firmware)"

echo
read -p "?> " choice
echo
case "$choice" in
  1 )
	if [ -f ${IMG_DEV} ];
	then
		echo "Flashing CalaTronics Firmware"
		echo
		echo "> dd bs=1M if=${IMG_DEV} of=${SD_CARD}"
		sudo    dd bs=1M if=${IMG_DEV} of=${SD_CARD}
	else
		echo "ERROR: CalaTronics Firmware not available offline (${IMG_DEV})."
	fi
	;;
  2 )
	echo "Saving   CalaTronics Firmware"
	echo
	echo "> dd bs=1M if=${SD_CARD} of=${IMG_DEV}"
	sudo    dd bs=1M if=${SD_CARD} of=${IMG_DEV}
	;;
  3 )
	echo "Running CalaTronics IMG (Simulator) [${HOST_IP}:${HOST_PORT}->${GUEST_IP}:${GUEST_PORT}]"
	echo
	sudo qemu-system-arm \
		-kernel kernel-qemu -cpu arm1176 -m ${MEMORY} -M versatilepb -no-reboot -serial stdio \
		-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda ${IMG_DEV} -net nic -net user,net=${HOST_NET},host=${HOST_IP},hostfwd=tcp:127.0.0.1:${HOST_PORT}-${GUEST_IP}:${GUEST_PORT}
	;;
  4 ) 	echo "Running CalaTronics SD (Firmware) [${HOST_IP}:${HOST_PORT}->${GUEST_IP}:${GUEST_PORT}]"
	echo
	sudo qemu-system-arm \
		-kernel kernel-qemu -cpu arm1176 -m ${MEMORY} -M versatilepb -no-reboot -serial stdio \
		-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda ${SD_CARD} -net nic -net user,net=${HOST_NET},host=${HOST_IP},hostfwd=tcp:127.0.0.1:${HOST_PORT}-${GUEST_IP}:${GUEST_PORT}
	;;
  * ) 	echo "No option was selected, aborting."
	exit;;
esac
echo

If you already perform an initialization through the previous scripts, you may consider to flash the SD card with the image (you have in your PC).

4) Connecting to the Emulator!

Once you run the image with the simulator (by NOT passing the device option to the ccrpi.sh or by selecting the mode 3/4) you may want to connect to the system using ssh…

#!/bin/bash
echo -en "\ec"
echo
echo "CalaTronics RPi Firmware SSH Connection"
echo

echo "Login:    pi"
echo "Password: raspberry"

HOST_PORT="2222"

echo
ssh -lpi 127.0.0.1 -p${HOST_PORT}

Note that the selected SSH host is localhost while the port is 2222. This port forward rule is the result of the ccrpi.sh script options.

5) Enjoy your Raspberry Emulator!

Hope you enjoyed this fantastic journey into emulators, images and bash scripts… Now you are ready for a new challenge… install ROS??

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.