2014年12月29日 星期一

Javascript: 直接使用 HTML 的 Option 值

最近幫一位前輩修改他的網頁,當中用到 SELECT 元件;希望在點擊後會把值傳送到 Javascript 那邊。之前用慣了 this.selectedIndex,今次卻因為設計的緣故不能用 Index 值,需要改為 this.options[this.selectedIndex].value。
<select class="menu" onchange="onClickMenu(this.options[this.selectedIndex].value);">
 <option value="#ancla0" selected="selected">我们的故事</option>
 <option value="#ancla1" class="second_item">课程</option>
 <option value="#ancla2" class="second_item">活动</option>
 <option value="#ancla3" class="second_item">日记</option>
 <option value="#ancla4" class="second_item">联系</option>
</select>

2014年12月25日 星期四

縮時拍攝失敗


聖誕假期到韓國滑雪,順道希望拍攝縮時影片,所以趕製縮時拍攝裝置。腳架帶了、小米電池帶了、縮時拍攝裝置也都帶了。似乎萬無一失,可是卻偏偏拍攝不成。問題出在可惡的小米電池。

當晚在酒店房間,架好腳架、裝好縮時拍攝裝置、接上小米電池,也利用藍牙透過 iPad 設定好拍攝的數值。豈料,小米電池在供電一會後自動停止。電量是滿滿的,充 iPhone 也沒有問題。之前試過 WeChat 送的電池運作量好,估不到買的小米電池卻有這樣的問題。在沒有帶後備電池的情況下,唯有放棄。改為拍攝星星,不過渡假村也實在太光了,雖然影到星星,但光害在相片中也挺高。

2014年12月19日 星期五

趕製《縮時拍攝裝置》・五


代碼雖然完成,但從 iPad 發過去的訊號都變成亂碼,這是 baud rate 不正確所致。記得曾聽聞過 BLE mini 在某個版本之後,靜悄悄地把 baud rate 改了。於是我從最大的 115200 逐個逐個嘗試,到 9600 還是亂碼。向 Peter 老師請教後,估計有兩個情況有可能導致問題發生。一是 BLE mini 壞了,二是韌體問題。我發現還有第三個可能性,是沒有設定端口的方向。不過後來證實了是不用設定方向。檢查韌體,發現版本是 2013 年的,舊了點。下個最新版本並安裝好後,所有部份回愎正常。


還有點時間,繼續設計外觀。造了一個相機接口,可是要很花力氣才能連接。唯有暫時頂檔。

2014年12月18日 星期四

趕製《縮時拍攝裝置》・四


把最後的 BLE mini 也焊接好後,零件部份已經完工。接著是外殼及軟件部份。而軟件部份又分為 Arduino 端及 iOS 端。iOS 端目前可以用《AMIGO Controller》來頂上。外殼內部空間加大了,底板沒有卡著。加高了筒的尺寸,耳機接口有足夠空間。同時也留了放置電線的地方。接著搞 Arduino 部份。

在紙上考慮好需要的指令,定義出相關的參數,以最簡單的方式編寫 Arduino 程式。雖然 delay 指令會佔領著時間,無法做出分工工作,但時間緊迫,暫時使用。以下是目前為止的代碼:
//========================================================================
//  AMIGO Timelapse for Arduino
//------------------------------------------------------------------------
//  Created by Pacess on 2014-12-17
//  Copyright (c) 2014 Hotaru Productions Company.  All rights reserved.
//========================================================================

//------------------------------------------------------------------------
//  0    1         2         3         4         5         6         7
//  5678901234567890123456789012345678901234567890123456789012345678901234

#include <SoftwareSerial.h>

//------------------------------------------------------------------------
//  Command list
//------------------------------------------------------------------------
//   ! means end of command
//
//   Input:  Capital letters for Bluetooth to Arduino
//     O!     = Shutter open
//     C!     = Shutter close
//     F!     = Focus
//     O0000! = Set shutter open duration
//     C0000! = Set shutter close duration
//     R!     = Reset frame counter
//     I!     = Get current information and settings
//     G!     = Go according to the settings
//
//   Output:  Small letters for Arduino to Bluetooth
//     f0000o0000c0000! = Frames taken, Shutter open duration, Shutter close duration
//------------------------------------------------------------------------

//  Defines
const int PORT_LED = 13;

const int PORT_BLUETOOTH_RX = 10;
const int PORT_BLUETOOTH_TX = 11;

const int PORT_SHUTTER = 4;
const int PORT_FOCUS = 3;

const int ONE_SECOND = 1000;

const unsigned int BAUDRATE_ARDUINO = 57600;
const unsigned int BAUDRATE_BLUETOOTH = 57600;

//------------------------------------------------------------------------
//  Global variables
SoftwareSerial bluetoothSerial(PORT_BLUETOOTH_RX, PORT_BLUETOOTH_TX);

int ledValue = HIGH;

//  1 = One second
unsigned int shutterOpenDuration = 1;
unsigned int shutterCloseDuration = 59;
unsigned int framesTaken = 0;

