I've had an idea floating around in my head recently -- mostly inspired from my buddies that are into cycling, and my endeavouring to learn some Python. Now that I think about it -- I've learned quite a lot of python over the last year or so... Picking a project and running with it is a pretty great way to learn (bad habits).
Python implementation of the ANT, ANT+, and ANT-FS protocols. For more information about ANT, see http://www.thisisant.com/.
Add the afforementioned python library to your projects requirements.txt file: ```
pip install -r requirements.txt```
Start up a new python file called
, and copy/paste the following:
from ant.core import driver, node, event, message from ant.core.constants import *
NETKEY = b'\xB9\xA5\x21\xFB\xBD\x72\xC3\x45'
class ANTListener(event.EventCallback): last speed time = 0 last speed revs = 0 now speed revs = 0
last_cadence_time = 0 last_cadence_revs = 0 now_cadence_revs = 0
wheel_diameter = 0.673 ## Wheel diameter in m def process(self, msg, _channel): if isinstance(msg, message.ChannelBroadcastDataMessage): self.last_cadence_revs = self.now_cadence_revs self.last_speed_revs = self.now_speed_revs ## Process Cadence Cumulative Revolutions ## ctimeLSB = msg.payload,ctimeMSB = msg.payload,cadenceLSB = msg.payload, cadenceMSB = msg.payload ctime = int(format(msg.payload,'#010b')+re.sub('0b','',format(msg.payload,'#010b')),2) self.now_cadence_revs = int(format(msg.payload,'#010b')+re.sub('0b','',format(msg.payload,'#010b')),2) ## Precess Speed Cumulative Revolutions ## stimeLSB = msg.payload,stimeMSB = msg.payload,speedLSB = msg.payload,speedMSB = msg.payload stime = int(format(msg.payload,'#010b')+re.sub('0b','',format(msg.payload,'#010b')),2) self.now_speed_revs = int(format(msg.payload,'#010b')+re.sub('0b','',format(msg.payload,'#010b')),2) speed_rev_delta = self.now_speed_revs - self.last_speed_revs speed_time_delta = stime - self.last_speed_time cadence_rev_delta = self.now_cadence_revs - self.last_cadence_revs cadence_time_delta = ctime - self.last_speed_time speed = (speed_rev_delta/speed_time_delta)*1024*(self.wheel_diameter*math.pi*60*60/1000) ## rev/sec x 0.673*math.pi m/rev x 1km/1000m x 60s/min x 60min/hr cadence = (cadence_rev_delta/cadence_time_delta)*1024*60 print("Cadence Timestamps: ",ctime/1024,"|| Cadence Revolutions: ",self.now_cadence_revs) print("Cadence Rev Delta: ", cadence_rev_delta," Cadence Time Delta", cadence_time_delta," cadence: ",cadence," RPM") print("Speed Timestamps: ",stime/1024,"|| Speed Revolutions: ",self.now_speed_revs) print("Speed Rev Delta: ", speed_rev_delta," Speed Time Delta", speed_time_delta," Speed: ",speed," km/hr") print("=============") self.last_speed_time = stime self.last_cadence_time = ctime antDevice = '/dev/ttyUSB0' antVendor=0x0fcf # antProduct=0x1009 antProduct=0x1008 stick = driver.USB2Driver(idVendor=antVendor, idProduct=antProduct) antnode = node.Node(stick) antnode.start() channel = antnode.getFreeChannel() def setup(self): # Start shit up #stick = driver.USB2Driver() if not self.antnode.running: self.antnode.start() # Setup channel net = node.Network(name='N:ANT+', key=NETKEY) self.antnode.setNetworkKey(0, net) self.channel.name = 'C:HRM' self.channel.assign(net, CHANNEL_TYPE_TWOWAY_RECEIVE) self.channel.setID(121, 0, 0) self.channel.searchTimeout = TIMEOUT_NEVER self.channel.period = 8070 self.channel.frequency = 57 self.channel.open() def start_listen(self): if not self.antnode.running: self.setup() # Setup callback # Note: We could also register an event listener for non-channel events by # calling registerEventListener() on antnode rather than channel. self.channel.registerCallback(ANTListener()) def stop_listen(self): # Shutdown self.channel.close() self.channel.unassign() self.antnode.stop()
The above script generally does the following:
preps the ANT stick for the appropriate idVendor and idProduct, and finds a free channel to work on;
* Currently, we set up a channel only for our speed/cadence sensors;
* You can find your device type (if you're a linux user) via
starts the device listening for broadcast events from any sensors matching our specified type;
stops the device and closes the channel and antnode -- freeing the USB device to use again;
* For whatever reason, I end up having to unplug / re-plug the device to get it connected again.. whatever...
* Listens for broadcast events on the channel
wheel_diametervalue -- mine is 673mm;
So assuming that you've punched in the appropriate
listed in your
, and updated for any difference in wheel size -- you SHOULD be up and rolling:
Open up your terminal:
listener = cadence.ANTListener()
you SHOULD start seeing outputs like the following: ``` Cadence Timestamps: 6.95703125 || Cadence Revolutions: 285 Cadence Rev Delta: 4 Cadence Time Delta 2742 cadence: 89.62800875273523 RPM Speed Timestamps: 7.2412109375 || Speed Revolutions: 1581
Cadence Timestamps: 9.6435546875 || Cadence Revolutions: 289 Cadence Rev Delta: 4 Cadence Time Delta 2460 cadence: 99.90243902439025 RPM Speed Timestamps: 10.1884765625 || Speed Revolutions: 1589
Cadence Timestamps: 13.0166015625 || Cadence Revolutions: 294 Cadence Rev Delta: 5 Cadence Time Delta 2896 cadence: 106.07734806629834 RPM Speed Timestamps: 13.140625 || Speed Revolutions: 1597
Cadence Timestamps: 15.744140625 || Cadence Revolutions: 298 Cadence Rev Delta: 4 Cadence Time Delta 2666 cadence: 92.18304576144037 RPM Speed Timestamps: 16.130859375 || Speed Revolutions: 1605
Cadence Timestamps: 18.486328125 || Cadence Revolutions: 302 Cadence Rev Delta: 4 Cadence Time Delta 2412 cadence: 101.8905472636816 RPM Speed Timestamps: 18.7626953125 || Speed Revolutions: 1612 Speed Rev Delta: 7 Speed Time Delta 2695 Speed: 20.24448181159524 km/hr ```
So that's it that's all! That's how you can whip up a quick and dirty ANT+ speed/cadence reader...
Next steps are up to you -- I've got some cool ideas for what I want to accomplish... Images below paint a bit of a story for what I'm thinking...
What projects / ideas are you working on? Do you like to have some kind of creative fire burning? I feel like most people here are pretty creative -- that's kind of the "early adopter" crowd that Steem has attracted.
Do you think you'd play a cycling game where you can meetup digitally and race other Steemians / Exhaust-o-nauts? I probably would, so long as I didn't have to go up against @run.vince.run or @jgrieco. This would probably be a fun way to have another "Solstice Race" event...