發表文章

目前顯示的是 2025的文章

文章總列表

ANT+找樂子(2),解析心跳感應器和封包

圖片
整活啦 ANT+ Device Profile,Heart Rate Monitor 規格 ,心跳傳輸的速度約4Hz。 上一篇範例程式 速度怎麼搞都很慢,問Grok AI,或是Chatgpt答案都很怪,這種冷門知識還是得靠自己。這篇要講心跳表的定義,以及怎麼用openant讀出數值 心跳表的規格 RF頻率 = 2457Mhz(下表的57代表2400Mhz + 57Mhz) 心跳表用哪個頻率是規定好的 訊息發送間隔是32768/8070=4.06Hz,大多ANT+感應器操作在4Hz附近 Device Type是0x78,Transmission Type=1 為什麼Message Period不設定成8192(4Hz) 為了避免無線電波碰撞。ANT+讓每個裝置頻率略有不同,就算發生碰撞也是短時間,稍後還是會錯開。這個是很有智慧的設計! 直接操作Channel 不囉唆,直接上code node = Node(), set network key ANT+的公開鑰匙,幾乎99%的ANT+裝置都用這把鑰匙 ANTPLUS_NETWORK_KEY = [0xB9, 0xA5, 0x21, 0xFB, 0xBD, 0x72, 0xC3, 0x45] new_channel,開啟host(電腦)和裝置的通道,這個通道是雙向的 幾乎所有範例都是雙向,直接抄 set_period(8070) 根據上表,心跳表的週期是8070照著設定 ch.set_id(54345, 120, 241) # GARMIN WATCH ch.set_id(49528, 120, 1) # Magene 上述的code,連接Garmin Watch或是Magene心跳帶都可以 ch.open() node.start() 開始和ANT+裝置溝通 finally:     node.stop() 如果按CTRL+C,有機會能正確結束程式。不然在MAC經常要插拔Dongle才能恢復 解析ANT+封包 來自規格書的照片先來一張, 中文資料 byte0[bit7]叫Toggle bit,ANT+經常會重送資料以免接收端漏收,招數很土,但是有用 因為會重送,所以當封包內容改變,toggle-bit會變化;這樣接收端就能判斷是資料有變 byte0[bit6:0]叫page,這裡是一個編號,代表後面b...

ANT+找樂子(1),建構開發環境

圖片
緣起 Garmin單車碼表是高階貨色,行業的領頭羊。搭配ANT+感應器,心跳表,單車踏頻,功率計,然後就被鎖在Garmin宇宙了。寫年度考績表實在壓力太大了,我決定深入看看ANT+協定,找樂子 找樂子工具 我用這些東西找樂子,他們不難找 Macbook AIR M2 ANT+ Dongle,下圖左邊的收訊很爛,右邊的好多了,不過都可以用 ANT+ Dongle再說個兩句 右邊的Dongle插入電腦顯示以下資訊,USB廠商識別碼0xFCF(4047),加拿大Dynastream公司在2003年發布ANT規格,2006變成GARMIN子公司 設定開發環境具體步驟 寫下來,下次重灌電腦可以用 取得libusb,和USB Dongle打交道 Windows也許有安裝包可以下載 MAC靠 homebrew 裝,我有點抗拒怕把系統弄亂。反正就找樂子,裝吧 連進他的網站,命令直接複製貼上 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 操作brew brew update // 更新brew工具 brew install libusb // 安裝libusb brew install joe // 安裝我慣用的editor, joe (這一步可跳過) brew list // 列出所有安裝的包裹 設定 openant 開發環境,已經有人包好方便的Python套件,找樂子,裝吧 建立獨立antdev開發環境,和系統Python隔開 python3 -m venv antdev 啟用開發環境 & 升級pip cd antdev source bin/activate pip install --upgrade pip 安裝openant開發包 pip install openant 掃描ANT+裝置 打開手錶的心跳廣播,戴上心跳表,或是讓任何ANT+裝置醒過來 輸入命令尋找ANT+裝置 openant scan 下圖找到裝置 - ID=54345 - Device_type=120 - Transmission_type=241 解析ID 稍微聊一下上面找到的ID,基本上ANT+裝置 完整ID 是32bit,由三個...

單車內搭衣指南

