2015年5月12日 星期二

讓AutoCAD圓柱體模型表面更精細

AutoCAD 3D模型可以匯出為 .stl 檔給3D印表機列印,但是列印出來時為什麼精細度不是很好? 如下圖:


改變 AutoCAD 系統變數「FACETRES」可以調整圓弧面的精細度。

FACETRES 的值愈大愈精細。

因為 AutoCAD 系統變數「FACETRES」的預設值是 0.5,所以才會出現如上圖的很多摺邊。

您可以將 FACETRES 的值調大一些(例如 10),列印出來的精細度就會好多了,如下圖:


2015年5月11日 星期一

const vs. #define

大家都知道 Arduino 可用的記憶體非常少,以 UNO 來說它能用來存放變數的靜態記憶體只有 2k,所以在避免超限使用記憶體的情況下,使用 const 或 #define 哪一個會比較節省記憶體呢?


#define 是甚麼?

#define 經常被誤以為是一個程式函式,其實它不是。事實上,它的作用只是會在程式被編譯前將文字內容相互替換而已。例如我們編寫 define.ino 程式碼,如下:

#define PIN 13
void setup() {
  pinMode(PIN, OUTPUT);
}
void loop() {
  digitalWrite(PIN, HIGH);
  delay(500);
  digitalWrite(PIN, LOW);
  delay(500);
}

在 IDE 將程式碼送到編譯器編譯之前,預置處理器會先做一個簡單的內容置換,將 PIN 置換為 13,所以其實編譯器編譯的內容會是如下程式碼:

#define PIN 13
void setup() {
  pinMode(13, OUTPUT);
}
void loop() {
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
}

上述是一個強大且實用的功能,沒有任何記憶體被 "PIN" 這個變數所耗損。事實上,所有程式碼當中並不存在一個叫作 "PIN" 的變數。


const 是甚麼?

關鍵字 "const" 告訴編譯器它是一個不能被編譯的變數(或指標)。然而,它仍舊是一個變數,你要如何使用它,就看你在程式碼當中的使用方式了,或許會也或許不會因而耗損到記憶體。事實上,編譯器藉由使用 IDE 和 avr-gcc 已經聰明到可以辨識具有常數修飾子(const modifier)的變數是不能在程式運作時去改變它的值的,並且它也會試著去避免使用到記憶體。

例如,我們編寫 const.ino 程式碼,如下:

const int pin=13;
void setup() {
  pinMode(pin, OUTPUT);
}
void loop() {
  digitalWrite(pin, HIGH);
  delay(500);
  digitalWrite(pin, LOW);
  delay(500);
}

它將不會耗損任何記憶體,編譯器知道它沒有理由可以在記憶體內建立一個變數,所以原本的記憶體空間還是保存著。


使用 avr-size

您可能已經注意到,在 Arduino 的 IDE 編譯程式碼時,狀態窗口會顯示如下這樣的訊息:


這個"草稿碼二進位的大小"訊息指的是經過編譯後的十六進位檔案(.hex)佔用多少快閃(Flash)記憶體的大小,請注意,它並未指出這個程式碼使用了多少靜態記憶體。

那麼要如何才能知道使用了多少靜態記憶體呢? 我們可以使用 avr-gcc 工具箱裏面的 avr-size.exe (它的路徑是在 <Arduino>\hardware\tools\avr\bin) 去查詢 .elf 檔案 (它的路徑是在 C:\Documents and Settings\USER\Local Settings\Temp\build<一串數字>.tmp 資料夾裏)。

因為我們要比較 define.ino 和 const.ino 各自使用多少靜態記憶體,所以您應該分別編譯這兩個檔案。

由於待會兒我們要在命令視窗下執行,為了方便起見,您可以將 avr-size.exe、define.cpp.elf 和 const.cpp.elf 複製貼到 D:\ 裏面。

現在請開啟命令視窗,並切換路徑到 D:\,然後鍵入

avr-size -C define.cpp.elf

然後您可以看到它顯示如下畫面:


接著再鍵入

avr-size -C const.cpp.elf

然後您可以看到它顯示如下畫面:


結果~~~~讓人非常驚訝對吧? 它們所耗用的記憶體竟然是相同的,都是 9 bytes。


那麼到底使用哪一個比較好?