//========================================================================
void setup()  {
   pinMode(PORT_LED, OUTPUT);
   pinMode(PORT_FOCUS, OUTPUT);
   pinMode(PORT_SHUTTER, OUTPUT);

   //  Make sure pin is low
   digitalWrite(PORT_FOCUS, LOW);
   digitalWrite(PORT_SHUTTER, LOW);
   delay(ONE_SECOND/4);

   //------------------------------------------------------------------------
   //  Open onboard serial communication
   Serial.begin(BAUDRATE_ARDUINO);

   //  Wait for serial port to connect.  Needed for Leonardo only
   while (!Serial);
    Serial.println("AMIGO Timelapse is ready!");

   //  Set my data rate for SoftwareSerial port
   bluetoothSerial.begin(BAUDRATE_BLUETOOTH);
   bluetoothSerial.println("AMIGO Timelapse connected.");
}

//------------------------------------------------------------------------
//  Toggle LED light
void toggleLED()  {
   if (ledValue == HIGH)  {ledValue = LOW;}
   else  {ledValue = HIGH;}
   digitalWrite(PORT_LED, ledValue);
}

//------------------------------------------------------------------------
char readSerialByte()  {
   char data = 0;
   while (1)  {
      if (bluetoothSerial.available())  {data = bluetoothSerial.read();  break;}
      else if (Serial.available())  {data = Serial.read();  break;}
   }

   Serial.write(data);
   return data;
}

//------------------------------------------------------------------------
void openShutter()  {
   toggleLED();
   digitalWrite(PORT_SHUTTER, HIGH);
}

//------------------------------------------------------------------------
void closeShutter()  {
   toggleLED();
   digitalWrite(PORT_SHUTTER, LOW);
}

//------------------------------------------------------------------------
void focusNow()  {
   toggleLED();
   digitalWrite(PORT_SHUTTER, HIGH);  delay(ONE_SECOND);
   digitalWrite(PORT_SHUTTER, LOW);
}

//------------------------------------------------------------------------
void loop()  {

   //  Read byte from serial ports
   char dataByte = readSerialByte();

   //------------------------------------------------------------------------
   //  Process command
   switch (dataByte)  {

      default:  {
         //Serial.print("# ");  Serial.println(dataByte, DEC);
      }  break;

      //------------------------------------------------------------------------
      case 'O':  {
         dataByte = readSerialByte();
         if (dataByte == '!')  {

            //  This is an immediate action (O!)
            openShutter();
            Serial.println("OK");
            break;
         }

         //  This should be setting (O0000!)
         unsigned int value = 0;
         do  {

            value = (value<<8)|dataByte;

            //  Read the rest bytes
            dataByte = readSerialByte()-'0';

         }  while (dataByte != '!');
         shutterOpenDuration = value;

         Serial.print(shutterOpenDuration, DEC);  Serial.println(" OK");
      }  break;

      //------------------------------------------------------------------------
      case 'C':  {
         dataByte = readSerialByte();
         if (dataByte == '!')  {

            //  This is an immediate action (C!)
            closeShutter();
            Serial.println("OK");
            break;
         }

         //  This should be setting (C0000!)
         unsigned int value = 0;
         do  {

            value = (value<<8)|dataByte;

            //  Read the rest bytes
            dataByte = readSerialByte()-'0';

         }  while (dataByte != '!');
         shutterCloseDuration = value;

         Serial.print(shutterCloseDuration, DEC);  Serial.println(" OK");
      }  break;

      //------------------------------------------------------------------------
      case 'F':  {
         dataByte = readSerialByte();
         if (dataByte != '!')  {break;}

         focusNow();
         Serial.println("OK");
      }  break;

      //------------------------------------------------------------------------
      case 'R':  {
         dataByte = readSerialByte();
         if (dataByte != '!')  {break;}

         framesTaken = 0;
         Serial.println("OK");
      }  break;

      //------------------------------------------------------------------------
      case 'I':  {
         dataByte = readSerialByte();
         if (dataByte != '!')  {break;}

         bluetoothSerial.print("f");
         bluetoothSerial.print(framesTaken, DEC);
         bluetoothSerial.print("o");
         bluetoothSerial.print(shutterOpenDuration, DEC);
         bluetoothSerial.print("c");
         bluetoothSerial.print(shutterCloseDuration, DEC);
         bluetoothSerial.println();

         Serial.print("f");
         Serial.print(framesTaken, DEC);
         Serial.print("o");
         Serial.print(shutterOpenDuration, DEC);
         Serial.print("c");
         Serial.println(shutterCloseDuration, DEC);
      }  break;

      //------------------------------------------------------------------------
      case 'G':  {
         dataByte = readSerialByte();
         if (dataByte != '!')  {break;}

         bluetoothSerial.print("Start ");
         bluetoothSerial.print(shutterOpenDuration, DEC);
         bluetoothSerial.print(" vs ");
         bluetoothSerial.print(shutterCloseDuration, DEC);
         bluetoothSerial.println();

         Serial.print("Start O");
         Serial.print(shutterOpenDuration, DEC);
         Serial.print(" vs C");
         Serial.print(shutterCloseDuration, DEC);
         Serial.println();

         framesTaken = 0;
         while (1)  {

            Serial.print("Open #");
            Serial.println(framesTaken, DEC);

            openShutter();
            delay(shutterOpenDuration*1000);

            Serial.print("Close #");
            Serial.println(framesTaken, DEC);

            closeShutter();
            delay(shutterCloseDuration*1000);

            framesTaken++;

            if (bluetoothSerial.available())  {break;}
            else if (Serial.available())  {break;}
         }
         Serial.println("OK");
      }  break;
   }
}

