Project in history – Going wireless for a Tamiya kit

This project is completed around 2011. It may look ancient as everyone is crazy about “Drone” today. Nevertheless, it brought me so much fun doing it I am still fond of the good memories today and would like to share here.

The goal back then was simple. A wired Tamiya kit + Arduino + bluetooth + Android phone = Wireless remote controlled bulldozer. Integrate the wireless and accelerometer capability from an Android phone to control this kit. As far as I can recall there was no such term as STEM back then but this sort of project can been seen in those syllabuses today on this exciting subject.

The name Tamiya must ring the bell for everyone who had get their feet wet in the remote control modelling world. Tamiya made great kits at very reasonable price for beginners to moderates. I was lucky enough to own and build one of their classic – a bulldozer kit – many years ago and it remained one of the best part of my memory although that bulldozer itself is nowhere to be seen now.

The below is about pretty much the same kit I came across from Tamiya around 2011 which is Xmas gift from my wife.

The finished mods. It is a Bluetooth enabled Tamiya kit that can be controlled from an Android phone.

The Tamiya kit came with a perfect wired On-Off switches to control the kit for forward-backward-left-right maneuvers.

The classic kit I had decades ago (also from Tamiya) is of a wooden base, with metal gears. They are now replaced as plastic that are easier to work with but honestly I still missed the wood and metal. By the way, no power drill is needed for the classic kit with wood, I built mine comfortably with screwdriver and brute force.384637_333179810028224_1549591974_n395470_333179900028215_716701980_n

The core that made it possible from wired to wireless is an Arduino Mega board. Mounted with ease to the baseboard (white) on the Tamiya kit.

The Communication module is an HC-05 Bluetooth board alongside with the H-bride (SN754410) on an Arduino compatible extension board. The design was pretty standard to divide the control circuit from the power circuit that have to drive two 3V motors with power requirements the Arduino board cannot handle.376070_333180030028202_823667822_n


Prototype in testing.

A variation configuration using a mobile phone mounted on the kit and via WIFI to stream the real-time video, and have the control of the kit via Bluetooth from the viewing PC. It is a very popular mods back then and the experience of controlling a MARS Rover at home is simply fantastic.


LU decomposition in TI-84

As an extension to a previous entry on doing LU decomposition in Nspire and R, the TI-84 is covered here. There is no built-in function like in the Nspire for this, but there are many programs available online, with most of them employing a simple Doolittle algorithm without pivoting.

The non-pivoting program described here for the TI-84 series is with a twist. No separate L and U matrix variables are used and the calculations are done in place with the original input matrix A. The end result of both L and U are also stored in this input matrix. This is made possible by the property of the L and U matrices in this decomposition are triangular. Therefore, at the little price of some mental interpretation of the program output, this program will take up less memory and run a little faster than most simple LU decomposition programs online for the same class of calculator. From a simple benchmark with a 5 x 5 matrix, this program took 2 seconds while another standard program took 2.7 seconds.

The input matrix A.

Results are stored in the same matrix.

L, U, and verification.

Unit conversion quirks in TI Nspire

The TI Nspire calculator provided a rich set of common units from area, length, mass, etc. Units start with an understore in Nspire, for example, kg is represented as _kg. User are free to create their own units. On the desktop version of the Nspire software, a short cut for the conversion symbol (► ) is “@>”.

Recently over a conversation with a friend living overseas we are curious of the lowest we can get for a cut of meat at our own places. I am getting 12 per 500 gm on discount a few days ago. He gets 7.8 per 1 lb at best.

Some mental calculations for we have different units, but I decided to fire up the Nspire for this inequality to see what will happen:

Alas, doesn’t work. Obviously I was expecting a boolean. The more verbose inequality with some pre-calculation didn’t work either.

That’s where I realize Nspire might not be handling unit in equations the way we expected. An easy fix of course is to times a common unit (e.g. _kg) on both sides, but that pretty much defeat the whole purpose of simplicity of calculations of this kind.

Consolidating real time traffic CCTV data from with Goolge Map API

Real time CCTV snapshot images from major route and highways in Hong Kong are provided online at Considering availability of data and related technology in the last decade, we have made a huge progress from obtaining traffic jam information from the radio to real time traffic CCTV images on the web.

