2014年1月30日 星期四

使用 PHP 檔頭的密碼功能

Authorization with PHP Header

得到朋友提點,才知道原來能用 PHP 檔頭達致密碼功能。適合不能設定 .htaccess 的地方。
$allowedIPArray = array("012.345.678.900");

$ipAddress = $_SERVER["REMOTE_ADDR"];
$ipAddressX = $_SERVER["HTTP_X_FORWARDED_FOR"];

//  Check if specific IP address
if (!in_array($ipAddress, $allowedIPArray) && !in_array($ipAddressX, $allowedIPArray))  {

 //  IP not in allowed list, ask for login then
 if (!isset($_SERVER["PHP_AUTH_USER"]))  {

  header('WWW-Authenticate: Basic realm="Please enter your login account."');
  header("HTTP/1.0 401 Unauthorized");
  exit(-1);
 }

 //  Login received, check for permission
 $login = $_SERVER["PHP_AUTH_USER"];
 $password = $_SERVER["PHP_AUTH_PW"];

 if ($login != "pacess" || $password != "1234")  {

  header("Content-type: text/html; charset=utf-8");
  echo("Access denied!");
  exit(-2);
 }
}

//  Login success!

2014年1月28日 星期二

OnTV Video Downloader


經網友提點,才發現有一部份 Sita 在 OnTV 的影片還沒有下載。於是編寫了個 Javascript + PHP 的工具,一次過下載回來。當然,這個工具不單止只適用於「陳僖儀」,任個關鍵字也可以。

2014年1月27日 星期一

《不作他選 Fun Fun 賞》


清晨六時半起來,除了為了接送女兒上學之外,就是為了監察客人的項目《不作他選 Fun Fun 賞》。今天是正式上線之日。

《頭條日報》是香港免費報章中發行量最多的一份,讀者人數很多。是次為她們開發的《不作他選 Fun Fun 賞》,相信會有很多人參與,同時在線的情況亦是公司成立以來最多的(不計 Little Diary)。我也感到特別的緊張。幸而,整天以來小問題倒是有的,但沒有大問題,實在感恩。多謝有份負責的同事,他們的努力使得項目得以順利進行。之前為 Sita 製作的「頭條日報剪報程式」也再次派上用場。收集最高清圖像作為公司的發展記錄。

2014年1月26日 星期日

《AMIGO Controller》開發記錄:動作編輯畫面(二)


今天繼續開發動作編輯畫面。先是處理「點選」及一起移動的功能。這是以 Notification 方式處理,效果不錯。

2014年1月25日 星期六

陳僖儀 Wallpaper


今日為 MacBook Pro 大掃除,順便製作了一張《陳僖儀 Wallpaper》。不過有點花,較難聚焦在桌面的圖示。後來加入 40% 黑色便順眼很多,能突出圖示之餘,又保持到 Sita 的相片。不錯,不錯。

2014年1月24日 星期五

加薪

今日正式向同事個別公佈加薪的幅度。有的同事歡迎、黑面也有。在考慮個別加薪幅度的時候,我有點困惑。究竟是按同事的態度來決定幅度?還是由成果來判斷?甚至是兩者?

我認為成果是最公平公正,你能及時或提早完成、應用運作良好、客人滿意,當然能加得多;要是經常延遲或耗時太多、應用「北」到七彩、客人經常投訴,減薪也不能怪人。可是,這個做法太不人性化。遇上能力較弱但態度良好的同事時,會是打壓的操施,不能提升士氣。所以,最後還是選用兩者。表現良好的同事能獲得最大加薪幅度,成果不佳的則只能獲得最少幅度。

不過,遇著同事黑面,心裡還是有點聲音。要是以前的我,一定會說:「不減還有得加,是不是應該慶幸?」,現在由衷地覺得:「公司的一點心意」,希望同事不要介懷,能正面地想。我很希望大家一起努力,在明年能有花紅及雙位數字的增長。

2014年1月23日 星期四

請辭