圖片
緣起 我一直想知道單車內搭衣,到底有沒有用。我前後測試非常多件,寫一下comment 96單車內搭衣 迪卡儂399內搭衣 ATLAS秋冬內搭衣 SHIMANO內搭衣 Q36.5 base layer0/ base layer1 新竹風城單車出清CABALLERO內衣 淘寶EVR內搭衣 內搭衣主要有四種材質,他們幾乎不會壞,這裡有 常見布料 介紹 聚酯纖維(可以上色) 聚丙烯(只有白色,繩子,超疏水) 尼龍(亮亮的,滑順,但是容易起毛) 彈性纖維(萊卡,Spandex) 內搭衣穿一整天 穿迪卡儂399當睡衣,衣服太透氣了,根本不聚熱,睡覺冷得要死;隔天套上T-Shirt/襯衫上班,辦公室有空調,一整天感覺冷冷的,這衣服不能替代棉質內衣 車衣+內搭衣,在戶外騎車 我騎觀霧來回大概10H,夏天單穿車衣,流汗流到衣服黏在身上 多一層內搭衣,保證車衣不黏皮膚;網狀材質的衣服不會黏在身上,不管是聚酯纖維,聚丙烯,尼龍,導汗效果都很好。只要拉下拉鍊,風加減能穿到身體,不會被濕車衣全部擋住 外騎我一定穿一件,只要沒有 熱到沒風 ,基本上都有好處 室內騎車的實驗 踩訓練台穿車衣加內搭衣,超白癡的實驗,多一層一定更熱啊!在室內穿內搭衣比較涼,也能避免汗亂噴,踩台我穿內搭衣 內搭衣+車衣(熱到受不了) 車衣(流汗衣服黏在身上) 內搭衣(電風扇能吹到身上) 內搭衣PK 我買了那麼多件,應該有資格說個兩句 聚酯纖維容易染色,所以顏色繽紛的貨色,大多是聚酯纖維 迪卡儂有 399 (聚酯纖維80%)和 749 (聚丙烯40%+尼龍40%)兩種內搭衣,我問grok AI差異,他說聚丙烯布料排汗效能最頂,只是難以染色,幾乎都是白色。也許我該去買一件749實驗看看 ATLAS秋冬款 是100%聚丙烯,非常透氣,比較厚 SHIMANO VERTEX內搭衣 是85%聚丙烯,蝦皮買從印尼雅加達寄來。和ATLAS接近 96單車內搭衣 比較薄,應該是聚酯纖維,穿起來比迪卡儂399涼 Q36.5 base layer 0 ,數字最小,應對最熱的天氣,非常薄,穿起來非常涼 Q36.5 base layer 1 ,比layer 0稍微厚一點,材料多一點 中國EVR內搭衣,網布比較大顆,保證隔開衣服和皮膚 CABALLERO網站停在2017,應該沒營業了。以尼龍為主力(90%),加上萊卡(10%)。標價1280出清20...

軟體架構,流程類軟體指南

圖片
緣起 在軟體裡,有些地方是流程(flow),目的是把別人叫起來。至於對方做什麼,其實我們不在意。這種軟體寫起來有些注意事項 開機流程範例 一般會有個進入點,對每個模組初始化,長得像下面這樣 // init.c extern void mod_a_init(u32 evt); extern void mod_b_init(u32 evt); typedef void (*func_fp)(u32); void init_flow() {     func_fp tbl[] = {         mod_a_init,         mod_b_init,     };     func_exec(tbl, sizeof(tbl)/sizeof(func_fp), EVT_BOOT); } 流程的比喻:貨輪 海運的貨櫃是標準化的服務,以貨櫃作為運送的單位。上述流程要求大家參數一致,讓流程呼叫 void (*fp)(u32); Function prototype 的用途 呼叫函數的約定(Calling Convention)定義在ABI(Application Binary Interface)裡。因為每次都會忘記,寫下這些詞彙當筆記 以範例的函數,第一個參數放r0,再用rcall指令跳進去。編譯器知道函數原型,比如幾個參數,各自的型別,才能正確呼叫 為什麼直接寫prototype,而不是吃對方的header file 不要吃模組的header,例如mod_a_intf.h,原因如下 軟體分層的邏輯,一般是上層應用吃底層的介面,沒有反著走的。init.c顯然是底層服務(例如長榮貨輪),他只要知道呼叫哪個函數,以及對方的參數正確(合乎貨櫃規格),不用全套知識(mod_a_intf.h) 防禦性設計,我們希望init.c固若金湯。如下面範例,mod_a_intf.h故意把SOME_OPTION轉ANOTHER_OPTION;假如init.c得看到SOME_OPTION,吃下去會出事 #if defined(SOME_OPTION)     #undef SOME_OPTION     #defi...