Advancement in web technology not only enabled access of information, but also provided information in a manner flexible enough to easily build new view of content from multiple sources. The term “mashups” generally refer to this type of web application, and one such example presented here being visualizing road traffic data in near real time images on the web. A demo page is available on this site.

As explained in a previous article demonstrating a practical neural network application, CCTV images from the Hong Kong road network are already made available online. Together with Google Map API, an integration of the two will no doubt a very interesting fusion of technology.

Firstly, visit for a glimpse of the traffic data available. Each CCTV provides image data on the web via a fixed URL.

The next thing to do is to integrate these data in Google Map API. In an attempt for a quick demonstration, a simple out-of-the-box application is adapted to retrieve data from These include the camera image, and the best of all, the geographical information from each of these images, i.e. the longitude and latitude. provided a complete list of geographical data of its cameras, but since they are encoded in a format not directly understood by Google Map (HK80), a translation is required.

After confirming the position of each camera, a simple CSV file is created and the resulting Javascript is generated using an AWK script. There can’t be a method possibly be simpler than this when a prototype page with the Google API has been worked out. The below is captured from the resulting web page showing a selection of location of interest from all available CCTV images from


The map below in HTML created using Google Map API showing a complete list of CCTV location available at Clicking on each marker will open the real time image from the corresponding CCTV camera.hkdatagovcctv1

Excel is used to output a CSV data file for generating the Javascript file for use in the above example. The original file is in PDF but it is fairly easy to convert into Excel and then export from local coordinates in (HK80) to something Google Map API can understand and render.hkdatagovcctv3

The layout of the CSV file is largely duplicated from the PDF file, and the line below is a sample. Most fields are self-explanatory, only the last three fields are additional to the data from the PDF file. Two of these are the converted coordinates for Google Map, and the last one is the default position of the CCTV image with respect to the marker. This can be either one of C,Q,W,A,S. For Q,W,A,S the image will be displayed on the corresponding quadrant as these characters are laid out on the keyboard, while C represent the display centered below the marker.

H106F,H106F.JPG,Connaught Road Central near Exchange Square,,816365,834060,22.2861747,114.1554513,C