幾天前同事向我請辭。我當然詢問箇中原因,聽到兩個很合理的理由。他是幫得手的同事,所以也想挽留他,嘗試跟他說明公司的發展,也跟其他董事商量一下。公司之前已經宣佈過加薪事宜,不過不合他的意思。經過商討之後,我們決定把他的薪金由原本的個位數字提升到雙位數字,希望他能明白公司在蝕錢的同時,已經盡力改善同事的待遇。作為老闆的我,三年沒有加薪,也要同事有得加薪。可惜,還是留不住同事。

坦白說要加到同事要求的數字是有足夠能力,先不說他是否值這個金額,也不說他的能力,我只想說作為管理層,需要為公司的前景考慮,也需要為其他同事考慮。一個錯誤的決定會有深遠的影響。被拒絕那刻也突然感覺到,像我公司這些初創企業,要是遇到能同甘共苦、肯博肯捱的同事時,真的要好好善待。單是這份心意已經很感恩了。同事出來打工為錢、為理想十分正常。如能加多份心,公司真的會感受得到。

2014年1月22日 星期三

BlockView

動作編輯畫面中的動作是一個個的 BlockView 物件,那是自定的。它負責的是一個動作的數據,同時也對拖拉動作作出處理。由於加入了多選功能,可以同時拖拉超過一件 BlockView 物件。原本在拖拉時會利用 Protocol 通知上層,現時則在上層同時再通知下層中其他被選的 BlockView 作相同操作。

後來覺得這樣雖然能達到目的,但似乎不夠好。上下層的代碼要緊密處理才不易出事。於是嘗試改為 Notification 形式,發現這個方法較為簡單,上層不用通知下層也有相同效果。

2014年1月21日 星期二

《AMIGO Controller》開發記錄:動作編輯畫面

Motion Editor Screen

《AMIGO Controller 2.00》其他三個畫面都造好了,最後是動作編輯畫面。這是四個之中最複雜的一個。保留了動作區塊,加入了動作組的概念。網友 Keith 的經驗最多,由他提供的資訊一定是心得精華所在。不過,我希望介面能盡量簡單易用,不想做得太多按鈕、太多數據。這裡需要取捨。原本 Keith 說要支援同時操作底板內所有 43 個埠。如是這樣,畫面再大也容納不下。考慮到編輯操作時的容易出現的失誤,我決定介面只有 10 個頻道。一個頻道等如一個埠。跟《AMIGO Controller 1.00》不同的是,頻道不會指定對應某一個埠,改為按動作區塊的設定。即是在頻道 1 可以是管理 1 號埠,也可以是 2 號埠。加上動作組內也是 10 個頻道,總共同時能處理 100 個埠,完全包含底板內的 43 個埠。

2014年1月20日 星期一

BLE mini vs HM-10

