[Beagleboard] A 36km High Altitude Payload with Live Images

I am happy to announce that the BeagleBoard survives fine in zero pressure, low temperature environments like 36km up in the sky. For a project, i have sent the BeagleBoard up there, taking pictures and sending them live through a simple, small, radio transmitter. In this post i will try to show what it did, how to make it, including some pictures, scripts and other stuff i have used.

The ‘Space Camera Live 1’ project itself

This article is about the Main Payload used in this project. I advise you first to checkout what this project was about, by clicking on the Space Camera Live 1 link.

me with the Flight computer

Beagleboard and its parts

To power the beagleboard, i made a proper “Beagle Battery” module. How i made that or make it youself you can read that here.
To use the GPS/GPRS system on the beagleboard, i made a proper module that you can read about and make yourself here.

Overview of the internals

Insides of the main payload

The outsides

An overview (after launch)

Some other parts i have written about seperately:

Making a proper antenna.
Making a ‘hot-wire’ cutdown mechanism.
Cutting your styrofoam.

Downloads & Scripts

For all the scripts i have used, there is only one really important external one.
SSDV Script [external, github].

Script structure

loopall.sh

This script was invoked at startup by cron.

  1. #!/bin/bash
  2. #(C) Tim Zaman 2011
  3. cd /home/ubuntu
  4. bash catloop.sh & bash snaploop.sh & bash sendloop.sh

catloop.sh