The AWK script below is used to loop through the CSV file to generate the part of the HTML content for each CCTV data.


	print "y0=" $7 ";x0=" $8;
	print "y1=y0+0.04;x1=x0+0.05;"
	print "var bounds" idx " = new google.maps.LatLngBounds(new google.maps.LatLng(y0,x0),new google.maps.LatLng(y1,x1));"
    print "var srcImage" idx " = '" $4 "';"
	print "var marker" idx " = new google.maps.Marker({position:new google.maps.LatLng(y0,x0),map:map,title: '" $1 "\\n" $3 "'});"
	print "var quadrant" idx " = \"C\";"
    print "overlay" idx " = new TrafficImageOverlay(bounds" idx ", srcImage" idx ", quadrant" idx ", map);"
	print "arr.push(overlay" idx ");"
	print "marker" idx ".addListener('click', function() {overlay" idx ".toggle();});"
	if ($9=="C") {
		print "overlay" idx ".toggle();"

Finally, the HTML file.

<!DOCTYPE html>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Hong Kong Real Time Road Traffic Camera Image</title>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;

    <script src=""></script>

    var overlay;
	var arr = [];
    TrafficImageOverlay.prototype = new google.maps.OverlayView();
    TrafficImageOverlay.prototype.toggle = function() {
      if (this.getMap()) {
		if (this.quadrant_=="A") {this.quadrant_="Q"; this.setMap(null); this.setMap(this.map_);}
		else if (this.quadrant_=="Q") {this.quadrant_="W"; this.setMap(null); this.setMap(this.map_);}
		else if (this.quadrant_=="W") {this.quadrant_="S"; this.setMap(null); this.setMap(this.map_);}
		else if (this.quadrant_=="S") {this.quadrant_="C"; this.setMap(null); this.setMap(this.map_);}
		else if (this.quadrant_=="C") {this.quadrant_="A"; this.setMap(null);}
      } else {

	TrafficImageOverlay.prototype.refreshImg = function() {
		try {
			this.img_.src=this.image_+'?rand=' + Math.random();
		catch (err) {

	function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
			zoom: 12,
			center: {lat: 22.308, lng: 114.1368}

		var x0,x1,y0,y1;

		<!-- code block below is generated from awk script, showing only one block. One block for each CCTV data. -->

		var bounds1 = new google.maps.LatLngBounds(new google.maps.LatLng(y0,x0),new google.maps.LatLng(y1,x1));
        var srcImage1 = '';
		var marker1 = new google.maps.Marker({position:new google.maps.LatLng(y0,x0),map:map,title: 'Tsing Ma Bridge'});
		var quadrant1 = "Q";
        overlay1 = new TrafficImageOverlay(bounds1, srcImage1, quadrant1, map);
		marker1.addListener('click', function() {overlay1.toggle();});

		<!-- end code block generated from awk script -->

    function TrafficImageOverlay(bounds, image, quadrant, map) {this.bounds_ = bounds;this.image_ = image;this.quadrant_ = quadrant;this.map_ = map;this.div_ = null;this.setMap(map);}
		TrafficImageOverlay.prototype.onAdd = function() {
        var div = document.createElement('div'); = 'none'; = '0px'; = 'absolute';
        var img = document.createElement('img');img.src = this.image_; = '100%'; = '100%'; = 'absolute';div.appendChild(img);this.div_ = div;
		var panes = this.getPanes();panes.overlayLayer.appendChild(div);

	TrafficImageOverlay.prototype.draw = function() {
        var overlayProjection = this.getProjection();
        var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
        var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
        var div = this.div_; = sw.x+'px';'px';'px';'px';
		if (this.quadrant_=="Q") {
			div = this.div_; = sw.x-(ne.x-sw.x)+'px';'px';'px';'px';
		}else if (this.quadrant_=="W") {
			div = this.div_; = sw.x+'px';'px';'px';'px';
		}else if (this.quadrant_=="A") {
			div = this.div_; = sw.x-(ne.x-sw.x)+'px';'px';'px';'px';
		}else if (this.quadrant_=="S") {
			div = this.div_; = sw.x+'px';'px';'px';'px';
		}else if (this.quadrant_=="C") {
			div = this.div_; = sw.x-(ne.x-sw.x)/2+'px';'px';'px';'px';

	TrafficImageOverlay.prototype.onRemove = function() {
        this.div_.parentNode.removeChild(this.div_);this.div_ = null;

    google.maps.event.addDomListener(window, 'load', initMap);

	var refreshIdx = 0;
		function() {
			if (refreshIdx >= arr.length) {
				refreshIdx = 0;
			try {
			} catch (err) {
<div id="map"></div>

Visualizing WordPress stats with Excel Power Map

Power Map is a feature available in recent release of Microsoft Excel providing easy to use visualization of data in geographical form as well as temporal animation.

In a sample usage to understand where the readers of this blog are from this year, the WordPress stats data from 2016 are imported into Excel Power Map. WordPress already offered graphical presentation of visitor origin in a nice world map. For animating the data through a whole year by month, Excel Power Map is a nice and easy to use tool with just a little bit more effort to create such animation.

The statistic page should be familiar to all WordPress user. Download the data for each month as CSV and store on local drive.

Now prepare the data by consolidating them all in a single Excel worksheet. I used the good ole awk as the source files are in plain text CSV to save some copy and paste efforts. For the animation to work, a new column indicating the time of data (e.g. data for USA in January 2016) has to be added for the Power Map to handle temporal attribute, and this column can not be in formula form.

When the source data are ready, select the whole region and click the 3D Map button under the Insert menu.

Now the Power Map UI will be displayed. A globe map will be displayed by default but since I preferred a flat map form instead of 3D so I clicked on the Flat Map button.

The Power Map user interface works pretty much like a pivot table. You drop the dimension on the pre-defined attribute settings pane on the right hand side to tell Power Map how you would like the map to present your data. To create animation, just drag the date column to the “Time” section as the attribute and Power Map will be able to render accordingly.

Now that everything is ready, the animation play nicely and Power Map will also be able to create the animation file.powermap5