花了兩天時間製作《AMIGO Controller 2.0》的藍牙部份。今次同時支援 BLE mini 及 HM-10。目標能同時操作八台機體,沒有使用 SDK,改為直接編寫自己的接口。搞了很久能成功連線,但仍未能存取數據。iOS 6 沒問題,iOS 7 卻出事。查看兩者的 SDK 都大同小異,明明方法用對了,但沒有效果。細心檢查才發現是 UUID 錯配了,同時留意到是「writeValue」時出問題:
NSData *chunk = [NSData dataWithBytes:byteArray+offset length:size];
if (characteristic.properties&CBCharacteristicPropertyWriteWithoutResponse)  {
    [peripheral writeValue:chunk forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse];
}  else  {
    [peripheral writeValue:chunk forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
}
iOS 6 不用分 With 還是 Without,iOS 7 卻要分開處理才能成事。最後 HM-10 在兩個 iOS 內都正常運作,收發自如;但 BLE mini 卻十分難搞,只能在 iOS 6 發出訊號,無發接收。一想到 BLE mini 價錢是 HM-10 的 7 倍,就很想完全放棄 BLE mini...。

2014年1月18日 星期六

拉闊圖書館・十三:三角插

BeyondZ Library 13

周三是第十三課《拉闊圖書館》,由同事 Kic 教大家插「三角插」公仔。


我在聖誕節交換禮物時第一次接觸三角插作品,那是 Kic 親手製作。後來我也把它做了一次「逆向工程」,知道了如何摺出三角插。也跟著網上教學嘗試製作另一個作品,給女兒交功課之用。可惜失敗了。今次得到 Kic 老師的指點,終於成功製作底部。真是有些竅門,三角插才不容易散開。也認識到三角插原來是由獄犯創作出來的藝術,真是意想不到。

2014年1月17日 星期五

在 Xcode 5 及 SDK 7.0 下關閉 iOS 6 圖示的反光效果

Turn Off Gloss Effect for iOS 6 on Xcode 5 with SDK 7.0

我真的不起歡 iOS 7。無論從圖案設計、使用習慣、到編程部份都有很多問題。就像一直在 InfoPlist 中設定圖示的反光效果為例,在 Xcode 5 及 SDK 7.0 下變得無用。如想取消圖示高光,得要去 Images.xcassets 中的 Inspector 選單中,把 iOS icon is pre-rendered 打勾才可...。

2014年1月16日 星期四

《AMIGO Controller》開發記錄:即時姿勢調校畫面

Instant Pose Screen

這個星期很努力地開發《AMIGO Controller 2.00》。繼終端機畫面後,完成了動作控制畫面及即時姿勢調校畫面。除了重整架構外,也加入了新元素及改良,希望造出一套又美觀又實用的控制器。

原本在版本 1.xx 時的動作控制畫面中,使用了自行製作的 MotionButton 類。它是模擬 UIButton 的觸感,再加入雙擊及長按操作。最主要是由程序生成,可設定任意顏色及大小。可是在 iOS 7 環境下會令到後方的 UIScrollView 無法拖拉。在版本 2.00 中決定用回 UIButton,但仍然保持其他特色。暫時試過在 iOS 6 及 iOS 7 下也表現出相同的結果。可以正式取代 MotionButton。

2014年1月15日 星期三

NSUserDefaults 存取留意事項

Hints for Using NSUserDefaults

《AMIGO Controller 2.00》支援多款機體,除了在啟動時要檢查用戶的介面是選了哪款機體外,在應用程式由背景模式返回前景模式也要這麼處理。今早找到了一個關鍵。在返回前景時必須調用 [[NSUserDefaults standardUserDefaults] synchronize] 才讀取設定的數值;否則數值有機會未及時更新。

2014年1月14日 星期二

《AMIGO Controller》開發記錄:伸縮搖桿

Joystick Panel

這是《AMIGO Controller 2.00》的終端機畫面。搖桿能隨意收起,方便查看更多的訊息。花了很多時間才完成。原因是在 iOS 6 跑得好好地,但在 iOS 7 中則出現問題。如:畫面下半部份接觸不良。以下是我的解決方案。在 Root View Controller 的 viewDidLoad 加入:
//  Fix for iOS 7 frame size not update anymore issue
int topMargin = 0;
if (_appManager.iosVersion < 7.0f)  {topMargin = 20;}

CGRect rect = [[UIScreen mainScreen] bounds];
CGRect applicationFrame = CGRectMake(0, 0, rect.size.width, rect.size.height-topMargin);
if (isiPad == YES)  {applicationFrame = CGRectMake(0, 0, rect.size.height, rect.size.width-topMargin);}
[self.view setFrame:applicationFrame];
[self.view setAutoresizingMask:UIViewAutoresizingNone];

其實重要的是最後那句 [self.view setAutoresizingMask:UIViewAutoresizingNone]。不過只限 iOS 7;如果在 iOS 6 跑這句,就到 iOS 6 接觸不良。

2014年1月13日 星期一

《AMIGO Controller》開發記錄:縮時攝影

AMIGO Timelapse

《AMIGO Controller 2.00》其中一個特色是把我所有機體或機器的控制器收納在一起。為免日後發生根本性的問題,於是先把《AMIGO Timelapse》的 iPhone App 加入。由於《AMIGO Controller 2.00》同時支援 iPhone 及 iPad,也順道製作 Timelapse 的 iPad 版。原來 Timelapse 的代碼寫得比較好,很輕易地便成功加到《AMIGO Controller 2.00》之內。iPad 版的介面作簡單的設定便能完成。唯獨是在 iOS 7 環境下,畫面下方的 Focus 及 Shutter 按鈕都沒有反應。相信跟 iOS 7 的改動有關,需要下點功夫解決。

因應《AMIGO Controller 2.00》會加入「多機同步」功能,這個畫面需要加入「連線」按鈕。預計可以同時連接 12 台《AMIGO Timelapse》並且一起連動,看來很吸引呢!

2014年1月12日 星期日

HM-10 藍牙 4.0 模塊

HM-10 Bluetooth LE Module

春節之前,有另一批《Tri-Robot DMP》附運。目前 App Store 上的《AMIGO Controller》是 1.10 版本。還有很多需要改良的地方。我希望能盡快推出 2.00 版,提升用戶體驗。

今天收到另一個牌子的藍牙模塊,是 BLE mini 的四份一價錢,而且還能透過 AT 指令修改 BLE 的名稱,我認為是一個必須的功能。看過他的代碼,發覺跟 BLE mini 的處理差不多,應該很容易加入到編寫中的 BLE SDK。如果這顆藍牙能滿足機體所需,我們將會全面改用這款晶片。

2014年1月11日 星期六

《AMIGO Controller》開發記錄:BLE SDK

製作中的《AMIGO Controller 2.00》打算加入「多機同步操作」功能。現時使用的 BLE SDK 無法滿足這個需要,所以我決定自行編寫 BLE 的連接部份。

原來的 SDK 中有一個 NSArray 儲存了偵測到的藍牙裝置,不過它只容許連接當中一個裝置。自行修改的 SDK 不太難改,只要在容許更多連接就可以。而當斷線時針對指定裝置來處理就可以。

2014年1月10日 星期五

小米電源

Xiaomi Dianyuan

周六跟朋友們吃晚飯,席間一位由美國回港短休的朋友向我抱怨。指她那台老舊的 iPhone 3G 電力消耗得太快,半天就沒電,十分不便。我建議她購買外置電池時,想起了小米電源兩天後便推出,無論質素、容量、價錢都十分好,推介她準備搶購。小米電源在 1 月 6 日正午 12 時開賣,朋友下午 4 時打來告訴我已經賣光了,問我有沒有辦法。而我當時建議她購買 eneloop。之後的兩天,其他朋友都要求我幫忙在下次開賣時代購。

我沒有留意小米電源的銷情,從一位朋友中得知半小時就賣光了。昨天早起無所事事,於是到小米官網看看。無意中發現了漏洞,使我能夠在「暫時缺貨」的情況下購買到小米電源。我一直在想以這樣方式落的單能否如常寄出?就在今天我得到答案了。然而,小米的反應十分瞬速,不到半天的時間已把漏洞修補。一間機構有這般的靈活性,實在抵讚!

2014年1月9日 星期四

《AMIGO Controller》開發記錄:ViewControllers


在決定《AMIGO Controller 2.00》加入更多機體支援後,程式及畫面的結構需要作出改動。

原來的設計是在應用啟動時,自行決定顯示 iPhone 版本還是 iPad 版本。現在機體多了,每款機體又有 iPhone 及 iPad 兩個版本;而某些機體像 Tri-Robot DMP 一樣,要處理的事情很多,需要多過一個畫面的內容,導致需要製作的介面有很多。為了清楚有甚麼東西要做,先在 https://www.text2mindmap.com 構思一下整體結構。

2014年1月8日 星期三

Settings Bundle


經過反覆考慮之後,我決定「扭計骰機械人」由《AMIGO Controller》控制。畢竟要扭出一幅圖畫,單單機體自己是無法完成。所以,今晚我在《AMIGO Controller》加入了機體選擇的設定。

2014年1月7日 星期二

陳僖儀 @蘋果動新聞


http://video.appledaily.com.hk/admedia/20140107/06012014_news_902_w.mp4

2014年1月6日 星期一

我期望 2014 年的蘋果

My Apple Big Plan

蘋果 CEO Tim Cook 在 2014 快將來到之際向員工發放了「Big Plan」訊息,當時我想豈不是 iWatch, iTV, 大號 iPhone/iPad,有甚麼「大」呢?但偶爾地把資訊歸納後,漸漸地看到一幅景象。這是我看到蘋果的 2014:

帶著 iRing 走到家的門前,不用鎖匙已經能打開大門。因為 iRing 透過生物辨識技術,已經能辨認出來者的身份。唉,不是叫「iWatch」嗎?我想這種穿戴裝置已經超越了「手錶」的範疇;Apple 總愛帶點圓的東西,Ring 正是圓形,而且簡單易記易上口。我認為這款裝置除了顯示時間之外,大部份情況下是不用「看」的。至於生物辨識技術,我想除了指紋外,還有機會是心跳及血壓,甚至體溫。這樣就能確認來者身份,不易被冒認。大門門鎖是支援 iBeacon 的裝置,只要 iRing 走近,並且身份得到確認,便能打開大門。這裡有一個關鍵要素處理。就是目前 iBeacon 訊號沒有加密認證,訊號能夠被複製。不過 WWDC 2013 已公開說明在 iOS 層面會解決這個問題。

走進屋後,iPanel 顯示出一大堆通知,可能是電郵、可能是哪個電器需要更新...等。Siri 能把訊息一一讀出,主人還可以繼續他的活動。當然,訊息是針對剛回來的那個人。為何不是叫「iTV」?同理,已經超越了「Vision」的功用。形狀相信還是電視,但已經是掌管全家設備的一個核心。iPanel 透過 iBeacon 能得知家中有甚麼電器及其距離。以 Star Networking 的方式能計算出各電器的位置。當然,戴著 iRing 的家庭成員在家中甚麼位置也能換算出來。iPanel 除了能看電視、能上網、能跑應用之外,更能以 Bluetooth LE 連接其他電器作資料交換。例如 iRing 量度出心跳、血壓、體溫不正常,能透過 iPanel 直接發出 iMessage 給醫院作記錄,甚至能自動召喚救護車到場。例如空調能按照家中各人的體溫,自動調節合適的溫度。要處理這麼多資訊,機能也有點要求。Mac Pro 般規格應該能夠勝任。現時 Mac Pro 能縮到這麼小,攤分到 40 寸大電視之內沒有困難。輸入方面,Siri 語音、觸控式屏幕、手勢輸入不能少。配合 Apple ID 便能在 iPanel 上直接購買家庭用品。

這不就是人們一直盼望的「Smart Home」嗎?技術是已有的技術,實現起來沒有難度。電器只要裝上 Bluetooth LE 及 iBeacon 通訊協議便能使用,廠商要支持不是問題,成本也高不了多少,但效用可大。Bluetooth LE 已經在數年前加入到 iPhone 及 iPad 內。現時大部份人們持有的 iOS 裝置已經準備就緒。加上最近 Apple 收購的公司,都能跟以上情境扯上關係,要實行也不是問題。只要 iRing 及 iPanel 準備好就行。最吸引我眼球的是 Apple 投資機械人開發。我認為民用的機械人應該是像家傭般的角色。機械人硬體只是輸入及輸出裝置,機械人大腦不應體現在機械人硬體本身,較為適合在 iPanel 般的裝置上。電力及體積的考慮減輕了。Apple 向來不是要爭第一,而是改善人們生活。iPanel 既能攻佔「客廳」,又能改善生活,是一箭雙雕的產品。不過,以上純屬個人的天馬行空想法,不代表 Apple 的策略。

2014年1月5日 星期日

Javascript 點點圖工具

Rubik's Art Painter

相片轉換到扭計骰的效果不太好,所以用 Javascript 寫了一個《Rubik's Art Painter》方便自己。另外,花了 HK$140 購入了 60 顆迷你扭計骰,質素都不錯。
function onMouseMove(event)  {
  var mouseX = event.clientX-_canvas.offsetLeft;
  var mouseY = event.clientY-_canvas.offsetTop;

  if (_mouseState == 0)  {return;}

  var x = Math.floor((mouseX-1)/16);
  var y = Math.floor((mouseY-1)/16);
  if (x < 0 || y < 0)  {return;}

  var index = (y*_imageWidth)+x;
  _patternArray[index] = _currentColorID;

  x = (x*16)+1;
  y = (y*16)+1;
  _context.fillRect(x, y, 16-1, 16-1);
}

//----------------------------------------------------------
function onMouseUp(event)  {
  var mouseX = event.clientX-_canvas.offsetLeft;
  var mouseY = event.clientY-_canvas.offsetTop;
  _mouseState = 0;
}

//----------------------------------------------------------
function saveImage()  {
  var codeString = "";
  var index = 0;
  var colorID;

  for (var y=0; y<_imageHeight; y+=3)  {
    for (var x=0; x<_imageWidth; x+=3)  {

      index = (y*_imageWidth)+x;

      colorID = _patternArray[index+0];  codeString += colorID+",";
      colorID = _patternArray[index+1];  codeString += colorID+",";
      colorID = _patternArray[index+2];  codeString += colorID+",";

      colorID = _patternArray[index+_imageWidth+0];  codeString += colorID+",";
      colorID = _patternArray[index+_imageWidth+1];  codeString += colorID+",";
      colorID = _patternArray[index+_imageWidth+2];  codeString += colorID+",";

      colorID = _patternArray[index+_imageWidth+_imageWidth+0];  codeString += colorID+",";
      colorID = _patternArray[index+_imageWidth+_imageWidth+1];  codeString += colorID+",";
      colorID = _patternArray[index+_imageWidth+_imageWidth+2];  codeString += colorID+",";
    }
  }
  alert(codeString);
}

2014年1月4日 星期六

魔方圖案轉換器

Convert Image to Rubik's Cube Pattern

既然魔方圖案的扭法都找出來了,下一步就是準備圖案本身。我不希望以手動方式去製作圖案,所以花了很多時間去編寫這個轉換器,主要的困難居然是那個「拖拉上傳」部份...。有了這個工具,便能把圖案上傳,並按畫面中設定的像素面積自動轉換成魔方的顏色及圖案。目前還沒有加入「Dithering」的功能,得出來的效果只是一般。不過,我並不打算加入這個處理。原因是很費時,而且坊間有圖像編輯軟件能做得更好。若要「Dithering」的話,先在 Pixelmator, Photoshop,...等處理好再上傳就行了。

2014年1月3日 星期五

魔方解題程式

Rubik's Cube Solver in Javascript

對於「扭計骰機械人」的構造,今天有了另一個想法。原本 PHP 的部份改為 iPhone/iPad 處理。它的運算能力夠強,而且擁有鏡頭,可以把魔方的六個面都拍下,然後再給出運算。在沒有頭緒如何編寫魔方解題程式的情況下,只好使用最簡單的方法:逐個面去扭。目前設定上限為 11 步(太多會運算得上數分鐘時間),在 Javascript 下測試,暫時都能找出解法,大多在 2~3 秒內完成,也有需要用上 28 秒才完成。有待改良...。

2014年1月2日 星期四

CSS 3D Cube


關於《扭計骰機械人》的開發,我會先證明了運算的方法,甚至是可行性後才會動手製作。機體會以 Arduino 為大腦,貪其簡單易用,主要是操作「扭」這個動作。至於要扭的步驟,擔心 Arduino 會花很多時間運算,暫時由 PC 處理。在未建構硬件之前,目前的構思是用 Javascript 代表 Arduino 做「扭」及畫面上的工作,運算則是 CentOS 端的 PHP 處理。Javascript 是比較方便的語言去讓我測試運算是否正確。待沒有問題時,便會移植到 Arduino 上。昨天研究了如何在 HTML 利用 CSS 顯示立體魔方的方法:
#cameraDiv {
 width: 400px;
 height: 160px;
 margin: 80 0 80 0px;
 -webkit-perspective: 800;
 -webkit-perspective-origin: 50% 0%;
 -moz-perspective: 800;
 -moz-perspective-origin: 50% 0%;
 -o-perspective: 800;
 -o-perspective-origin: 50% 0%;
 -ms-perspective: 800;
 -ms-perspective-origin: 50% 0%;
}
#cubeDiv {
 position: relative;
 margin: 0 auto;
 height: 160px;
 width: 160px;
 -webkit-transition: -webkit-transform 2s linear;
 -webkit-transform-style: preserve-3d;
 -moz-transition: -webkit-transform 2s linear;
 -moz-transform-style: preserve-3d;
 -o-transition: -webkit-transform 2s linear;
 -o-transform-style: preserve-3d;
 -ms-transition: -webkit-transform 2s linear;
 -ms-transform-style: preserve-3d;
}
.face {
 position: absolute;
 height: 160px;
 width: 160px;
 padding: 0px;
 background-color: rgba(0, 0, 0, 1.0);
}