2014年12月17日 星期三

趕製《縮時拍攝裝置》・三


零件位置大概有個預算了,接著是外殻的鍊成。在《Inventor》畫了一個圓筒設計,蓋也畫了,同時也打印了。筒蓋接合得非常好。不過,有太多空間浪費了。於是畫了一個新的方型筒。打印出來後,發現左右那 0.5mm 的工差位是不夠,底板還是卡著,使出大一點力氣才能把底板推進筒中,而且耳機接口的空間也不足。有待改善。由於時間緊迫,還是把底板的零件焊接一起。明天還要重寫 Arduino 程式。

2014年12月16日 星期二

趕製《縮時拍攝裝置》・二


一年前打算趕製《縮時拍攝裝置》,最後都趕不上,項目一直閣置沒有理會。一年後的今天,在快要出發韓國時,又再燃起決心。外觀及軟件重新製作,只有三天時間,今回趕得切嗎?

上年外觀設計出來的實物,體積過大,放在相機上方顯得累贅,需要精簡空間。於是先從底板入手,把零件放得密一些,把 Arduino 及 BLE mini 置得貼一些,省下空間。找到了一個最迫而又對稱的設計。我喜歡對稱的美。

2014年12月12日 星期五

在 Mac 安裝 ffmpeg

公司快將推出一款包含很多影片資訊的流動應用程式。有大量的影片需要處理,例如:縮細解像度、檔案格式轉換、加入字幕、放置水印、影片剪接、製作預覽版本...等。為了能更有效處理這些事情,我選用了 ffmpeg 來幫忙。要在 Mac 機上安裝 ffmpeg 不難。首先到 http://ffmpegmac.net/ 下載最新版本,解壓並把檔案拷貝到 /usr/sbin/ 內。這樣便能在 Terminal 下執行 ffmpeg。

2014年12月11日 星期四

AMIGO Arm 設計・五


一覺醒來,物料沒有卡著,打印工作順利完成。看來手動把物料理順後,打印才變得安心。第一次印 30 度斜板,雖然有點方格紋理冒起,效果還是能夠接受。在沒有打印支架的情況下,仍然能保持型狀已經不錯。在放入 Futaba S3003 時,才發現設計時遺漏了置入時的空間及考慮,變得根本無法放入馬達 (T_T)。手術成功,但病人死了。今次又吸收了一點設計經驗。下次努力!

2014年12月10日 星期三

AMIGO Arm 設計・四


今日嘗試設計底座,盡量不以板金方式思考,因而得出這個設計。目前在打印中。單單一層圓盤就得花上 25 分鐘時間。看來打印完整個模型要七個小時。一覺起來便打印完成,如果唔卡料的話...。

2014年12月9日 星期二

AMIGO Arm 設計・三


邊設計邊製作的《AMIGO Arm》現在長成這個樣子了。有點像 Cute 版機械人。頂方還要接上手腕及蟹蚶手。不過,稍為嫌長度不久。組合完成後拿不到遠一點的東西。還有馬達數量應該可以再減少。再想想...。

2014年12月8日 星期一

創富媒體 13:女孩商機


文章刊登於「創富媒體

很多時都聽到一句說話「女人錢很容易賺」。我是相信的。同時,我亦很想開發出一套女性向的遊戲,賺這些女人錢。然而,靈感這樣東西不是想便一定會有;所以到目前還是空想。不過,最近我卻發現到一套遊戲,體現了這個想法。

大女剛踏入八歲,受到同學的感召,迷上了《星光少女 Pretty Rhythm》的《星光寶石 Prism Stone》。根據網上資料顯示,《星光少女》是日本玩具廠商 Takara Tomy、Syn Sophia 與南韓孫悟空玩具公司聯合製作的女性向跨媒體製作專案。於 2010 年 7 月 15 日推出。當中包含動畫、漫畫、大型遊戲機及手提遊戲項目。遊戲是以唱歌跳舞為主的節拍類玩法。遊戲是免費的。而《星光寶石 Prism Stone》則是放在大型遊戲機上使用的道具;最少一顆,最多五顆才能進行遊戲。跟網絡遊戲的設計一樣,每粒寶石擁有不同的服飾、舞蹈及能力。有些寶石是稀有的。寶石分為不同的包裝,最便宜的是一包兩顆;六粒裝、十粒裝的也有;甚至一套完整五粒的套裝也有。從包裝外看不出是甚麼寶石,抽到甚麼就看運數了。一顆平均 HK$15 的寶石,稀有版本可以炒賣到 HK$90 一顆。難怪有女孩告訴我曾用一顆寶石換來五顆。

一個用來放置寶石的膠盒,沒有寶石的,索價 HK$298。有了這個盒是很方便,值不值得真是見仁見智。然而,我面前的女孩身上已經帶著三個。每個都放滿寶石。更說家中還有部分沒有帶來。有這個財力之餘,也十分願意花錢。

這個生意還有一個特別之處,就是遊戲機的地點不多,全香港只有 49 台,賣寶石的地方不代表一定會有遊戲機出現。變相買了也有機會用不到。我曾試過帶女兒到有遊戲機的地方,可是一天兩節,每節只有兩小時的時段已過,沒有得玩。這應該是老闆想出來的鬼主意。因為她跟我說:「現時買包十粒裝的話,我可以立即開機給你,每個女兒可玩一局」。也曾試過到達店舖,但遊戲機壞了。老闆還叫我買點寶石而被我大罵。甚至按照店舖清單去過一個地點,那文具店已結業多時。得物無所用。