筆者建議您使用 const 的方式會比較好。因為如果您不小心把 #define PIN 13 寫成 #defun pin 13 (注意 PIN 變成小寫的 pin),如下:

#define pin 13
void setup() {
  pinMode(pin, OUTPUT);
}
void loop() {
  digitalWrite(pin, HIGH);
  delay(500);
  digitalWrite(pin, LOW);
  delay(500);
}

或是不小心把 #define PIN 13 寫成 #defun PIN 13; (注意在13的後面多了一個分號),如下:

#define pin 13;
void setup() {
  pinMode(pin, OUTPUT);
}
void loop() {
  digitalWrite(pin, HIGH);
  delay(500);
  digitalWrite(pin, LOW);
  delay(500);
}

那麼在編譯時將會產生錯誤,而這個錯誤是不太容易發現是在哪兒出錯的,如下圖:




相關文章

有關於 const vs. #define 的社群討論 http://forum.arduino.cc/index.php?topic=86800.15

hex 檔 http://pizgchen.blogspot.tw/2015/04/hex.html

2015年5月7日 星期四

枚舉(enum)

如果我們能善加使用 enum 的功能,產生更短的且可讀性更好的代碼,將是非常有益的

我們知道 Java 支援 enum 語法,但其實 Processing 並不支援 enum 語法。雖然您可以在 Processing IDE 裏看到 enum 這個關鍵字會變色,而且您也遵循它的使用規則建構枚舉資料,可是在編譯時它會產生這樣的錯誤:

Unrecognized type:46 (ENUM_DEF)

雖然如此,我們還是可以找出一個辦法來解決這個問題。從現在起您必須記住,您無法像 Java 那樣把 enum 跟主程式寫在一起,而必須把 enum 寫在另外一個頁籤(Tab),然將它的延伸檔名命名為 .java 即可,如下:

主程式:

Day day;
         
void setup() {
  println(day.FRIDAY);
}

void draw(){}


新建一個頁籤,並將它命名為 Day.java

public enum Day {
  SUNDAY, 
  MONDAY,
  TUESDAY, 
  WEDNESDAY, 
  THURSDAY, 
  FRIDAY, 
  SATURDAY

}; 


start()

一般寫 Processing 程式的人都知道,一個最基本的程式架構必須包括 setup() 和 draw() 這兩個函式,如下:

void setup() {
}

void draw() {
}

而且一直以來都以為第一個執行的函式是 setup(),其實不是如此。

請您將下列程式碼鍵入 IDE 並執行,

void start() {
  println("start");
}

void setup() {
  println("setup");
}

void draw() {
}

結果您會發現訊息欄印出的是

start
setup

所以結論是:

第一個執行的函式是 start(),Processing 主要是用它來做初始化的動作,接著才是執行 setup()。

那麼問題來了,Arduino 是否也隱藏有這樣的玄機嗎?








2015年5月5日 星期二

Upload 位於 SD Card 內的 .hex 檔


https://github.com/osbock/Baldwisdom/tree/master/BootDrive

https://github.com/thseiler/embedded/tree/master/avr/2boots


下載 Youtube, 土豆...等影片

轉載 http://briian.com/10070/fvd-video-downloader.html



讀取 Yahoo 氣象資訊

Yahoo 網站提供免費的氣象資訊,包括溫度、濕度、風速、風向、能見度和大氣壓力...等,我們可以使用 Processing 取回這些資訊,將它顯示在電腦螢幕上,或是傳給 Arduino 等互動裝置。


下載 Library

切換到網頁 https://github.com/onformative/YahooWeather ,點選右下角落的「Download ZIP」按鈕。或是點按網址 http://www.onformative.com/uploads/googleWeather/YahooWeather.zip 直接下載。

下載後解壓縮,並將他複製到 <Processing>/libraries 資料夾內。最後,別忘了要退出 Processing 再重新啟動。


開啟範例圖檔

內建的範例程式可以讓您快速感受到取得氣象資訊是多麼容易的一件事。

點按下拉功能表 File > Examples...,再展開 Contributed Libraries > Yahoo Weather 並雙擊 WeatherSimpleExample。

程式碼如下:

import com.onformative.yahooweather.*;

YahooWeather weather;
int updateIntervallMillis = 30000;