#cubeDiv .one  {-webkit-transform: translateZ(80px);  -moz-transform: translateZ(80px);  -o-transform: translateZ(80px);  -ms-transform: translateZ(80px);}
#cubeDiv .two  {-webkit-transform: translateY(80px) rotateX(270deg);  -moz-transform: translateY(80px) rotateX(270deg);  -o-transform: translateY(80px) rotateX(270deg);  -ms-transform: translateY(80px) rotateX(270deg);}
#cubeDiv .three  {-webkit-transform: translateZ(-80px) rotateX(180deg);  -moz-transform: translateZ(-80px) rotateX(180deg);  -o-transform: translateZ(-80px) rotateX(180deg);  -ms-transform: translateZ(-80px) rotateX(180deg);}
#cubeDiv .four  {-webkit-transform: translateY(-80px) rotateX(90deg);  -moz-transform: translateY(-80px) rotateX(90deg);  -o-transform: translateY(-80px) rotateX(90deg);  -ms-transform: translateY(-80px) rotateX(90deg);}
#cubeDiv .five  {-webkit-transform: translateX(-80px) rotateX(270deg) rotateY(270deg);  -moz-transform: translateX(-80px) rotateX(270deg) rotateY(270deg);  -o-transform: translateX(-80px) rotateX(270deg) rotateY(270deg);  -ms-transform: translateX(-80px) rotateX(270deg) rotateY(270deg);}
#cubeDiv .six  {-webkit-transform: translateX(80px) rotateX(270deg) rotateY(90deg);  -moz-transform: translateX(80px) rotateX(270deg) rotateY(90deg);  -o-transform: translateX(80px) rotateX(270deg) rotateY(90deg);  -ms-transform: translateX(80px) rotateX(270deg) rotateY(90deg);}