This script syphoned off the GPS info and the Battery status.

  1. #!/bin/bash
  2. #Project Space Camera Live
  3. #(c) Tim Zaman 2011
  4. # catloop.sh
  5.  
  6. OLDIFS=${IFS}
  7.  
  8. BATDEV="/dev/BAT"
  9. GPSDEV="/dev/GPRS"
  10. GPSLOG="/dev/shm/gps.log" #Logs to RAM
  11. GPSLOGRAW="/home/ubuntu/gpsraw.log"
  12. #BATLOGRAW="/home/ubuntu/batraw.log"
  13. typeset -u CHECKSUM #Anything stored in Checksum var will be uppercase
  14.  
  15. stty -F $GPSDEV 115200 raw crtscts
  16. stty -F $BATDEV 9600 raw
  17.  
  18. echo "AT#STARTMODESCR=1,10" > $GPSDEV
  19. sleep 1s
  20. echo "AT#EXESCR" > $GPSDEV
  21.  
  22. NR=1
  23. ONE=1
  24. COM=","
  25. VAVG=0 #preallocate average mV
  26.  
  27. while [ 1 ]
  28. do
  29.  
  30. 	let NR=$NR+$ONE
  31. 	GPSSTR=""
  32. 	BATSTR=""
  33.  
  34. 	#Battery...
  35. 	#timeout 10s cat $BATDEV | tee -a $BATLOGRAW | head -n1 > "/dev/shm/bat.str"
  36. 	timeout 10s cat $BATDEV | head -n1 > "/dev/shm/bat.str"
  37. 	BATSTR=`cat "/dev/shm/bat.str" | tr -d 'n' | tr -d 'r'`${COM}
  38. 	echo " raw bat: "$BATSTR
  39. 	if [ ${#BATSTR} -gt 10 ]
  40. 	then
  41. 		IFS=","
  42. 		set -- $BATSTR
  43. 		IFS=${OLDIFS}
  44.  
  45. 		TIMEBAT=$1
  46. 		VBAT1=$2
  47. 		VBAT2=$3
  48. 		VBAT3=$4
  49. 		VBAT4=$5
  50. 		TEMPB=$6 #deoesnt get filled in?
  51. 		let VAVG=($VBAT3+$VBAT4)/2
  52. 		if [ "$TEMPB" -ge "90" ]
  53. 		then	#Incorrect measurement so 0
  54. 			TEMPB="0"
  55. 		fi
  56. 	fi
  57.  
  58. 	#GPS...
  59. 	#timeout 10s cat $GPSDEV | tee -a $GPSLOGRAW | grep --text --line-buffered "GPSACP" | head -n1 > "/dev/shm/gps.str"
  60. 	timeout 10s cat $GPSDEV | grep --text --line-buffered "GPSACP" | head -n1 > "/dev/shm/gps.str"
  61. 	GPSSTR=`cat "/dev/shm/gps.str" | tr -d 'n' | tr -d 'r'`${COM}
  62.  
  63. 	GPSSTR=$(echo $GPSSTR|sed 's/ /,/g') #replace " " with ","
  64. 	echo " raw gps: "$GPSSTR
  65. 	if [ ${#GPSSTR} -gt 50 ]
  66. 	then
  67. 		IFS=","
  68. 		set -- $GPSSTR
  69. 		IFS=${OLDIFS}
  70.  
  71. 		TIME=$2
  72. 		LAT=$3
  73. 		LON=$4
  74. 		ALT=$5
  75. 		FIX=$6
  76. 		COURSE=$8
  77. 		SPD=$9
  78. 		DATE=${11}
  79. 		SAT=${12}
  80. 		SAT=`echo ${SAT#0}` #remove leading zeros
  81.  
  82. 		#Convert time and altitude
  83. 		TIME1=${TIME:0:2}
  84. 		if [ $TIME1 -lt "22" ]
  85. 		then
  86. 			TIME1=$((TIME1+2))
  87. 		else #Later than 22hr
  88. 			TIME1="0"$((TIME1-22))
  89. 		fi
  90.  
  91.  
  92. 		TIME=$TIME1":"${TIME:2:2}":"${TIME:4:2}
  93. 		ALT=`echo $ALT | cut -d '.' -f1` #Round off altitude
  94.  
  95. 		#Convert Latitude
  96. 		LAT1=${LAT:0:2}
  97. 		LAT1=`echo $((LAT1))`
  98. 		LAT2=`echo "scale=4 ; ${LAT:2:7} / 60" | bc`
  99. 		LAT2=`echo $LAT2`
  100. 		LAT2=${LAT2:1:6}
  101. 		LATCHAR=${LAT:9:1}
  102. 		LAT=$LAT1"."$LAT2
  103. 		if [ $LATCHAR = 'S' ]
  104. 		then #South is negative
  105. 			LAT="-"$LAT
  106. 		fi
  107.  
  108. 		#Convert Longitude
  109. 		LON1=${LON:0:3}
  110. 		LON1=`echo $((LON1))`
  111. 		LON2=`echo "scale=4 ; ${LON:3:7} / 60" | bc`
  112. 		LON2=`echo $LON2`
  113. 		LON2=${LON2:1:6}
  114. 		LONCHAR=${LON:10:1}
  115. 		LON=$LON1"."$LON2
  116. 		if [ $LONCHAR = 'W' ]
  117. 		then #West is negative
  118. 			LON="-"$LON
  119. 		fi
  120.  
  121. 		SENTENCE="PD4TA,"$NR$COM$TIME$COM$LAT$COM$LON$COM$ALT$COM$SAT$COM$TEMPB$COM$VAVG
  122. 		CHECKSUM=`java CRC16CCITT $SENTENCE`
  123. 		CHECKSUM=`printf "%04X" 0x$CHECKSUM`
  124. 		SENTENCE="$$"$SENTENCE"*"$CHECKSUM
  125.  
  126. 		echo $SENTENCE > $GPSLOG #Write to RAM
  127. 		echo $SENTENCE >> $GPSLOGRAW #Write to file as well
  128. 		echo $SENTENCE
  129. 	fi
  130. done

snaploop.sh

This script made the webcam snap images and giving them a rating (score).

  1. #!/bin/bash
  2. #Project Space Camera Live
  3. #(c) Tim Zaman 2011
  4. # snaploop.sh
  5. # run as sudo!
  6.  
  7. SWIT=1
  8. FIVE=5
  9. CAPTX=800
  10. CAPTY=600
  11. ##SENDX=240
  12. ##SENDY=176
  13. VIDDEV="/dev/video0"
  14. DIRIMGRAM="/dev/shm/snaps/raw/"
  15. DIRIMGMMC="/home/ubuntu/snaps/raw/"
  16. #DIRIMGSM="/home/ubuntu/snaps/small/"
  17. DIRIMGNEW="/dev/shm/snaps/new/"
  18. #DIRREJECT="/home/ubuntu/snaps/rejected/"
  19. mkdir "/dev/shm/snaps/"
  20. mkdir $DIRIMGRAM
  21. mkdir $DIRIMGNEW
  22.  
  23. uvcdynctrl --d /dev/video0 --set="Exposure, Auto Priority" 0
  24.  
  25. while [ 1 ]
  26. do
  27. 	#if [ $SWIT = $FIVE ] #Once in 5 snaps its a large capture
  28. 	#then
  29. 	#	#CAPTX=1600;CAPTY=1200 #huge problems with the webcam mangling the image
  30. 	#	SWIT=1 #Set back to 1
  31. 	#else
  32. 	#	CAPTX=800; CAPTY=600
  33. 	#	let "SWIT = SWIT + 1" #Iterate..
  34. 	#fi
  35.  
  36. 	filename=`date +"%H%M%S"`".jpg"
  37. 	FILEIMG=$DIRIMGRAM$filename
  38. 	##FILEIMGSM=$DIRIMGSM$filename
  39. 	echo "Snap[x,y]=["$CAPTX","$CAPTY"]"
  40. 	##echo "Send[x,y]=["$SENDX","$SENDY"]"
  41.  
  42. 	#Resize captured image and move to small folder
  43. 	uvccapture -o$FILEIMG -d$VIDDEV -x$CAPTX -y$CAPTY -m #-w #-w doesnt help with the wrong images
  44. 	##convert $FILEIMG -resize "$SENDX"x"$SENDY"^
  45.         ##  -gravity center -extent "$SENDX"x"$SENDY" $FILEIMGSM
  46.  
  47.  
  48. 	SCORE=`bash imgscore.sh $FILEIMG`
  49. 	SCORE=`printf "%03i" $SCORE`
  50. 	echo "Score = "$SCORE
  51.  
  52. 	#FILESDIRNEW=`ls $DIRIMGNEW | wc -l`
  53. 	#if [ ${FILESDIRNEW} -gt 4 ] #this was used in the "best of 5 latest" method. unused.
  54. 	#then #Too many files, remove one then copy
  55. 	#	echo "Too many images in new folder, deleting oldest.."
  56. 		#Now remove the oldest:
  57. 	#	mv $DIRIMGNEW`ls -tr $DIRIMGNEW | head -1 | tr -d "nr"` $DIRREJECT
  58. 	#fi
  59.  
  60. 	#Then copy from small folder to new fo lder and prepend score
  61. 	##cp $FILEIMGSM $DIRIMGNEW$SCORE"-"$filename
  62. 	cp $FILEIMG $DIRIMGNEW$SCORE"-"$filename #Copy image to "new" folder
  63. 	cp $FILEIMG $DIRIMGMMC$SCORE"-"$filename #Also copy to MMC
  64. 	rm $FILEIMG #Then remove the image to make some file in the RAM
  65. 	echo "*****"
  66. 	sleep 1s
  67. done

sendloop.sh

This script took care of choosing the image, decoding it, splitting it, and sending it out to the radio.

  1. #!/bin/bash
  2. #Project Space Camera Live
  3. #(c) Tim Zaman 2011
  4. # sendloop.sh
  5.  
  6. USBDEV="/dev/FTDI5V"
  7. VIDDEV="/dev/video0"
  8. DIRIMG="/dev/shm/snaps/new/"
  9. DIRSENT="/dev/shm/snaps/sent/"
  10. DIRREJECTED="/dev/shm/snaps/rejected/"
  11. DIRSPLITS="/dev/shm/splits/"
  12. mkdir "/dev/shm/snaps/"
  13. mkdir $DIRSPLITS
  14. mkdir $DIRSENT
  15. mkdir $DIRIMG
  16. mkdir $DIRREJECTED
  17.  
  18. sleep 5 #wait for images to be taken
  19.  
  20. NR=0
  21. ONE=1
  22. FIVE=5
  23. TEN=10
  24. SWIT=1
  25.  
  26. SENDX=320
  27. SENDY=240
  28. BAUDRATE=600
  29.  
  30.  
  31. stty -F $USBDEV $BAUDRATE raw cstopb
  32.  
  33. while [ 1 ]
  34. do
  35.  
  36.  
  37. 	IMGAMOUNT=`ls $DIRIMG | wc -l`
  38.  
  39.  	if [ "$IMGAMOUNT" -eq "0" ] #If there is no image in new folder so sent the latest..
  40. 	then
  41. 		echo "No images detected. Choosing most recent reject.."
  42. 		filename=`ls -t $DIRREJECTED | head -1 | tr -d "nr"`
  43. 		FILEIMG=$DIRREJECTED$filename
  44. 		echo "Recent folder empty, possible camera error :(" >> $USBDEV
  45. 	else #There are sufficient current (new) images so sent the best
  46. 		echo "Choosing from "$IMGAMOUNT" images.."
  47. 		filename=`ls $DIRIMG | head -1 | tr -d "nr"`
  48. 		FILEIMG=$DIRIMG$filename
  49. 	fi
  50.  
  51. 	if [ $SWIT = $TEN ] #send a big one every 10 images at 1200bd
  52. 	then
  53. 		sleep 3
  54. 		BAUDRATE=1200
  55. 		SENDX=800; SENDY=576
  56. 		SWIT=1 #Set back to 1
  57. 		sleep 3
  58. 	else
  59. 		BAUDRATE=600
  60. 		SENDX=320; SENDY=240
  61. 		let "SWIT = SWIT + 1" #Iterate..
  62. 	fi
  63.  
  64. 		echo "!!! NEXT ONE @ "$BAUDRATE"BAUD, CYCLE "$SWIT"/"$TEN" !!!" >> $USBDEV
  65.  
  66. 	#Now convert image size
  67. 	convert $FILEIMG -resize "$SENDX"x"$SENDY"^
  68.           -gravity center -extent "$SENDX"x"$SENDY" $FILEIMG
  69.  
  70. 	echo "Baudrate="$BAUDRATE
  71. 	echo "Image Nr: "$NR
  72. 	echo "Sending image:"$FILEIMG
  73. 	echo "Sendsize [x,y]=["$SENDX","$SENDY"]"
  74.  
  75.  	if [[ $FILEIMG == *.jpg ]]
  76. 	then
  77. 		stty -F $USBDEV $BAUDRATE raw cstopb #Set USB baudrate settings appropriate
  78. 		sleep 1
  79. 		echo "NOW SENDING AT "$BAUDRATE" BAUD !" >> $USBDEV
  80. 		ssdv -e $FILEIMG -i $NR > "/dev/shm/img.ssdv"
  81. 		cat /dev/shm/gps.log >> "/dev/shm/img.ssdv"
  82. 		mv $FILEIMG $DIRSENT #Move used image to sent..
  83. 		find $DIRIMG -type f -name "*.jpg" -exec mv {} $DIRREJECTED ;
  84.  
  85. 		rm /dev/shm/splits/* #make sure folder is empty
  86. 		if [ $SWIT = $ONE ] #Only for 120baud party
  87. 		then
  88. 			sleep 1
  89. 			cat "/dev/shm/img.ssdv" >> $USBDEV #And send it out
  90. 			sleep 3
  91. 		else #If not 1200 baud, split it up and send GPS stuff
  92. 			#Now for the splitting
  93. 			split --bytes=256 "/dev/shm/img.ssdv" /dev/shm/splits/
  94.  
  95. 			for f in /dev/shm/splits/*
  96. 			do
  97. 				echo "Now at splitpart: $f"
  98. 				cat /dev/shm/gps.log >> $f #Append rtty string
  99. 				cat $f >> $USBDEV #And send it out
  100. 				sleep 3
  101. 			done
  102. 		fi
  103. 		rm /dev/shm/splits/*
  104.  
  105. 		#cat "/dev/shm/img.ssdv" > $USBDEV #Send entire file out
  106. 		let NR=$NR+$ONE #Sent Image Iteration as last
  107. 		echo "DONE SENDING AT "$BAUDRATE" BAUD !" >> $USBDEV
  108. 	else
  109. 		echo "No image sent.."
  110. 		echo "No jpegs left.." >> $USBDEV
  111. 	fi
  112.  
  113. 	echo "*****"
  114.  
  115. done

imgscore.sh

  1. #!/bin/bash
  2. #(c) Tim Zaman 2011
  3. # imgscore.sh
  4. # Example usage: "bash imgscore.sh <image.jpg>"
  5. # Returns the score (lower=better)
  6. # THIS FUNCTION SHOULDNT ECHO ANYTHING BUT THE RESULT!
  7. f=$1
  8.  
  9. STDSTR=`identify -verbose $f | grep "standard deviation:" | tr -d "nr:"`
  10. MEANSTR=`identify -verbose $f | grep "mean:" | tr -d "nr:"`
  11. stdarr=($STDSTR)
  12. meanarr=($MEANSTR)
  13. fsize=`stat -c %s $f`
  14.  
  15. STDR=`printf "%.0fn" ${stdarr[2]}`
  16. STDG=`printf "%.0fn" ${stdarr[6]}`
  17. STDB=`printf "%.0fn" ${stdarr[10]}`
  18. STDAVG=$(echo "($STDR + $STDG + $STDB)/3" | bc -l)
  19. STDAVG=`printf "%.0fn" ${STDAVG}`
  20.  
  21. #MEANR=`printf "%.0fn" ${meanarr[1]}`
  22. #MEANG=`printf "%.0fn" ${meanarr[4]}`
  23. MEANB=`printf "%.0fn" ${meanarr[7]}`
  24. #MEANAVG=$(echo "($MEANR + $MEANG + $MEANB)/3" | bc -l)
  25. #MEANAVG=`printf "%.0fn" ${MEANAVG}`
  26.  
  27. SCORE=$(echo "sqrt ( (50-$STDAVG)^2 *2 + (160-$MEANB)^2 )" | bc -l)
  28.  
  29. if [[ $fsize -ge 200000 ]]
  30. then
  31. 	penalty=100
  32. 	SCORE=$(echo "$SCORE + $penalty" | bc -l)
  33. 	#echo "[imgscore: large size detected]"
  34. fi
  35.  
  36. SCORE=`printf "%.0fn" ${SCORE}`
  37.  
  38. #The lower the score, the better the image
  39. echo $SCORE
  40. #echo "$f,$STDR,$STDG,$STDB,$MEANR,$MEANG,$MEANB"
  41.  
  42. #Apply to image:
  43. #SCORERAP=$(echo "(50-$SCORE)/5" | bc -l)
  44. #SCORERAP=`printf "%.0fn" ${SCORERAP}`
  45. #convert $f -pointsize 40 -stroke black -fill white -draw "text 6,42 '$SCORERAP'" "c_"$f

Tim Zaman

MSc Biorobotics. Specialization in computer vision and deep learning. Works at NVIDIA.

You may also like...

3 Responses

  1. stefan Taylor says:

    Hi Tim,

    I’m looking at starting my own space project with my kids. What is the board in front of the camera in the picture “Overview of the internals” – red one.

    Where can i get one of these?

    also do you have any of your boards still left that you over ordered.

    Regards,

    Stefan.

    P.S. Nice work on all of it by the way.

  2. Costyn says:

    Hi Tim,

    I was wondering about the legality of transmitters other than the NTX2 unit here in NL? I was looking at the TX2H-433-64, which is cheaper and more powerful. Is that an option or will that get me into trouble?

    Thanks!

    Cheers,

    Costyn

    • Tim Zaman says:

      Well, that’s not officially clear. What is true, is that Everyone can use the NTX2 modules in holland. What is also true, is if you do not have a radio licence, you can not use any of the other modules outside the NTX2’s frequency and power.
      If you do have a radio licence, its more of a question of how you see things. In 2008, the law states that you HAVE to be at your radiotransmitter that time of operation. In a sattelite ofcourse, this is not possible, so no amateur radio law applies.
      BUT, in 2010, the law states, that you CAN use your amateur radio licence in a sattelite, *if* you are able to turn it off. So that might mean you are going to have to implement a receiver on the HAB itself. Otherwise, you could state that its going to turn off anyway after an hour after liftoff. Or, you could get yourself a pretty large sniper rifle and shoot it from the skies.
      Another question kind of over-rules all of this: why would you want to use a more powerful module? i mean, i have sent at 1200baud on 10mw, with ranges up to 460km to schotland with good extracted sentences. Why would you want anything stronger? Also the bandwidth ot the TX2 is way too large, you can tune it though, i have one too. And, the TX2 isnt made for long range, its really tiny.