void setup() {
  size(700, 300);
  fill(0);
  textFont(createFont("Arial", 14));
  // 2442047 = the WOEID of Berlin
  // use this site to find out about your WOEID : http://sigizmund.info/woeidinfo/
  weather = new YahooWeather(this, 638242, "c", updateIntervallMillis);
}

void draw() {
  weather.update();

  background(255);
  text("City: "+weather.getCityName()+"; Region: "+weather.getRegionName()+"; Country: "+weather.getCountryName()+"; Last updated: "+weather.getLastUpdated(), 20, 20);
  text("Lon: "+weather.getLongitude()+" Lat: "+weather.getLatitude(), 20, 40);
  text("WindTemp: "+weather.getWindTemperature()+" WindSpeed: "+weather.getWindSpeed()+" WindDirection: "+weather.getWindDirection(), 20, 60);
  text("Humidity: "+weather.getHumidity()+" visibility: "+weather.getVisibleDistance()+" pressure: "+weather.getPressure()+" rising: "+weather.getRising(), 20, 80);
  text("Sunrise: "+weather.getSunrise()+" sunset: "+weather.getSunset(), 20, 100);
}

public void keyPressed() {
  if (key == 'q') {
    weather.setWOEID(638242);
  }
  if (key == 'r') {
    weather.setWOEID(44418);
  }
}

點擊「Run」按鈕執行程式,就可以看到如下畫面:


目前顯示的是德國柏林(Berlin)的天氣,按下鍵盤的 'r' 鍵可以顯示英國倫敦(London)的天氣,按下鍵盤的 'q' 鍵可以再顯示柏林的天氣。



顯示台灣城市天氣資訊

要顯示各地區氣象資訊的關鍵是甚麼? 答案是「WOE ID」,只要改變 WOE ID 就可以顯示不同區域的氣象資訊。

範例程式中德國柏林(Berlin)的 WOEID 是 638242,英國倫敦(London)的 WOE ID 是 44418,那麼台北的 WOE ID 是多少呢? 您可以到這個網頁

https://weather.yahoo.com/taiwan/

選擇清單中的台灣各地區城市。

我們以台北為例,請您點按 Taipei City,在新頁面內再點按一次 Taipei City,網頁會跳到

https://weather.yahoo.com/taiwan/taipei-city/taipei-city-2306179/

網址最後面的數字就是台北的 WOE ID。



您可以用這組數字取代掉程式碼中的 638242,如下兩行:

weather = new YahooWeather(this, 638242, "c", updateIntervallMillis);

weather.setWOEID(638242);

如果要查其他地方的 WOEID,可以直接在搜尋欄位內鍵入地名或郵遞區號。


我們再以桃園為例,在搜尋欄位內鍵入「taoyuan」,就可以得到網址

https://weather.yahoo.com/taiwan/taoyuan-county/taoyuan-city-2298866/

所以桃園的 WOE ID 為 2298866。


最後,我們要顯示台北和桃園的氣象資訊,程式碼如下:

import com.onformative.yahooweather.*;

YahooWeather weather;
int updateIntervallMillis = 30000;

void setup() {
  size(700, 300);
  fill(0);
  textFont(createFont("Arial", 14));
  weather = new YahooWeather(this, 2298866, "c", updateIntervallMillis);
}

void draw() {
  weather.update();

  background(255);
  text("City: "+weather.getCityName()+"; Region: "+weather.getRegionName()+"; Country: "+weather.getCountryName()+"; Last updated: "+weather.getLastUpdated(), 20, 20);
  text("Lon: "+weather.getLongitude()+" Lat: "+weather.getLatitude(), 20, 40);
  text("WindTemp: "+weather.getWindTemperature()+" WindSpeed: "+weather.getWindSpeed()+" WindDirection: "+weather.getWindDirection(), 20, 60);
  text("Humidity: "+weather.getHumidity()+" visibility: "+weather.getVisibleDistance()+" pressure: "+weather.getPressure()+" rising: "+weather.getRising(), 20, 80);
  text("Sunrise: "+weather.getSunrise()+" sunset: "+weather.getSunset(), 20, 100);
}

public void keyPressed() {
  if (key == 'q') {
    weather.setWOEID(2298866);
  }
  if (key == 'r') {
    weather.setWOEID(2306179);
  }
}


相關文章

Onformative http://www.onformative.com/lab/google-weather-library-for-processing/

Python Weather API https://code.google.com/p/python-weather-api/