.animate  {
 -webkit-animation: rotatingAnimation 10s infinite linear;
 -moz-animation: rotatingAnimation 10s infinite linear;
 -o-animation: rotatingAnimation 10s infinite linear;
 -ms-animation: rotatingAnimation 10s infinite linear;
 animation: rotatingAnimation 10s infinite linear;
}
@-moz-keyframes rotatingAnimation  {
 from  {-moz-transform: rotateX(0deg) rotateY(-22.5deg);}
 to  {-moz-transform: rotateX(360deg) rotateY(-22.5deg);}
}
@-webkit-keyframes rotatingAnimation {
 from  {-webkit-transform: rotateX(0deg) rotateY(-22.5deg);}
 to  {-webkit-transform: rotateX(360deg) rotateY(-22.5deg);}
}
@-o-keyframes rotatingAnimation {
 from  {-o-transform: rotateX(0deg) rotateY(-22.5deg);}
 to  {-o-transform: rotateX(360deg) rotateY(-22.5deg);}
}
@-ms-keyframes rotatingAnimation {
 from  {-ms-transform: rotateX(0deg) rotateY(-22.5deg);}
 to  {-ms-transform: rotateX(360deg) rotateY(-22.5deg);}
}
@keyframes rotatingAnimation {
 from  {transform: rotateX(0deg) rotateY(-22.5deg);}
 to  {transform: rotateX(360deg) rotateY(-22.5deg);}
}
HTML 代碼:
<div id="cameraDiv">
 <div id="cubeDiv" class="animate">
  <div id="face01Div" class="face one"><table border="0"><tr><td class="inputDivR">0</td><td class="inputDivR">1</td><td class="inputDivR">2</td></tr><tr><td class="inputDivR">3</td><td class="inputDivR">4</td><td class="inputDivR">5</td></tr><tr><td class="inputDivR">6</td><td class="inputDivR">7</td><td class="inputDivR">8</td></tr></table></div>
  <div id="face02Div" class="face two"><table border="0"><tr><td class="inputDivW">0</td><td class="inputDivW">1</td><td class="inputDivW">2</td></tr><tr><td class="inputDivW">3</td><td class="inputDivW">4</td><td class="inputDivW">5</td></tr><tr><td class="inputDivW">6</td><td class="inputDivW">7</td><td class="inputDivW">8</td></tr></table></div>
  <div id="face03Div" class="face three"><table border="0"><tr><td class="inputDivO">0</td><td class="inputDivO">1</td><td class="inputDivO">2</td></tr><tr><td class="inputDivO">3</td><td class="inputDivO">4</td><td class="inputDivO">5</td></tr><tr><td class="inputDivO">6</td><td class="inputDivO">7</td><td class="inputDivO">8</td></tr></table></div>
  <div id="face04Div" class="face four"><table border="0"><tr><td class="inputDivY">0</td><td class="inputDivY">1</td><td class="inputDivY">2</td></tr><tr><td class="inputDivY">3</td><td class="inputDivY">4</td><td class="inputDivY">5</td></tr><tr><td class="inputDivY">6</td><td class="inputDivY">7</td><td class="inputDivY">8</td></tr></table></div>
  <div id="face05Div" class="face five"><table border="0"><tr><td class="inputDivB">0</td><td class="inputDivB">1</td><td class="inputDivB">2</td></tr><tr><td class="inputDivB">3</td><td class="inputDivB">4</td><td class="inputDivB">5</td></tr><tr><td class="inputDivB">6</td><td class="inputDivB">7</td><td class="inputDivB">8</td></tr></table></div>
  <div id="face06Div" class="face six"><table border="0"><tr><td class="inputDivG">0</td><td class="inputDivG">1</td><td class="inputDivG">2</td></tr><tr><td class="inputDivG">3</td><td class="inputDivG">4</td><td class="inputDivG">5</td></tr><tr><td class="inputDivG">6</td><td class="inputDivG">7</td><td class="inputDivG">8</td></tr></table></div>
 </div>