軟體架構,C語言,維持Header file彼此獨立

圖片
緣起 我提供某個服務service.h給大家用,今天要講裡面SERVICE_SZ_A參數的故事 // service.h #define SERVICE_SZ_A (10) struct {     u32 user_a_data[ SERVICE_SZ_A ] } 來自USER_A的抱怨 SERVICE_SZ_A 其實是USER_A維護的,在另外一個地方也定義了 // user_a_intf.h #define USERA_SZ (10) 兩個參數放在兩個檔案,不一致會出錯,現在我們有 維護問題 了 service.h user_a_intf.h 來自USER_A的建議 簡單粗暴,希望這個參數,統一由USER_A提供,不要再自己定義了 // service.h #include "user_a_intf.h" // avoid the interface duplication struct {     u32 user_a_data[ SERVICE_SZ_A ] } 我不打算接受這個建議 service.h想維持獨立(不依賴別人) 其他吃service.h的人,未必需要user_a_intf.h(介面的污染) 如果user_a_intf.h如果也吃service.h,會產生circular inclusion,有潛在的問題 最後的解法 最後我們找到完美的解法,既可以維持介面獨立,又可以解決維護問題,兩個人都滿意 服務端service.h 維持獨立 ,最終的長相就是那樣 在USER_A多放user_a_err_chk.c做檢查,工作量不多 // user_a_err_chk.c #include "service.h" #include "user_a_intf.h" #if SERVICE_SZ_A != USER_A_SZ     #error #endif 在需要保持介面獨立的地方,做個副本(duplication),然後再找地方檢查,大家就開心了 這題我遇過很多次,腦袋得稍微轉彎,我預期以後還要再用。寫下來,下次可以直接用 問AI的意見 這題應該有前人解過(Internet找得到),問問AI的看法,看起來是沒問題的

中雙塔專案,結案報告,Day#2

圖片
上路吧 準備車子比較簡單,補好破胎,充飽電,檢錄完就搞定了;人繼承昨天疲勞,腳酸酸,人累累,站上起跑線也算準備完成。今天要騎塔塔加公路,在阿里山區繞,從甲仙出來,再南下直奔鵝鑾鼻,里程417K,4500M爬升,限時28H 日月潭 大會幫我拍到一張照片,賺大啦 3H06,11:06,65K,CP1和社門市 騎下日月潭,穿過水里龍神廟,我最期待的 塔塔加公路 來了。電動玩具(Rouvy)的Tatajia Hill Climb我刷過三次, 真實世界 全景的震撼,陳有蘭溪橋樑蜿蜒曲折,騎過樹木光影精細變化,連續而細膩的坡度起伏,光騎這段今天就值了 騎到和社門市3H如預期喝完兩壺水(500ml/H),爬塔塔加公路最後補給點,吃泡麵補滿電解質,再外帶手捲,整備25分鐘再上 6H35,14:35,107K,CP2塔塔加(+1842M) 剩下爬坡1800M大概要3H;兩壺水填裝125ml糖漿和運動飲料,一壺再加迪卡儂蔓越莓BCAA粉甜死人,剛好到山頂喝光。整數路牌吃蔓越莓,0.5吃運動飲料,沿路自動補水補膠 兩個手捲,一個在1H吃,另外一個山頂吃,確保有柴燒 爬山約1.5H遇到 KMCC高美車隊 的 大丹哥 ,感謝您的水和可樂;路上也遇到同車隊的 優尼克 ,兩位前輩的文字紀錄提供大量情報,讓我制定計劃,勇敢在這裡騎車,再次感謝 2023大丹哥 北段紀錄 , 南段紀錄 2024優尼克 北段紀錄 , 南段紀錄 預想不到, 訓練方式 , 2024參賽心得 瘋系列參賽心得 檢錄點提供薑茶,咖啡,搭配山下帶上來的手捲,吃飽喝足繼續走 塔塔加公路終點(21)/阿里山公路終點(18) 這張圖可能有用,過了這裡,路牌變成台18線 8H27,16:27,151K,石槕門市 阿里山公路混雜著緩下坡,陡下坡,上坡,並不是輕鬆滑到目的地。框煞下坡,而且是不熟悉路段必須拉長煞車距離。照車友建議在石槕門市補滿水 9H23,17:23,176K,CP3山美大橋 溜往龍美遇到磅礴大雨,參加瘋系列活動淋淋雨才對味。左轉嘉129下切到達娜伊谷,溜得我瑟瑟發抖,煞車在抖動啊! CP3山美大橋,吃瘋系列傳統的雞腿麵兩碗,稍微休息,準備騎今天最凶險的路段 13H45,21:45,242K,甲仙門市(66K/ 4H22) 從山美大橋,穿過青山巷到台29線的地圖如下,在蜿蜒曲折沒燈的山區前進。下過雨後非常潮濕,爬升913M照著...