最終在父母家附近找到一家長開遊戲機的文具店,可是人龍有十人以上。每個女孩手上都有很多寶石,最少都有二三十粒。遇上裝備利害,身手靈活的女孩,一局遊戲花上五分鐘並不出奇。十個人便要等上五十分鐘,但還是大排長龍。女孩告訴我,現時已經少了人玩,高峰時人龍是目前的兩倍。可見這個遊戲的吸引之處。

2014年12月6日 星期六

BeyondZ 誠聘人才


Project Manager

Responsibilities
  • Work closely with project team to develop mobile applications
  • Brainstorm, develop and contribute to BeyondZ projects
  • Documentation, testing and quality assurance of the developed apps
     
    Requirements
  • Experience in Project Management
  • Experience in leading a programmer team
  • Experience interfacing Apps to server-side APIs
  • Experience building UI and Core App infrastructure
  • Experience with HTTP, XML, JSON, and Web Services via REST
  • Experience with multiple mobile platforms (iOS, Android, Blackberry, Windows mobile) is a strong plus
  • BS degree in Computer Science or equivalent
  • One or more Apps available for download
  • Know any programming language is plus
  • API and/or SDK development is a big plus
     
     
    Marketing Executive

    Responsibilities
  • Planning, advertising, distribution, sponsorship and research of BeyondZ mobile apps
  • Account services / management of clients' projects
  • Follow up the full set of project process and documentations
  • Feedback on consumers' comments
  • Exhibition / Roadshow Management
     
    Requirements
  • Work with passion
  • Creative and positive thinking
  • Degree holder or tertiary education
  • Strong interest in mobile industry
  • Spoken language : English, Cantonese and Potunghua
     
     
    Senior Mobile Apps Developer

    Responsibilities
  • Work closely with project team to develop mobile applications
  • Brainstorm, develop and contribute to BeyondZ projects
  • Documentation, testing and quality assurance of the developed apps
     
    Requirements
  • Solid Java programming
  • Experience interfacing Apps to server-side APIs
  • Experience building UI and Core App infrastructure
  • Experience with HTTP, XML, JSON, and Web Services via REST
  • Experience with other mobile platforms (iOS, Blackberry, Windows mobile) is a plus
  • BS degree in Computer Science or equivalent
  • 3-5 years of Android application development experiences
  • One or more Apps available for download
  • API and/or SDK development is a big plus
  • Candidates with less experience will be considered as Junior Mobile Apps developer
     
     
    Graphics Designer

    Responsibilities
  • Prepare mobile apps graphics for programmers
  • User interface design
  • Website design
  • Facebook apps graphics design
  • Other promotion materials design
     
    Requirements
  • Willing to learn
  • Good art and color senses
  • Passionate about drawings
  • Self motivated and able to work independently
  • A team player with good interpersonal and communication skills
  • Willing to work under pressure and work overtime to meet tight project schedule
  • Hands on experiences in iOS / Android / Facebook application is a strong plus
  • 3D modelling technique is a strong plus
  • 2014年12月5日 星期五

    ArrayZ 推料馬達問題


    AMIGO Arm 的中間部份設計好了,本想打印出來;可是 ArrayZ 再次出現問題。在列印的過程出,膠料沒有被推出。原因是推料的馬達無故地抽搐。亦即是推了少少又回抽少少。所以沒有物料能順利推出。經過一番檢查之後,發現是推料馬達的訊號線跟底板接觸不良。修理過後,目前運作良好。不過,在沒有搬動過的情況下,接線也會發生接觸不良的話,加上物料線又會出現打戟現象,打印起來還真是提心吊膽。看來 ArrayZ 要面向大眾用戶群時,還要有待改進。要是想簡簡單單使用的話,還是選 Makerbot 好一點。

    2014年12月4日 星期四

    AMIGO Arm 設計・二


    繼續 AMIGO Arm 的開發。今天打印的是底部關節。原本預留了 1mm 工差,但打印出來後卻容不下圓碟,唯有把工差加大至 2mm。重新打印。今次成功了。


    考慮了打印時地心吸力引發的問題,在設計時已經沒有加入枝節類的物件;同時要讓碟盤平坦,打印時要反過來打印。圓角的斜度也不能太高,否則將會打印失敗。

    2014年12月3日 星期三

    AMIGO Arm 設計


    ArrayZ 修復完畢。Windows 7 重灌了。Inventor 也裝好了。可以繼續開發工作。繼續以回收箱內的零件設計《AMIGO Arm》。對於整隻手臂沒甚麼頭緒,唯有邊畫邊改邊試。但還是有點想法,部件不要太過板金,需要多一點立體感。不過,原來這樣的設計不易,尤其是立體打印機能打印到出來的話,需要考慮的事情更多、限制更大。


    繪畫了部件,利用立體打印機打印。需時 4 小時,隔晚打印。早上起來,物料再次卡住,導致打印完成,但部件沒完成。雖然如此,還是可以利用部件試試尺寸及位置是否適當。0.5 豪米的出血位十分好用。部件跟伺服馬達配合得相當完美。沒有修改的必要。只要進料順利,便能成功打印兩個部件,組成下臂。

    2014年11月28日 星期五

    藍牙輔助通訊


    為客人開發的流動應用程式中,因為不知道使用時 WiFi/3G 的接收力為何,於是加入了新構思的「藍牙輔助通訊」設計。

    我設計的應用程式中,所有上傳或下載的工作都會有一條專屬隊伍負責。為的是當使用時沒有連線能力時,也能保存數據及繼續使用。當上網能力恢復後,積存在隊伍的工作便會依順序處理。雖然這個設計運作良好,但遇上需要多機同步的時候,便會出現時間延遲現象。自從 iOS 7 加入了 Multipeer Connectivity Framework 之後,方便了在離線環境下透過藍牙來作為潮通的渠道。今次設計是受到《FireChat》的啟發。當斷線時,數據除了會排入通訊隊伍外,還同時發送到在場附近的裝置,使得大家的數據同步一致。萬一其中一台裝置能成功連線,所有積存數據都會立即上傳到服務器;同時從服務器下載回來的資料,亦會發送到在場其他裝置。

    今天是客人在全國各地,包括香港舉行 VIP 活動的日子,經過一朝早的監察,運作十分暢順。日後有相類似的應用程式時,也可以繼續使用這個設計。

    插圖在 Lucidchart 製作

    2014年11月23日 星期日

    流動應用程式・第一課


    一連兩天到澳門教授《流動應用程式》的開發課程。這是我第一次成為老師角色。今次體驗了「教學相長」的感受,當教導別人時,更能考驗自己,檢視到不熟悉的地方。看到同學們努力學習,更使我傳授更多技術知識。同學們真的很聰明,希望他們能努力學習,應用在機械人操作上。

    2014年11月21日 星期五

    在 MacBook Air 上安裝 Windows 7

    早前在 MacBook Air 上安裝 Windows 7,主要是為了利用 Inventor 來繪畫精準的模型。雖然 Inventor Fusion 有 Mac 版本,但界面及操作都變差了,還是用 Windows 版得心應手。可惜數星期前 Inventor 壞了而無法啟動;重新安裝也沒有改善,唯有將整個 Windows 7 重灌。搞了一個星期也弄不到 USB 版的 Windows 7。後悔當初沒有好好記錄步驟。所以今次要來過記錄。

    製作 USB 開機手指
    1. 找一台裝有 Windows 7 的電腦
    2. 準備好 Windows 7 的 ISO 影像檔
    3. 下載 Windows USB/DVD Download Tool
    4. 啟動 Windows USB/DVD Download Tool
    5. 點選 Windows 7 的 ISO 影像檔
    6. 選擇 USB 手指
    7. 按「Begin Copy」
    8. 等待完成

    安裝 rEFIt
    1. 下載 rEFIt
    2. 雙擊 rEFIt-0.14.dmg
    3. 執行 rEFIt
    4. 按照指示進行安裝
    5. 重啟電腦

    安裝 Windows 7
    1. 插入帶有 Windows 7 的 USB 手指
    2. 重啟電腦
    3. 開機後會見到 rEFIt 的選單
    4. 點選 Windows 圖示後會從 USB 啟動 Windows 設定程式
    5. 跟平常安裝 Windows 進行安裝
    6. 如發現「Missing Operating System」則把 USB 插到其他 USB 口再重啟電腦
    7. 如發現 Partition 無法進行安裝,可嘗試格式化一次
    8. 完成

    2014年11月18日 星期二

    SMS 推送


    接了一個需要推送 SMS 的項目,同事找了一間便宜的。第一次推送完畢,發現推送到國內的 SMS 有一半是失敗了,而且我們還要為失敗的 SMS 付費。於是我們改用另一家聲稱為 Apple iReserve 做推送的公司。她的收費較貴,但有 Apple 作為客戶,信心增加了。為安全起見,還是嘗試發送四個號碼,結果是有四份三成功。比之前那一家有更高成功率,因此轉用新的 SMS 服務商。不幸的是,當我們正式推送時,失敗率卻提升到 40%。

    我們一直認為推送 SMS 是簡單的事,中間的通路做好了,概念上是一直能用下去。向服務商了解過後,原來失敗的原因有很多。漫遊有可能導致失敗、關機有可能導致失敗、飛線有可能導致失敗、使用聯通有可能導致失敗、八小時內多次推送有可能導致失敗、短訊內容使用 IP 地址有可能導致失敗、短訊內容有敏感字眼有可能導致失敗、同一個短率推送多次有可能導致失敗、電話號碼錯誤有可能導致失敗...。原來在國內做推送會遇到很多問題,今次學到很多知識和經驗。

    2014年11月17日 星期一

    把 Raspberry Pi 顯示旋轉 90 度


    Raspberry Pi 重灌後,又要側頭看我那垂直的顯示器。同樣地,又是忘了如何設置...。


    在 /boot/config.txt 可以優先設置 Raspberry Pi。這個檔案內的設定都會在啟動時先行載入後才正式啟動。當中把 display_rotate 選項改為 3 便會把顯示內容旋轉 270 度。與其說是旋轉是有點不對,因為 Raspberry Pi 會按旋轉後的闊高作為畫面,所以我的畫面才會變成直身。

    2014年11月16日 星期日

    燒錄 OctoPrint 到 SD 卡


    無論怎樣試,都無法把「ArrayZ」及「OctoPrint」成功連接。正確來說,連接是成功了,但卻控制不了、打印不了、溝通不了。我在想,會不會是 OctoPrint 的版本舊了?於是乎重新下載、重新安裝。可能是年紀大了,不記得上次是怎樣安裝,唯有重新搜尋。為免重蹈覆徹,還是在部落格記錄一下。

    在 Mac 機上使用「ApplePi-Baker」。左手面點選連接好的 SD 卡;右手面選好要燒錄的 Linux 影像檔,點「Restore Backup」,等待完成。把 SD 卡接上 Raspberry Pi 後開機,會彈出啟動選單。最主要是把空間擴展到整張 SD 卡。其他的都按需要設定就可以。

    2014年11月12日 星期三

    利用 mitmproxy 進行即時修改

    Modify Response on the Fly by using mitmproxy

    「mitmproxy」的功能基本上跟「Charles Proxy」是一樣。前者沒有圖像介面,支持 Python 指令;後者則簡單易用。我簡單編寫了一個 Python 程序來示範如何利用 mitmproxy 進行即時修改。把上圖的代碼儲存為 apple.py 後,在終端上輸入指令:mitmproxy --host -s apple.py 開始進行即時修改。


    如上圖所示,只要遇上是 apple.com 的 HTTP 請求,便會把內容「Bigger」變成「Smaller」,及把「iPhone 6」變成「iPhone 7」。

    2014年11月11日 星期二

    在 CentOS 下安裝 mitmproxy...

    「Charles Proxy」是一套很好用的 MITM 工具,但它是收費的。雖然是很值得,但總想試試其他免費的方案。「mitmproxy」就是其中一個。

    試過幾次失敗後,最終都能成功安裝在 CentOS 6。問題是出在 Python 2.6 及 Python 3.4。原來「mitmproxy」在 Python 2.7 才能順利安裝。要是使用 CentOS 7 的話,隨機附送的就是 Python 2.7。安裝「mitmproxy」的步驟如下:

    1. 下載 Python 的 PIP 工具
        wget https://bootstrap.pypa.io/get-pip.py

    2. 安裝 Python 2.7 的 PIP
        python get-pip.py

    3. 下載 Python 的 EZ Setup
        wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py

    4. 安裝 Python 2.7 的 EZ Setup
        python ez_setup.py

    5. 安裝需要的封包
        yum -y install python-pyasn1 python-flask python-urwid readline-devel gdbm-devel bzip2-devel ncurses-devel sqlite-devel tk-devel gcc python-setuptools python-pip python27-pip newt-python python-devel python27-devel python-pyasn1 pyOpenSSL gcc libxml2-devel libxslt-devel libffi-devel openssl-devel

    6. 安裝 pyOpenSSL 0.14
        easy_install http://pypi.python.org/packages/source/p/pyOpenSSL/pyOpenSSL-0.12.tar.gz

    7. 啟動 IP 地址及接口轉發
        sysctl -w net.ipv4.ip_forward=1
        iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
        iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8080

    8. 生成自簽的 CA 證書給 SSL 監聽之用
        openssl genrsa -out ca.key 2048
        openssl req -new -x509 -key ca.key -out ca.crt

        ... No need to fill out optional fields ...
        Common Name (eg, YOUR name) []:*.google.com (domain you want to MITM here)
        ...

        cat ca.key ca.crt < ca.pem

    9. 執行 mitmproxy
        mitmproxy --cert=ca.pem -T --host

    2014年11月10日 星期一

    ArrayZ: 挑戰 OctoPrint


    在購買 ArrayZ 之前已經試過用 OctoPrint 遙距操作。十分好玩。現在有了 ArrayZ,也想設定 OctoPrint。一來可以在公司也能控制家中的 ArrayZ,隨時打印;二來所有模型檔案能直接無線上傳,不用再煩複地又插又駁 SD 卡及把 .gcode 抄進去,十分方便。

    OctoPrint 是安裝在 Raspberry Pi 中;嘗試過用 USB 線運接 ArrayZ 及 Raspberry Pi,並為 Raspberry Pi 接上網線。這樣做的好處是開啟 ArrayZ 時 Raspberry Pi 也會同時亮起。後來發現 Raspberry Pi 會無法正常運作,還是要獨立外接電源。其實 ArrayZ 用的是電腦火牛,帶多條 12V 輸出,只要加裝 12V 轉 5V 的變換器,也能達到相同效果。

    參考過 https://www.octobox.org/setup/ 知道連接埠是 /dev/ttyACM0,速度是 115200 bps。按連接後狀態成功轉換成「Operational」。上傳 gcode 也十分快速方便。可是溫度監測沒有數據傳回。而 XYZ 軸則只有 Z 軸能接受指令。至於打印方面也沒有反應,未知是哪個部份出現問題,有待找出成因。

    2014年11月9日 星期日

    ArrayZ: 解決塞頭問題


    昨天跟朋友外出吃晚飯,離家前開始打印一年要花三小時的模型。回家後發現 ArrayZ 在空轉,沒有物料被擠出,因為耗材線打結了。

    把耗材線理順後再次打印,物料還是沒有被擠出,原來負責推送耗材的馬達早已把耗材線磨成兩段,只好拆下馬達把打印頭那段清除,並把耗材線重新注入。可是,物料還是沒有被擠出。從注入耗材線的深度來看,卡著的地方剛剛是打印頭上方的柱狀位置。

    打印頭似乎被物料塞住了。我把溫度調高至 190 度後手動插入耗材,希望能打開堵室了的通道。還是不行。這時想起 Chris 說過為免耗材向上溶解,特意在打印頭的散熱區加裝兩把風扇來加速降溫。我想這是導致打不通的原因。然而,在主選單中找到了設定風扇轉速的設定。把數值由 200 改到 0,風扇真的不轉了。再次把溫度調高至 190 度,手動插入耗材。今次成功了,終於把堵室了的打印頭打通了。

    2014年11月8日 星期六

    ArrayZ: 消除波紋效果

    ArrayZ: Waviness Elimination

    我的 ArrayZ 之前因 X 及 Y 軸卡住問題無法自行解決,於是找了它的父親 Chris 幫忙。昨天修理完成後第一時間取回家中,安頓好後嘗試再次打印。效果良好。


    頂圖左面是之前的打印,右面是今次的打印。今次同時改善了之前打印時出現的波紋效果(左面)。那是由於軸底承托部件產生的副作用,把它拿走不會影響打印工程,又能消除波紋效果,所以順便把部件拆下來。

    2014年11月7日 星期五

    創富媒體 12:密食當三番


    文章刊登於「創富媒體

    跟一個認識的人閒聊。說是認識,是因為她是朋友的朋友。我們未曾見面,但通過數次電話,了解比認識的層次高一點。她是做網頁製作生意,教了我一點心得。

    她一直都很忙,朝九晚十二。經常有數個網頁項目在做,數個在傾。她正在為一個項目的死線,尋求支援。十四年前科網炒作熱熾,能寫點 HTML 碼便能賺到可觀的金錢。科網爆破後,加上越來越多人懂得製作網頁,價錢已經跌到四位數字。我認識的世界中,只有講求創意、講求設計、講求體驗,甚至是整個活動配套一起包辦的項目,才能達到六位數字的價錢。原本以為網頁開發生意沒有得做,她卻能以「密食當三番」一招勝出。每個項目三至五萬,兩個月內起貨,同時做兩個項目。搞的都是帶點簡單程式的網頁;前台盡量簡化,後台管理介面盡量繼承以往項目的元件,減少開發時間,增加利潤空間。對我來說,這些是沒有挑戰性的工作,但多勞卻是多得。還有其他副作用。價錢較低,客動較容易下決定;由報價到落手落腳開工的時間亦比大項目來得短;開發完成後的意見修改也較為少。

    曾上過朋友開辦的「搵銀」課程,當中有一句說話特別深刻「簡單的事重複做」,十分認同。我曾嘗試把這個理念應用到手機程式生意。四年前編寫了一個以地方風景為主題的「找錯處」手機遊戲。同一個程式,換了不同風景,成為獨立一個遊戲。最後推出了以香港、日本關西、歐洲、全球,共三個版本。當時花了一個月時間開發遊戲。三個遊戲帶來的收入不算好但是不錯,似乎驗證了以上說法。可惜好景不常。當時研究出「付費>免費>付費」戰術也居功不少。收到外國律師信稱遊戲名稱太接近她們註冊的「Photo Hunt」而被迫下架。雖然把遊戲改名「TravelHunt」後重新上架,但累積了的排名算法經驗值卻一舖清袋。

    「簡單的事重複做」在現任公司也曾經推動過,但客戶委托開發的手機程式都很不同,能繼承的主要都是後台為主,省下的時間不多;而自行開發的應用又不想千篇一律,能繼承的更少。說穿了其實「自 High」居多,所以也做不出甚麼成積。不過,目前還沒有這個打算;假若碰到機遇,還是想再次實踐。

    2014年11月4日 星期二

    創富媒體 11:機械人兵團


    文章刊登於「創富媒體

    香港正值多事之秋,很多年青人正在為香港的未來而抗爭。社會的動盪令我想到戰爭。戰爭的觸發是在雙方勢均力敵時,或者是一方有著顯著的進步並為另一方帶來壓力時出現。

    近年四翼機大為流行,而價錢亦一直打滑。現時淘寶一架帶定位系統的四翼機大概為 HK$4000 左右;十架即是 HK$40,000;百架才是 HK$400,000。四十萬是一個不少的數目,足夠在日本買層樓做業主;但花得起的人也很多。要是有一百架四翼機到一地點作出攻擊,一定有點成效。就算沒有武器,單憑飛行速度及高度,以十幾公里十幾層樓的高度下墜,很難不造成人命傷亡。若配備武器更加不堪設想。

    機械人技術也越來越受到學生歡迎。兩年前,網上大學 Coursera 只有創辦人 Andrew Ng 一個教授關於人工智能的課程,現在卻有八個相關的課程,相信日後會越來越多。意味著機械人技術越來越普及。若遇上有資金在手的金主,兩者合作便能開發出小型軍隊。雖則要比人類優勝還有很長的路要行。但比起人類軍隊,精準度高及費用低卻是它的賣點;而且還能無限複製,以量取勝。然而,中國軍方已經想到這一情況,並開發出以雷射激光為主的反無人機技術。聲稱以 30 架無人機作測試,能 100% 擊落半徑兩公里內的低空無人機。每架最多鎖定五秒便能被擊落,看來是很精準的反無人機系統。似乎,第一次機械人大戰快將發生。

    2014年10月29日 星期三

    優化了的「編譯計」指令

    Revised Xcode Build Count Script

    用 Build count 都有四年時間,主要是方便分辨版本。很多時候,一個版本經反覆測試後才能推出給用家使用;這時的版本號及次版本號都不會作出改變,所以才加入「編譯計」來配合除錯,有效地分辨出哪些錯誤已經被修正、哪些問題是新增。這個 Build Count 邏輯在 Xcode 6 亦都加入,新上傳到 iTunesConnect 的 IPA 需要用上 CFBundleVersion 來分辨。於是我把本來用 BUILD_COUNT 的變量改為 CFBundleVersion。同時也把指令改為適合所有專案使用。他日建立新項目時,只要 Copy & Paste 指令即可,十分方便。

    2014年10月28日 星期二

    Xcode 6 iOS 8 模擬器位置

    Xcode 6 iOS 8 Simulator Location

    替新客戶開發 iPad App,發現啟動畫面沒有正確地顯示出來。試過幾個方法都失敗,打算看看圖檔是否正確地安裝;才發現模擬器位置已不再是 file:///Users/pacess/Library/Application Support/iPhone Simulator。在 iOS 8 SDK 下,新的位置換成 file:///Users/pacess/Library/Developer/CoreSimulator/Devices/4912D6BB-9028-445B-BC09-DF58A08FA569/data/Containers/Data/Application/5FEADE2A-0EDD-4711-BB1E-5802ECB69CBF/Documents/ 之外,當中的格式亦只剩下數據內容,程式本身不再跟數據一起...。


    最後找到原因是建立專案時沒有啟動畫面,雖然後來手動地在 Images.xcassets 中加入,但仍然要手動在 Project Settings 中 General 內設定 Apps Icons and Launch Images 裡的 Launch Image Source 才行。

    2014年10月26日 星期日

    機械設計


    整理一下家中的伺服馬達,有 11 顆 Futaba S3003,10 顆 TowerPro MG-995。放在一旁十分浪費,總想砌點東西。於是在 Inventor 中協助設計結構。打算製作一台有機械臂的車輪車。S3003 負重只有 5KG/cm,應該會很容易超出負荷,需要兩顆馬達同時推進。有兩個結構以為行得通,測試後發現只能水平移動,不能自由走動。


    後來又想試試用三顆伺服馬達製作能寫字的機器,於是又來設計一下。由於以往習慣設計適合用鋁板加工的部件,在擁有 3D 打印機的時間,大腦的構想還是跟不切,畫出來的部件很多時都是平面的。我想需要時間轉型。

    2014年10月25日 星期六

    2014年10月24日 星期五

    再畫 DMP RS-1270


    三天前畫的 DMP RS-1270 畫得不夠好,後來發現拍檔 Keith 三年前已經把它畫了出來,而且畫得不錯。於是向他找來 Inventor 的檔案。可是我的 Inventor 太舊而無法開啟。今晚女兒們早就睡著,反正有點時間,於是執筆再畫,終於完成一個滿意的版本。從圖中左手面可以看出是次版本的步驟多了一倍有多。

    DMP RS-1270 Servo by pacess on Sketchfab

    2014年10月21日 星期二

    DMP RS-1270


    在《RBL Hong Kong》中,我發現了很多機體都使用了 DMP RS-1270 伺服馬達。它們都表現出快速及強勁的力度,是目前《Tri-Robot》輸蝕的地方。原來 DMP RS-1270 能做到 35KG/cm 的強度,難怪有些機體能整台被抽起。曾經有一批賣到澳門的《Tri-Robot》也用上了 RS-1270。不過,這是一個等價交換的世界,好的東西是價錢也高一點,但是值得的。我也心血來潮,希望製作一架新的機體,用上《AMIGO Controller》之餘,也用上 RS-1270。因此在裝上找了點設計參考,同時也研究一下我很喜愛,由 Team Osaka 開發的 VisiON 系列。這是由很利害的日本機械人設計師《高橋智隆》所設計,亦是目前香港推出的《Robi》的作者。畫好了 RS-1270 之後,接下來便是機體設計工作。

    2014年10月20日 星期一

    天氣數據


    一直都想學習數據分折;一直都想把天氣跟股市數據合起來,看看有甚麼反應 。大部份的術數都是由天干地支為基礎,而天干地支則是時間的計算單位;在斷事時更會參考天氣狀況。我相信天氣會影響人們的心情及運作,股市是大部份人在交投,就算是程式買入賣出,背後也有人為因素;所以天氣應該會影響股市,從而影響某隻股票。我需要收集一些天氣數據作為實驗之用,在網上找到過往天氣資料,可是以 HTML 網頁方式呈現。於是編寫程式解拆當中數據,並儲架至私人服務器,有待日後嘗試不同的演算法,看看能否找出箇中玄機。

    2014年10月19日 星期日

    第一屆《Robot Boxing League Hong Kong》


    第一屆《Robot Boxing League Hong Kong》在 2014 年 10 月 19 日舉行。是次參賽對伍共 32 隊,小弟的《Tri-Robot》也是其中之一。可惜在比賽早上趕工編製動作數據時,分別弄壞了左手及右臀位置的關節,在沒有後備 Servo 的情況下,只好退出比賽。通宵了一晚的趕工付諸流水,那就專心拍攝精彩的照片吧。