</div>

2014年1月1日 星期三

2014 的任務

Tasks 2014

新年尹始,是時候計劃一下想要完成的研究:

1. Quadcopter
想了兩年的 Quadcopter,需要學習如何選購無刷電機、電機控制器、電源、設計機身、鏡頭...等很多事情。有點雞與蛋的死胡同。要估計出機體的重量,才能計算電機所需的拉力,再選出合適長度的螺旋槳。重量又要視乎放多少東西進去,及有多少資金。還要等候 3D 打印機到手,才能測試出能否打印支架。無論如何,今年要有點成果。

2. 扭計骰(Rubik's Cube)機械人
這是 2013 想出來的項目,我很感興趣。可是要解決的問題也很多。機體打算用 3D 打印機製作,相信沒有難度。軟體方面則毫無頭緒,需要消化一下網上的資源。我打算利用 HTML5 + Javascript 嘗試印證邏輯是可行後,才會移植到機體上。希望能在 Hong Kong Maker Faire 登場。

3. AMIGO Controller 2.00
重寫的版本希望能在春節前完成,之後會嘗試加入聲控及手勢控制。我最想做的則是為機體加裝檢測器,以 iPad 為大腦,使機體能自動化暴走。

4. WiFi 機械臂車
相對以上的項目,這是較為簡單。用淘汰的 Futaba S3003 製作機械臂,加上車型底座,利用 WiFi 控制自由走動及夾東西。簡單但好玩的項目。

5. 反斗車王
這個項目曾經開始過,想在今年完成。是一架用 iOS 遙控的玩具車。甚至是一架 Google 自走車。即能自行開車、停車、避開障礙物。