中雙塔專案,結案報告,Day#1

圖片
2025/10/10,下午2點搭上大會接駁車前往富貴角,感謝家人支持讓我來玩,開騎前和夕陽合影 今天騎中雙塔北段328K/22H/6500爬升,能力所及的準備都做了,上吧 陽金公路 台北市 北宜公路,宜蘭 北橫宜蘭支線,南山,思源啞口,環山,梨山 大禹嶺,武嶺 埔里箱根 1H38M,20:38,24K,CP1二子坪停車場 巴拉卡公路大概6%爬升1000M,經過萊爾富左轉,看到于右任墓就快到山頂 3H19M,22:19,57K,北新門市 摸黑下山撞上坑洞,主力燈具扣具掛了,心慌慌,沒這顆燈就不用比了。還好燈具是Garmin接頭,碼表座裝頭燈解決這題 穿過台北市紅綠燈地獄回回血,看到新店捷運站補滿水要爬北宜了 5H36M,00:36,102K,CP2縣界公園 我唸大學單車環島兩次,騎過一次北宜,以前路上還有人撒冥紙供奉亡魂,現在路旁乾淨多了。北宜公路大概50K爬升1000,難度不高也得要2H通過;而且得留力北進武嶺。踩到縣界公園,和家人報平安,我跳過龍蝦泡麵先下山了 我第一次深夜騎往宜蘭,停下來看了好幾次夜景。現在會早早扣下煞車安全下山,下坡不敢飆車了。不曉得我騎北宜最佳時間是20年前的我,還是今晚呢(笑) 6H56M,01:56,134K,宜蘭內城門市 生理時鐘的威力來了,溜下北宜,在蘭陽平原騎車,理論上都要快速推進;可惜現在是睡覺時間,騎得軟爛無比,使不上力 2024/11雙塔520,AM12出發 2025/2東三塔,AM1在台東東河 2025/10中雙塔,AM1在蘭陽平原 撐到內城門市,北進武嶺最後補給點,再來得騎3H/60K到南山,吞下補給繼續趕路 BCAA膠囊*8 咖啡因膠囊*2 鹽巴膠囊*2 三角飯糰*2 8H25M,03:25,160K,百韜橋 以前農曆年,我從新竹騎車走北橫到宜蘭,每年都會被阿嬤罵,罵幾次還是要騎 2009年換工作,排單車之旅當畢業旅行。第二天騎到梨山腳軟軟,肩酸酸,偷雞找汽車幫我載背包外套去關雲山莊,然後糗大了。太陽下山越來越冷,想催速度也沒有,最後又黑又冷嚕到觀雲山莊 Day#1新竹 - 北橫 - 宜蘭羅東 Day#2羅東 - 中橫宜蘭支線 - 觀雲山莊 Day#3觀雲山莊 - 武嶺 - 太魯閣 當年還是小鮮肉騎三天都覺得難,過了16年參加中雙塔,一天抵三天,當然瑟瑟發抖 車友#155在百韜橋喊住我,補滿水,來罐紅牛。台七甲全線暗摸摸...