속도-파워 그래프를 얻었으니 이제 실내 자전거의 속도를 얻어내려면 어떻게 해야 하는지 알아보겠습니다.
일단 자전거에서 뭔가 속도를 얻어내는 센서에는 2가지가 있습니다. 첫번째는 바퀴에 부착되어 현재 자전거의 속도를 계산해내는 속도(speed) 센서이고요, 다른 하나는 페달에 부착하여 현재 페달의 회전수를 알아내는 케이던스(cadence) 센서입니다.
아래가 스피드 센서.
이게 케이던스 센서.
보통 헬스케어/피트니스 제품들에서는 ANT+라는 무선 프로토콜을 사용합니다. 근래 많이 쓰이는 BLE와 유사한 면이 많은 저전력 프로토콜인데요, 역사는 생각보다 오래 되었습니다. 각종 심박계나 자전거 센서들, 런닝용 발걸음 센서, 저울, 산소측정기 등도 사실상 거의 모두 ANT+ 프로토콜을 사용합니다. 근래에는 ANT+와 BLE를 동시에 지원하는 경우도 나오기는 합니다만, 여전히 대세는 ANT+ 프로토콜입니다.
속도 센서와 케이던스 센서, 두 센서의 프로파일을 비교하며 살펴보니 두 센서 모두 1회전당 1회의 펄스가 나오는게 원칙인데, 몇회에 걸쳐 누적된 수치를 한번에 보내주기도 하는 등 행동 양태에 따른 차이점은 거의 없습니다. 두 센서의 송출 데이타상의 차이점은 Device Type이 속도 센서는 0x7B이고, 케이던스 센서는 0x7A인 점이 다를 뿐입니다.
한가지 더 꼽아보자면, 센서의 데이타 수집 주기가 4Hz 내외라서 1초에 4회 정도씩 수집하도록 되어 있는데, 속도 센서는 8118/32768초에 한번씩, 케이던스 센서는 8102/32768초에 한번씩 데이타를 수집하는 것이 기본입니다.
두 센서 모두 Roll-over time은 64초, 65536회전입니다. 이 처리도 필요합니다.
실내 자전거에는 바퀴가 따로 없이 바퀴의 회전수가 곧 페달의 회전수이기 때문에 둘 중에 아무 센서나 사용해도 상관이 없습니다. 가격도 2가지 센서 거의 동일합니다. 다만, 원래 페달의 크랭크에 설치하기로 되어 있는 케이던스 센서가 좀 더 부착이 쉬우므로 이것을 사용하기로 합니다.
센서에서 펄스가 올 때마다 지난번 펄스의 시간과 대조하여 해당 구간의 델타 속도를 계산해낼 수 있습니다. 제대로 현재 속도를 표시하기 위해서는 델타 속도의 변화 추세를 미분하여 평탄화 작업을 해줘야 하지만, 우리의 목적은 어차피 역시나 해당 델타에서의 파워값만 얻어내어 무책임하게(?) 쏴주면 그 다음에는 속도계에서 알아서 할테니 굳이 복잡한 계산은 생략해도 별 지장 없습니다.
소스는 맨 아래에 있습니다. 페달을 돌려보니 아래와 같은 속도와 파워값 결과가 나옵니다.
대략 데이타의 적절성을 살펴보면..
REVO=21일때, 속도가 18.78mile/h일때에 149.29W가 나옵니다.
REVO=44일때, 속도가 34.27mile/h일때에 452.55W가 나오는걸 보니 몸이(허벅지가^^) 기억하는 파워값과 크게 다르지 않은 파워값을 얻어내는걸 알수 있습니다.
페달을 밟는 속도에 따른 파워값을 얻어낼 수 있으니 이제는 이걸 Zwift 게임에 쏘아주면 됩니다. 이 부분은 다음번에...
# -*- coding: utf-8 -*- import sys import time from ant.core import driver, node, event, message, log from ant.core.constants import CHANNEL_TYPE_TWOWAY_RECEIVE, TIMEOUT_NEVER import binascii import math
# 바퀴 크기 CIRCUMFERENCE = 5000 def convertSB(raw): value = int(binascii.hexlify(raw[1]),16)<<8 value += int(binascii.hexlify(raw[0]),16) return value
class SPEEDPOWER(event.EventCallback): lastTime = None lastRevolutions = None
# 속도와 파워 계산함 def calcSpeedPower(self, time, revolutions): if self.lastTime is None: return None
# 롤오버 한계를 넘어가면 한차례 뒤집어줌. if time < self.lastTime: time += 64 * 1024 if revolutions < self.lastRevolutions: revolutions += 65535
# 원래는 이거임. 이러면 좀 빨라질까 해서 상수들 미리 곱해놓은거. # speed = ((revolutions - self.lastRevolutions)*5000 / ((time-self.lastTime)*1024.0))*3600 speed = (float(revolutions - self.lastRevolutions) / float(time-self.lastTime))*17578.125
# 이건 앞서 구한 속도-파워 곡선의 식 power = 0.00259981 + 0.03980412*speed + 0.46587375*math.pow(speed,2) + (-0.00238126)*math.pow(speed,3)