Press "Enter" to skip to content

Category: cycling

_wahoo-fitness-tnp._tcp.local

Wahoo smart trainers support network connectivity (instead of just the traditional Bluetooth or ANT+). Since I don’t have one I’d never bothered looking into how it works, but this morning while troubleshooting something with TrainerRoad running in the background I happened to see an mDNS query for _wahoo-fitness-tnp._tcp.local and realized this is how the smart trainers get discovered on the network.

Neat!

Maybe one day I’ll have a smart trainer that can use the network and I can dig further into how this all works.

Comments closed

Surprise New Bike Day: 2023 Salsa Warbird C GRX 600 1x

It’s been no secret that for years my favorite drop bar bike was my beloved 2019 Salsa Warbird Carbon 105 700. This bike has been with me on some of my most memorable rides, from remote parts of the UP and Canadian wilderness to silly northern LP bike path routes, from single track where it didn’t quite belong to long summertime wanders on dirt roads.

For years, and especially in 2023 after switching it to 1x, I’ve told numerous folks that there’s nothing I’d change on it and no reason to get anything new; it’s simply excellent. But then in late November while cleaning it up for winter I found a bit of a shock: a small starburst crack in the frame at the top tube/seat tube junction and a couple other hairline cracks on the seat tube. As things wear out and everything eventually fails I can’t say I was devastated, but I really was disappointed. I loved riding that bike and did not want to change anything. I even came to really like the white color.

After finding the crack I rode it a couple more times and things seemed fine. I have a long seatpost which extended well below the crack area, and I didn’t feel or hear anything when riding, but like any crack it’s best to be safe. The warranty for a carbon frame is five years, which was coming up, so I sent photos of the crack to the folks over at the venerable Tree Fort Bikes and Salsa to get things rolling. I wasn’t sure if it was problematic, and — honestly — I really didn’t want to replace the frame if it wasn’t needed, but I wanted to ask. I love how my Warbird looks with the white frame and reflective black vinyl that I added, and I wasn’t exactly keen on a matte black replacement, re-running brake lines, etc. And, it rode great!

After just a handful of questions Craig emailed me with a massive surprise: Salsa is replacing my 2019 Warbird (v4) frame with a complete 2023 Warbird C GRX 1x bike, and instead of being a simple black warranty replacement it’s a nice clay-ish grey color! This was better than I could have possibly hoped for, because not only did it replace the problematic frame, it moved me to Shimano’s GRX drivetrain! And I also wouldn’t have to cut and re-run the brake lines, etc.

Back when my Warbird came out GRX wasn’t available, so it came with the (very good) 105 R7000 road groupset. This is an amazingly good drivetrain, but for rougher roads I switched to the Ultegra RD-RX800 derailleur, which was basically a high-end road derailleur with a clutch, originally intended for cyclocross use. Then in late 2022 I used a few Wolf Tooth Components parts and made it a sorta-hacky yet very functional 1x drivetrain because I wanted to get away from the problems inherent with 2x and riding in poor conditions, notably gunking up a front derailleur.

This setup worked great, but I felt a bit limited by maximum cassette size (40t) and my left brifter had a disconnected shift lever, which would rattle around on chattery roads. Minor, I know, and while I was proud of the semi-hacky drivetrain, improvements such as a full GRX drivetrain would have been nice, but I couldn’t justify it when things worked so well. But suddenly now I had it!

Last week I picked up the bike from Tree Fort, and over some unseasonably rainy, cold, and blah afternoons I shuffled parts around and now it’s ready. My new gravel bike, a 2023 Salsa Warbird C GRX 1x with a few upgrades!

Build

Frame / Fork: 2023 Salsa Warbird Carbon / Salsa Waxwing (Light Grey)
Wheelset: Specialized Roval Terra C
Ratchets: DT Swiss HWTXXX00NSK54S (54T)
Tires: Specialized Pathfinder Pro 2Bliss Ready (700×42, Black Sidewall)
Crank: Shimano FC-RX810-1 (42T, 172.5mm)
Bottom Bracket: Shimano SM-BB72-41B
Cassette:
 Shimano CS-M8000 (11-42)
Right Shift/Brake Levers:
Shimano ST-RX600-R
Left Shift/Brake Levers:
Shimano BL-RX600-L
Brake Calipers:
Shimano BR-RX400
Brake Rotors: Shimano SM-RT64 (160mm)
Brake Pads:
Shimano K05S-RX (Resin)
Chain:
Shimano CN-HG601-11
Rear Derailleur:
Shimano RD-RX812
Bar Tape:
MSW HBT-300 Anti-Slip Gel+ (Black)
Handlebar: Salsa Cowbell Deluxe (44cm)
Headset: Cane Creek Hellbender 70 (IS41/28.6/H9 | IS52/40)
Stem: Thomson Elite X4 (SM-E139 10° X 100mm X 31.8 1-1/8 X4 Black)
Spacers: Generic Aluminum
Stem Cap: MASH Donut 2.0
Seatpost: Thomson Elite (SP-E113SB 27.2 X 410 Setback, Black)
Seatpost Clamp: Salsa Lip Lock
Saddle: Specialized Power Expert (143mm, Black)
Pedals: Shimano PD-M8100
Bottle Cages: Specialized Zee Cage II (2x Left, 2x Right)
Bottle Cage Screws: McMaster-Carr 94500A233 (316 Stainless, M5 x 0.8mm, 20mm)
Front Light: Outbound Lighting Detour
Rear Light: Garmin Varia RTL515
Rear Light Mount: Garmin Varia Seat-post Quarter Turn Mount
Bell: RockBros Bell (Black)
Computer: Garmin Edge 840
Computer Mount: SRAM Quickview Computer Mount
Sensors: Garmin Bike Speed Sensor (Front Wheel), Garmin Cadence Sensor 2 (Crank)
Anti-Rub Tape: McMaster-Carr 76445A764 (Low-Friction UHMW Tape, 0.0115″ Thick, 2″ Wide)
Mounting Hole Plugs: Heyco 2590
Top Tube Bag: Revelate Designs Mag-Tank Bolt-On
Saddle Bag: Lezyne Road Caddy
Frame Pump: Lezyne Sport Drive HP
Derailleur Hanger: 465 / QBP FS2322

Weight

Total weight for the bike, with everything but bottles (including lights, pump, saddle bag+tools, and computer), is 22.54 pounds. Removing the computer/lights/saddle bag/pump brings it down to 20.78 pounds, so I expect that without pedals, cages, or mounts (the usual way of weighing a bike) it’d be in the 19-pound range.

Build Choices:

Crank/Cassette Upgrade: After moving my previous Warbird to 1x a year ago I realized that I like having a 42t front ring. Since the bike came with a 40t ring I wanted to upgrade that, but it turned out that I could get a complete FC-RX810 crankset with a 42t ring for not much more than a stand-alone ring. Swapping from the stock FC-RX610 swap saved 84g while increasing the chainring size, makes mounting a cadence sensor easier, and opens up the possibility of getting a power meter on the bike.

At the same time I ordered an CS-M8000 cassette to replace the stock CS-M5100, which saved another 114g. While I originally was going to get an 11-40 to match my previous Warbird, my friend Ray convinced me that a 42, ending up with an even 1:1 in the lowest gear would be good, and I agreed. Between the two sizes the seven lowest cogs are the same, so typical flat/rolling stuff would feel the same with either, but when I do need a climbing/trail gear it’ll be there.

Chain Drop Protection: I was originally going to fit some chain drop protection, like the Wolf Tooth LoneWolf, but after thinking about how many times I’ve dropped a chain in the past, I opted against it. Mounting this would also require fitting a front derailleur mount which makes bottle cage mounting more fiddly and makes the bike harder to clean. I may still fit this later on, but for now I’m content continuing without.

Rotors: I am generally very fond of Shimano rotors with solid aluminum center carriers as they seem to be harder to bend and have an aluminum core (Ice Technologies) to help with heat dissipation. The bike came with some SM-RT64, and while they are a bit heavier per-rotor (~25g) than others, and just steel, it would have cost a fair bit (~$100) to replace them. I have similar rotors on my fatbike and they’ve been working well, so for now I’m going to stick with these rotors and see how it goes. They can always be upgraded later.

Frame Pump/Saddle Bag: On the previous Warbird I used a somewhat large Specialized saddle bag with a tiny 4″ pump tucked inside next to the tube. This worked well, but I began having problems with the pack Velcro no longer holding, so I also had a releasable cable tie holding it to the saddle.

I’d also never needed — that is tested — the tiny pump in the field, so out of an abundance of caution (and some paranoia) I’d often tuck a second, larger pump in my jersey pocket for long rides. This other pump had been used a few times, so with the bike swap I’ve moved to mounting the beloved (and cheap) Lezyne Sport Drive HP to the frame behind the seat tube bottle cage. I’m wary of road spray causing problems with the pump, but if it does I’ll just start carrying it in my pocket.

By no longer needing room for a pump in the bag I was able to swap to the Lezyne Road Caddy, a small and elegant seat bag that I’ve had on my road bike for a couple years.

Bike Fit: This and my road bike, a custom built Salsa Warroad, are very very similar in geometry, but I’ve had it set up with the bars slightly lower than on the Warbird. Using my favorite stem comparison tool I found that by removing 10mm of spacers below the stem I can get the bar clamp to a nearly identical position on both bikes, so as a bit of an experiment I’m giving this a go, leaving the steerer tube uncut so I can go back if desired.

I’m slightly concerned about the fit when riding more technical trails, and I may have a harder time keeping my forearms near level while on rough surface, but it’s plenty easy to go back if needed.

Bottle Cage Screws: When using Specialized Zee Cages it’s important to have a low profile screw head, else they’ll rub on the bottle and make it hard to insert. The screws which come with the cages are a nice shape, but are a chromed steel that seems to corrode with sweat, sports drink, and road treatment chloride, so I prefer something else. I prefer something like 316 stainless, and I had some 20mm of these laying around from a previous project. For just-bottle-cages this is longer than the needed ~15mm, but the additional mass is across the three standard cages is only 6x 1/4 of the mass of a single screw (1.5x a single screw), or ~5g. It wasn’t worth spending $11+shipping to save that little mass.

Anti-Rub Tape on Head Tube: On my previous Warbird, and on the Warroad, I shortened the front brake hose so it’d take a clean path from the fork to the bar, not touching the head tube. This works, but also gets it the way of the light mount, and makes adjusting spacers difficult because I have to remove the bar from the stem to slide things upward.

The stock hose length on this model rubs the front of the head tube, but I’m not sure I want to shorten it yet. For now I simply put a strip of UHMW PE tape along the front of the head tube, below the Salsa logo, so the hose won’t rub on the frame/paint/carbon. Once I settle on spacers and work a bit more on accessory mounting I may shorten the hose, or I may just leave this alone.

Comments closed

Garmin Edge 530 WiFi Connection Weirdness

Today I tried to connect my Garmin Edge 530 running the latest firmware (v9.73) to my home wireless network, and couldn’t get it working. my friend Nick dug up a solution, so I wanted to share it here.

The problem I had is that when trying to find the network to join, either in the Garmin Connect mobile app or right on the device, my WPA2-secured wireless network would be shown as Unsecured and I couldn’t join it. No matter what I tried, on device or in app, switching around network types, names, security, or bands, the Edge 530 always saw it as Unsecured. The one thing I didn’t try was making a non-secured network, but that’s not an option for me.

Turns out you can work around this by using the Garmin Express desktop app then going into the 530, Tools & Content, Utilities, then under Wi-Fi Networks manually adding the network with appropriate security, password, etc.

After saving settings and ejecting the device it joined my wireless network, as confirmed on the device, in the DHCP leases, and on the APs themselves. Now it’ll automatically sync rides whenever I get back home.

Something else odd is the Edge 530 truncates 32-character SSIDs. My network at home is Smart Meter Surveillance Network, which is 32 ASCII characters long. This is the maximum allowed by 802.11, which is 32 octets, or 32 sets of 8 bytes, or 32 ASCII characters. For some reason in much of the Garmin UI it’d drop the last character, truncating to Smart Meter Survellance Networ. Thinking this was the problem I first dug into network name as a problem but eventually found a shorter SSID didn’t help. Also, this isn’t the first device I’ve had with SSID length problems (see Bypassing Reolink SSID Length Limitation); thankfully in this case it only seemed to be a display issue.

Comments closed

1x’ing my Salsa Warbird for 2023

Every since getting one of the v4 models back in late 2018, the Salsa Warbird has been one of my absolute favorite bikes. I’ve ridden on all surfaces, and it’s been great, with only one recurring problem: front shifting.

These days bikes ridden anywhere but pavement are almost exclusively rear-shifting-only (1x) — without a front derailleur — and for good reason. Unfortunately, when I bought my Warbird there weren’t many (any?) 1x groups for drop bar use; Shimano hadn’t even announced their excellent gravel-focused GRX group. So, my bike came with the best bang-for-the-buck drivetrain at the time, Shimano 105 R7000. This remains an excellent groupset, and I put it on my new road bike, but a couple things about it were a bit lacking for off-pavement use: lack of a clutch derailleur to keep the chain taut when things got rough, and the front derailleur.

Early on I switched the rear derailleur to a clutched Ultegra RX (RD-RX800-GS), which was basically a preview of GRX, and worked wonderfully. It dropped right in place on the bike and Just Worked to solve chain slap. But, I still had one more problem… The front derailleur.

Salsa Warbird v4 Front Derailleur Cable Route

Located where the rear wheel flings debris, front derailleurs are quite prone to getting gunked up while riding, and (unfortunately) the Warbird exacerbates this by having the shift cable exit the frame at the bottom bracket, behind the seat tube, facing upward. This location collects whatever flings off the tire and is a very hard place to seal a moving cable. Coupled with our gritty, chloride-treated dirt roads, the result has been shift cables and housing corroding and binding far before any other drivetrain parts wear.

This corrosion leads to extra drag on the shift cable needed to shift, up until things bind firmly, after which the sacrificial Main Lever Support L (part number Y63X80010) in the shifter to breaks (exploded view). The overall design of this sacrificial part is great; a removable and cheap plastic bushing on the shift/brake lever blade that presses against the metal piece that handles the shifting. If the cable becomes too tight this $3 piece fails before anything else in the shifter, and replacing it takes seconds. But, the cable and housing also need to be fixed, and COVID-era parts shortages (these supports were unobtainium for about 12 months — I was using 3D printed ones for a while) and it all quickly becomes an irritation.

I’d lived with front shifting quirks for a couple years as most of the time it was fine, but losing the front derailleur was always in the back of my mind. Mountain bikes have this way for years, with a rear cassette that provides all the range needed, and this has become common on new gravel bikes.

After front shifting failed early on in De Ronde van Grampian and I ended up stuck in the big ring, I realized two things: I should get rid of the front derailleur, and I don’t need quite all the range that a 50-34/11-34 2×11 drivetrain offers. I use most of the range, but could lose a little on the top and bottom end of the range and be fine.

The first change was to remove the front derailleur, which was made easy by the front shift housing being split with a barrel adjuster below the handlebar. I was able to pull the cable and remove the housing all the way back to just under the the bar, leaving 2″ stub of housing unobtrusively peeking out of the bar tape. Next time I rewrap the bars I’ll remove this, but for now it’s fine.

Then to finish the conversion I fitted a Wolf Tooth 42t chainring specifically designed with an offset designed for 1x. None of the single-ring chainring bolts that I had around the house fit right, so I grabbed some of Wolftooth’s matching chainring bolts and it was all set. The ring fits the crank perfectly, worked great with the original chain length, and the I could shift across the whole of the cassette without any rear adjustment.

I did two rides on local rolling dirt roads and except for some longer steep climbs things were good. I was feeling good for both rides, so I didn’t mind having to grind out the longer climbs in sub-optimal cadence, but I realized I might need some more range on longer days. I’d also been concerned the left brifter would be flappy and noisy without a shift cable connected, but it’s just the same as before.

Next up was getting more gear range…

Gear Ratios for 105 R7000 50/34 11-34, 42×11-34, and 42×11-40.

The original Shimano 105 R7000 drivetrain, with 50/34 chainrings and an 11-34 cassette, gave a range from 455% to 100%, plenty for all my riding, but with a whole bunch of overlap. While I’d use the lowest ratio gears somewhat frequently, I’d almost never use the highest gear because at typical cadence I’d be moving well above 33 MPH. At those speeds I’m probably coasting down a hill and no longer pedaling.

After changing to a single 42t chainring the available ratios were 382% to 124%. At the high end this is nearly identical to everything but the rarely-used smallest cog, but at the low end it was like I lost the easiest two gears. On a couple test local couple-hour rides I didn’t absolutely need them, but it did require a bit more effort on some of the harder climbs.

With 11-speed mountain bike drivetrains on the decline, I came across Shimano XT 11-40 cassettes on sale and decided to try a bigger cassette on the rear of the bike. I was still on the original cassette and it was nearly worn out, so a change was due. This required a 1.85mm spacer to make the MTB cassette fit on a road freehub, which moved the cogs outboard, but a few limit adjustments and all was good. Now with a range of 382% to 105% it was almost identical to what I’d use on the original 2x setup.

Ultegra RX derailleur and 11-40 Cassette

The larger cassette fit pretty well, but caused some small quirks in spacing with the upper jockey wheel: the B-tension screw had to be cranked in almost all the way to have the gap set properly on biggest cog. It was quite a fiddly adjustment, as a quarter turn too far one way would have the jockey wheel rubbing on the cassette and a quarter turn the other would make shifting slow. This much B-tension also unwrapped the chain from the cassette a fair bit, making me concerned that with less chain on the cassette while pedaling the chain and cassette would wear faster than normal.

At this point I did a test ride and everything worked great when riding. Between the new chain (old was at 0.5%), cassette, and chainring the drivetrain was silent and I didn’t have a bit of trouble, but I still wanted it to be better.

A few days earlier I’d ordered a Wolftooth RoadLink DM, a nifty part that replaces a link in rear derailleurs like mine, repositioning it to handle larger cassettes. This is advertised to improve chainwrap and shifting performance, and immediately after installation the benefits were apparent. On the biggest cog chainwrap is much better, the derailleur no longer looks over-extended, the B-screw doesn’t need to be turned all the way in, and shifting feels more spot on.

Ultegra RX w/ RoadLink DM and 11-40 Cassette

While I could have fitted a Shimano GRX RD-RX812 derailleur instead of using the RoadLink DM on the Ultegra RX, this would have cost $90 more than the RoadLink DM, and I’m not sure it’d be any better.

All done, total cost for this was $265.03 after tax, and with a new cassette, chain, and chainring, I’ve now basically got a new drivetrain.

Wolf Tooth Chainring: $84.95
Wolf Tooth Chainring Bolts: $26.45
Shimano XT Cassette: $95.39
Shimano SLX/105 Chain: $26.49
Wolf Tooth RoadLink DM: $31.75

I’m quite happy with how this all turned out. A problem is solved, worn out things were upgraded, functional parts were kept, and it works great. My Warbird is ready for another year of gravel fun.

Comments closed

Soma Smoothie HP: Brake Safety Issue

Shift cable/brake interference on prototype Soma Smoothie HP Frame (Photo from Soma)

Originally this post was going to be about my new road bike, but instead I’m writing a warning about the new Soma Smoothie HP and a safety issue, recommending against buying it without fully understanding the possible downsides. While the specs of this frame promise to be an excellent modern steel road bike, it has a design problem that can lead to rear brake failure.

Specifically, the location of the brake housing mounts results in the front derailleur cable resting on the brake cable at a mount. Over time movement of this cable can cut into the brake hose/housing, cable clip/tie, etc. If not caught in time this can lead to brake failure.

I purchased one of these frames and have been excitedly building it up, finding this problem late into the build when preparing to run the shift cables and brake lines.

When I brought this up with Soma seeking for a solution, they dismissed the issue, saying they identified this interference during frame development, but that it’s not concerning to them. Stan, with Soma, instead suggested that I rely on the cable tie (as seen above) to mitigate the rub, that rubbing through a brake hose or housing will take a long time, and to add additional material (rubber cable donuts or tape) to the cable if I am worried about it.

I disagree, as any component that’s designed to move should not have unintentional rub, particularly not against a safety-critical system like a brake. A frame should be designed to avoid this; it should not be necessary to bodge in rub protection to stave off cables cutting into other housing.

The photo at the top of this post is of Soma’s prototype build and shows the interference and their reliance on the head of a cable tie for keeping the shift cable in place and away from the brake line. Beyond the safety issue of the front shift cable rubbing on the brake line, the cable does not have a clean path between the upper stop and lower guide, which can lead to shifting issues.

While it would be possible to build this frame up as a 1x (no front derailleur) system to avoid this interference, I want this to be a double-chainring road bike (Shimano 105 R7000) and thus is not an option for me. Or one could go with wireless shifting, but due to cost this isn’t an option for me either.

I really wish Soma had fixed this interference when they first identified it, or at least mentioned it in their documentation so I would have passed on buying the frame. All it would have taken is moving the brake routing to either the centerline (like on this Lynskey) or much further up the downtube (like on my Salsa Vaya) and it’d have been solved.

After I found this a good friend reached out to me, and I’ve since passed the frame on to him. He was looking to build an wireless shifting road bike with fenders, and this will work out perfectly for him. With the electronic shifting he won’t run into this cabling issue.

For those considering this frame, unless you are going with wireless shifting, a 1x setup, or are willing to deal with the compromises of a shift cable rubbing on a brake housing/hose, I suggest that you look elsewhere.

EDIT on 2024-Feb-20: This evening I received email from Stanley at Soma Fabrications about updates to the Smoothie HP frame. It sounds like this will alleviate the concern I mention, so I’m sharing it here:

I just want to update you that early 2023 we replaced the plastic BB mounted cable guide on all our HP frames with one of those guides with two mounting holes (similar to Shimano SP18) which moves the derailleur wire just enough to avoid any contact with the zip tie or brake housing. 

Though we maintain the opinion the possibility of the front derailleur wire cutting thru both the zip tie and housing in real world use is extremely remote with the old set-up, we chose to improve the routing. 

The new production that arrived this month moves the brake guides to the 6 o’clock area which will probably avoid contact no matter what plastic guide is used on the BB.

Stanley Pun, Soma Fabrications, via email on February 20, 2024

Here (PDF) is the full email thread with Soma.

Below are photos showing the interference on my frame. These were taken when the build was nearly complete, while I was planning cable routing. These photos are when I first realized the problem and reached out to Soma.

Comments closed

Help Please: 2022 AIDS/LifeCycle Fundraising

Years ago Mark Ferlatte told me about the AIDS/LifeCycle (Wikipedia) charity ride from San Francisco to Los Angeles to raise money for the San Francisco AIDS Foundation and the Los Angeles LGBT Center. Money raised by this event allows the two non-profits to provide free HIV/AIDS medical care, testing, and prevention services. Each rider in the event raises at least $3000, with the event raising over $220,000,000 since it began in 1993.

At 545 miles over seven days, riding everywhere from the Pacific Coast Highway to proper California mountains, this sounded like it a wonderfully fun way to see a new part of the country, really enjoy being outside, and most importantly raise money to directly help save lives. But, it always seemed like such a logistical challenge that fell into the back of my mind as a one-day-in-the-future goal.

Well, here we are, and 2022 is the year!

This year Kristen and I are both signed up for the 2022 AIDS/LifeCycle ride! On June 5th we will set out from Cow Palace in San Francisco to spend the next week pedaling through one of the most beautiful parts of the country with a couple thousand other folks, all of us with one goal: helping those with HIV/AIDS.

This is where we need your help. Specifically, we need money.

Kristen and I each are working to raise least $3000 through donations from people like you. We all give money to trails, trail organizations, and other groups which help make our lives more fun and enjoyable. Please join us in also giving a bit more to save lives, so everyone can have a great life.

Please click one of these links to donate: SteveKristen

(Donations are to a non-profit, and thus tax deductible.)

Thank you for your help, and for making the lives of those with HIV/AIDS better!

Comments closed

Making an Online RAMBA Trails Map

RAMBA Trails Map v1.0 (Default View w/ Epic Loop Layer)

Introduction

Kristen and I have been spending a good deal of time in the Ishpeming and Negaunee area this year, and I’ve made it a personal goal to become more familiar the local trails — both RAMBA-supported and otherwise — and get them documented OpenStreetMap (OSM). Having these trails in OSM provides two big benefits: they appear in other mapping tools (such as OsmAnd, GaiaGPS, Strava, MapMyRide/MapMyRun) and the trail data can be freely used to build other tools.

Official RAMBA Map v6 from 2018

Over the years of making trail maps with OpenStreetMap I’ve mostly produced PDFs for printing, leaving mobile and online mapping to other apps. These work well, but have the big downside of rendering routes with their style. That is, online maps via these tools’ show the routes, but look quite different from print maps, even if all the data for them to display more data (such as colour=* tags on relations) is in OSM.

While these apps work pretty well, and I use them myself routinely for navigation, I got the itch to see if I could make a web-based map that looked more like locally produced print maps than app-based renderings. It seemed like a good project, a good way to learn some basics of modern web development, and maybe make something useful.

What I ended up with was a slippy map of showing the RAMBA trails that uses layers of pre-rendered tiles to show the different official trail routes, placed over a background map. The map viewer is client-side JavaScript that loads static tiles from a basic web server, making this a very simple app to host (just a bunch of static files on a site).

In this post I intend to document the major steps of how I made this map, why I used the tools I did, and share the code to reproduce (and update) this build. Hopefully this’ll allow others to get their head around these map presentation basics, perhaps even reusing this work to make and host another map.

Update OSM Data

Strava Global Heatmap in JOSM

Mostly outside the scope of this article but worth a mention, a significant amount of time was spent ensuring that the RAMBA area trails are accurately listed in OSM. Without good data it would not be possible to go further, as the OSM data is the base data used to create other maps.

By combining information from a bunch of sources, and doing some personal surveying of trails while riding and hiking, I was able to get all of the official RAMBA trails documented, along with numerous other paths and tracks in the area. This building a complete picture of the usable trails in the area.

Information used to get the RAMBA trails in OSM included:

  • My own recorded ride/hiking data, notes, etc.
  • Strava Heatmap data.
  • Official route files (GPXs) from events such as Marji Gesick and Polar Roll.
  • The official RAMBA map.
  • Hand-annotated map from Danny Hill listing local trail names.

These sources were combined in JOSM, cross-referenced, ways drawn and tagged, relations built out, and before long a complete picture of the RAMBA-area trails — official and otherwise — were in OpenStreetMap.

Most importantly, beyond documenting the trail locations, trails were grouped into route relations to show each official route, and then all the official routes were grouped into a superroute for all the RAMBA trails. As of time of writing, relation RAMBA Trails (12425503) is the superroute that aggregates the individual trail routes such as Epic Loop (8467869) and Malton Loop (8468010).

The result of this is accurate trail data that’s easy to query for and style using other tools.

Rendering Tiles with Maperitive

There are myriad ways to render tiles from OSM data, with most of these involving setting up a database server and a toolchain which’ll generate, cache, and serve tiles on demand. For most large data sets this makes a lot of sense, but for a small trail system I really wanted to use static tiles I could serve from a simple webserver.

Eventually I came across Maperitive, a desktop application for Windows that takes GIS data (including OSM), stylizes it with a relatively simple ruleset, and can generate tiles in the standard XYZ format for use elsewhere. It can also be scripted, which meant I could use it as part of an automated workflow to generate new tiles as the OSM data changes. This seemed like a good solution, so I set about writing some rulesets that would reasonably show the RAMBA trail routes and some automation around it all.

After a lot of experimenting I settled on a having separate tile set for each of the official loops, an overview of all trails, and a base map. The base map would always be shown, and a user can toggle between layers which highlight all the trails or individual loops.

After a few iterations of custom rules, I settled on a simplified set based on the Default.mrules file which comes with Maperitive for rendering the base map. The only modification was changing the font to Michael Adams’ Roadgeek 2005 Transport Medium font, as it looks nicer than the default, Verdana. For the overview and route layers I created simple rules based on the the default rendering of highway=path, using the Heavy version of the font. The rule for each trail route (relation) selects the trails in a given relation then colors them accordingly.

Creating these rules took a bit of fiddling, as Maperitive is both a bit of a dead project, not completely documented, and (in the latest Beta) sort-of buggy where sometimes the map display would stop updating. Still, even though I’m not great at making attractive things, I was able to come up with something that worked well enough.

Conveniently, Maperitive also comes with a command line version (Maperitive.Console.exe). After settling on rendering rules and a tile generation script, I used this as part of an automated workflow which downloaded OSM data directly then rendered each of the tile sets.

After tile generation I used a Windows binary of OptiPNG to losslessly compress the tiles, resulting in a ~62% space savings (original: 746MB, optimized: 286MB) which’ll reduce storage and bandwidth overhead.

The Front End

Editing in VS Code

With tiles generated I needed a way to display them. It turns out that OpenLayers was easy to use and it all ran as simple client side application in a browser. By using npm and parcel, with Visual Studio Code for editing, it was quite easy to get the site developed, tested, and bundled up for deployment. The only component I had to add was ol-layerswitcher control, which provides an easy way to toggle between layers.

Prior to this I had very little experience with modern web development, with my exposure to JavaScript pretty much limited to reading others’ code to figure out what it’s doing. After a bit of confusion (and having to accept the hidden complexity of using an application bundler), I was able to focus solely on writing a single main.js file with a basic index.html that together do what I wanted:

  • Run full screen by default.
  • Show all trails by default, with toggles for the defined routes (layers of the map).
  • Show an attractive background map below the routes to show the rest of the area.
  • Offer controls to use geolocation to showing one’s location on the map and reset the view to the original map extents.
  • Look sane on desktop and mobile devices.

This ended up being much easier than I thought, and between the OpenLayers Examples and just some basic programming I was able to get something I’m happy with. Far more time was spent designing the tiles and thinking about what I wanted it to do than writing the code to display it all.

Tile Hosting

The actual map tiles are a number of small PNG files, and a typical session of viewing and panning around the map can result in hundreds of image loads. This was seeming a bit slow when being served from nuxx.net via HTTP/1.1, so I looked into using HTTP/2 to improve performance.

Unfortunately, it was not simple to turn on HTTP/2 here at nuxx.net as I’m using PHP for WordPress, which in turn requires MPM prefork, which precludes mod_http2. I could have set up another web server and such, but for now I’m hosting the tiles in AWS, with the tiles uploaded to an S3 bucket and served via CloudFront.

This should allow for better tile download performance than what I can do from my server. Despite potentially incurring a bit of a financial cost it is a good experiment in hosting tiles in the cloud. I may change this in the future, particularly if it becomes cost prohibitive, but for now it’s working well.

Follow Along At Home

If you would like to generate this same map, start by downloading this ZIP file: ramba_trails_map_code_1.0.zip. It contains the scripts and rules needed to generate the map tiles (ramba.mscript and the .mrules files), the index.html, main.js, and package.json for the OpenLayers-based front end, the .osm file used to generate the first release of the map, and a few batch files that tie it all together.

You will need to download Maperitive (latest beta: link — from this post / mirror), curl, OptiPNG, and the Roadgeek 2005 fonts to generate and optimize the tiles. These scripts may work fine with older/release versions of Maperitive, but betas incorporate a bit of collision detection for text, making things look nicer.

These batch files are included to will help you out, but may need some editing to fit on your environment:

  • fetch_osm.bat: Uses curl to download all OSM data within a bounding box that encompasses the Ishpeming/Negaunee area.
  • generate_tiles.bat: Runs ramba.mscript via Maperitive.Console.exe to generate the tiles.
  • optimize_tiles.bat: Copies the unoptimized tiles from the .../tile_output/raw output directory to the .../tile_output/optimized directory, then runs OptiPNG against the tiles to optimize them in place.

To build the web app you’ll need to install npm, parcel, create a new OpenLayers app as per the directions here. Then install ol-layerswitcher (npm install ol-layerswitcher), replace the default index.html, main.js, and package.json with the ones I provided, and you should be ready to go.

Updating the Map

As you can see, the map is two major pieces: the front end and the tiles. Whenever the map data changes in OSM the tiles can be regenerated to update those layers. The code for the front end web app only needs to change if the storage location changes, features are going to be added, etc.

Conclusion

This map has worked out rather well and I’m happy calling it v1.0. It’s been a great learning experience, and I’ve even managed to produce something useful that didn’t exist before: an interactive map of some of the most rugged single track trails in Michigan; one of my favorite places to ride mountain bikes.

It’s far from perfect, and there are some things I could do differently, but for now, I’m considering it a success. When in Negaunee for vacation last week I successfully used development versions of this map to find my way around, so I know it’s better than nothing.

If you find any quirks in the map data — such as trails with wrong names or in the wrong location — please take a screenshot and show me what’s wrong and email that to steve@nuxx.net. I’ve done my best to ensure the RAMBA trails are accurately mapped, but I’ve certainly missed some things.

Problems

  • No key or other ancillary information (such as logos) as are normally found on print maps.
  • No terrain. While 1m DEM elevation data is available from the USGS, I couldn’t figure out how to use it in Maperitive for generating hillshading.
  • No easy way to add clickable items to show additional info, link to external map apps (eg: for navigation).
  • Maperitive’s text rendering isn’t the best, resulting in goofy looking text at some zoom levels.
  • Long trails only have one label placed on the middle. Trails with one name broken into multiple ways will be labeled numerous times.
  • Due to being run in a browser it’s a sufficient, but not great, mobile experience. Specifically, selecting the geolocation, recenter, and layer controls can be fiddly because they are so small.
  • Does not work offline, but thankfully most of the RAMBA area now has good mobile data coverage.

Things To Investigate

  • Keep an eye on AWS cost and performance.
  • Look at Leaflet for the front end, as it seems a bit more modern.
  • Consider rendering map tiles with TileMill. This will add a lot of complexity both in setup and styling tiles, but once done should allow a lot more flexibility in styling and overcome most of Maperitive’s problems. mapbox/mbutil should work for getting XYZ PNGs out of MBTiles files.
  • Consider using a tile server if I don’t want to deal with discrete files.
  • Look more into using vector tiles with client-side styling. (I passed on this for now, as a GeoJSON file showing each of the route is a large download and had no benefit over raster tiles.)
  • Maperitive should run under Mono, and OptiPNG is available for many platforms, meaning it should be possible to reproduce this build under macOS or Linux. Note that the GUI for Maperitive will not currently run on macOS due to Windows.Forms currently being based on Carbon, which is not available for 64-bit macOS. So while the CLI should work, the GUI version isn’t currently compatible with macOS 11.5 (Big Sur) and higher.
Comments closed

New Trail Bike: Pivot Trail 429 v3

For years the Pivot Trail 429 series of bikes have been a sort-of Holy Grail bike for me. The ultimate aggressive cross country / trail mountain bike, and something I really wanted to try. In August of 2020 I was able to spend a few hours riding v2 of the bike around some of my favorite Marquette and RAMBA trails and fell in love. Something about the bike and I clicked, and I came away wanting one. After that trip I sold my beloved Specialized Camber and got ready to buy a new bike.

With the COVID-19 related bike industry shortages it took a lot longer than I’d hoped, but almost a year after that demo — in August of 2021 — I made a quick trip up to Bellaire (three hours each way) and picked my new bike from Patrick at Paddles & Pedals: a Pivot Trail 429, v3, Race XT build, with the crank and wheels upgraded to high end carbon bits.

While I hadn’t ridden this new v3 of the Trail 429, and it’s a much longer reach bike than v2, I’d stared at geometry numbers for hours, comparing it to my current bikes, and figured that a size large in this model would also be right for me. After getting the bike and swapping the usual contact points, fitting the larger rotors that I wanted, and some other little bits, it was all ready to ride.

Using the Low bottom bracket setting (the higher of the two), a 35mm stem, an upper stack height of 30mm (headset upper cover + 15mm spacer) and the 11° sweep Salsa Salt Flat Carbon bar the RAD ended up just 5mm shorter of the Timberjack and feels pretty good on its first ride.

I may experiment with the Lower setting, which’d slacken the head tube and seat tube angle by 0.5°, bring the reach in and increase the stack, but this’ll likely require a 50mm stem to get the fit where I want it. At the same time, it’d bring the bottom bracket height closer to that of the Camber’s, which might be really nice. Between suspension setup and such, I’ve got a lot of experimenting to do.

Current build details are as follows:

Frame: Pivot Trail 429 v3, Large, Silver Metallic
Fork: Fox 2021 Performance Series 34 FLOAT 29 130 (Short ID: D4SW / 2021, 34, A, FLOAT, 29in, P-S, 130, Grip, 3Pos, Matte Blk, No Logo, 15QRx110, 1.5 T, 51mm Rake, OE)
Fork TA Parts: QR15 Geared Cam and Hardware
Rear Shock: Fox 2021 Series FLOAT (Short ID: D9N4 / 2022_21, FLOAT DPS, P-S, A, 3pos, Trunnion, Evol LV, Pivot, Trail 429, 165, 45, 0.9 Spacer, LCM, LRM, CML, No Logo)
Headset: Pivot Precision Sealed Cartridge (OE)
Crankset: RaceFace Next SL (170mm)
Bottom Bracket: RaceFace BB92 Cinch 30
Chainring: RaceFace 1x Chainring, Cinch Direct Mount- SHI 12 (32t)
Chain: Shimano CN-M7100
Derailleur: Shimano XT RD-M8100-SGS
Shifter: Shimano XT SL-M8100-IR
Shift Cables / Housing: Jagwire LEX-SL
Cassette: Shimano SLX CS-M7100-12
Brakes: Shimano SLX, Rotor: BL-M7100 / Caliper, BR-M7120
Brake Pads: Shimano N04C
Front Rotor: Shimano RT-MT800 M
Rear Rotor: Shimano RT-MT800 L
Front Brake Adapter: Shimano SM-MA-F203P/P (160mm Post to 203mm Post)
Stem: ENVE Alloy Mountain Stem (31.8mm clamp, 35mm length)
Bar: Salsa Salt Flat Carbon (750mm)
Wheels: Reynolds Black Label 309/289 XC
Tires: Maxxis Rekon (29 x 2.6″, 3C/EXO/TR)
Seatpost: Fox Transfer Performance Elite (175mm, 31.6mm)
Dropper Lever:Wolf Tooth ReMote Light Action (Black, 22.2mm Clamp)
Seatpost Collar: Pivot OE
Saddle:Specialized Power Expert (143mm)
Pedals: Shimano XTR PD-M985
Grips:ESI Extra Chunky (Black)
Bottle Cages:Specialized Zee Cage II (Black Gloss, 1x Left)
Computer:Garmin Edge 530, Garmin Speed and Cadence Sensors (v1), Best Tek Garmin Stem Mount
Bell: RockBros Handlebar Stainless Steel Bell (Black)
Derailleur Hanger: SRAM Universal Derailleur Hanger
Frame Protection Tape: McMaster-Carr UHMW PE

Comments closed

Industry Nine Hydra / Light Bicycle AM930 Wheel Build

Both the Electric Queen and Timberjack were fitted with the same Industry Nine Trail S Hydra 28H wheelset; a really nice value wheelset which mates the amazing Hydra hubs with aluminum rims. Despite slightly denting (and fixing) the rear rim, these have held up great and been wonderful to ride, but I still occasionally found myself missing the stiffness (and durability) of carbon rims.

As the bike sat over winter I figured it’d be a good time to upgrade to the carbon rims, so just before Thanksgiving when Light Bicycle was offering a bit of a sale I ordered a set of rims and got the process started. Between these value rims and (literally) slow-boat-from-China [1] shipping, eBay special spokes, and spare nipples from previous builds I was able to put together a nice, solid, carbon wheelset for about $550 less than if I’d bought a complete similar set from I9. And I’ll have some rims to sell (or reuse).

The Trail S Hydra rims come with straightpull hubs that I9 doesn’t sell separately, but they were nice enough to send me the specifications for them. With some forward/backward checking against the original rims and spokes (597mm ERD, 303mm spokes) I found the DT Swiss Spoke Calculator to work great for these hubs as well.

For rims I chose the Light Bicycle Recon Pro AM930 rim, which is their high end 30mm internal 29er rim with a nude unidirectional carbon finish. As options I chose 28h drilling, black logos, and black valve stems to match the hubs and any bike. (Silver logos would also have been fine to match the hub logos, but I really prefer plain looking rims.)

When shopping around for spokes a deal popped up on eBay offering a whole box of 298mm DT Swiss Competition straightpull spokes, which perfectly match Squorx nipples left over from previous wheel builds. I love working with nipples like these, because they are tightened with a T-handle tool from the back side, which makes building way more comfortable and faster than with a traditional spoke wrench. And it means no chance to mar the anodizing on the nipples.

The wheels were built up using Ultra Tef-Gel as thread prep, to a maximum tension of ~131kgf. Before starting the build I hadn’t realized that the inner and outer spokes on each side of the rim would be a different tension. As their flange offset is a bit different for each set of spokes on each side, necessary so the straight spokes don’t interfere with each other, the bracing angle is slightly different resulting in a different tension.

I did have a slight issue where, when bringing the front wheel to tension and trying to hit the Light Bicycle recommended tension of ~145kgf, the inner Squorx heads broke off three nipples. After this I detensioned the wheel and brought it back up to a lower, but still appropriate, spec. (In the process of figuring this out I ended up cutting two spokes as the nipples couldn’t easily be turned. After the third I detensioned the wheel and decided to build to a lower tension.)

Final tension for the wheels are as follows, with the small number the indicator on a Park Tool TM-1:

Front Wheel (NDS / L / Brake Side is Steeper Bracing Angle):

NDS (L) Inner: 22 (117 kgf)
NDS (L) Outer: 21 (105 kgf)
DS (R) Inner: 20 (94 kgf)
DS (R) Outer: 19 (85 kgf)

Rear Wheel (DS / R / Cassette Side is Steeper Bracing Angle):

NDS (L) Inner: 20 (20 kgf)
NDS (L) Outer: 19 (85 kgf)
DS (R) Inner: 23 (131 kgf)
DS (R) Outer: 22 (117 kgf)

Per usual with carbon rims building is a matter of centering the rim, eliminating runout, and detensioning the spokes. There’s really no truing (in the traditional sense) because single-spoke tension doesn’t really affect a stiff carbon rim.

Out of pocket cost was $651.13 on top of of the original wheelset, for a total of $1519.27 (excluding tires and sealant and whatever I can sell the old rims for):

Original Trail S Hydra 28H Wheelset: $868.14
LB AM930 Rims (w/ Valves + Tape): $563.14
DT Swiss Competition Spokes: $87.99
Total: $1519.27

A complete Industry Nine Hydra Trail S Carbon would cost about $2015 (with Shipping + Tax), about $500 more than the end cost of building these. While this set doesn’t have the US-made Reynolds Blacklabel rims, I’ve been happy with Light Bicycle rims on previous bikes and anticipate these’ll be just as good.

The final build, without tape/valves/tires/rotors/cassette, comes in at 794g for the front wheel and 917g for the rear wheel (1711g total). This is a 51g savings over the Trail S Hydra build when going to wider and stiffer rims. This isn’t enough weight savings to notice, but at least it didn’t add anything.

When putting the wheels back together I fitted the old tires as they still have a good bit of life left. I also used the original valve stems from Industry Nine as they are a bit shorter and I prefer the brass body versus the aluminum valves that came with the rims. It also turns out that Light Bicycle provided more than 2x as much tape as needed for the rims, which is great for future spare use. (The rims came with two rolls, one roll did both with plenty to spare.)


[1] The shipping notification states: “It is scheduled to board a Matson Liner’ ship for a sea journey of about 3-4 weeks before its arrival at Los Angeles port in the US. Then UPS will pick the package up to manage the local delivery for you. It is only when the pickup is made, the information at UPS website will be updated further as well as you could reach out to UPS by calling 800-742-5877 for quicker help then.”

Comments closed

Salsa Kingpin Deluxe Fork, DT Swiss 350 Big Ride Centerlock Hubs, 31mm Torque Cap Dropouts

For years I’ve been riding my beloved, custom-built, blue and black 2017 Salsa Mukluk with a set of DT Swiss 350 Big Ride-based wheels. This fall I noticed a very small crack in a non-critical part of the frame and Salsa quickly swapped me to a new 2019 Mukluk frame. Along with the new frame came a bit of an upgrade; Salsa’s Kingpin Deluxe fork.

31mm dropout for Torque Caps on the Salsa Kingpin Deluxe fork.

In looking at photos of the fork, test fitting with end caps, and as confirmed by Salsa directly, the Kingpin Deluxe has 31mm dropouts designed to fit the SRAM-developed Torque Cap end caps. Originally intended to make suspension forks less prone to twisting, the larger 31mm OD end caps, instead of the standard 21mm OD, strengthen the wheel/axle interface. This is well documented elsewhere, and end caps are available for most higher end wheel sets (I9, DT Swiss, etc), but it only appeared on non-fatbike RockShox suspension forks… until now.

It’s not clear to me why Salsa chose to put 31mm dropouts on the already-stiff, rigid, carbon Kingpin Deluxe fork, but they did. My guess is they saw potential for dynamo hubs — which generate power via forces between the still axle and moving hub shell — to use Torque Caps so they have a larger interface with the hub. After all, one of the new features of the Kingpin Deluxe fork is internal routing for dynamo hubs.

Parts from two DT Swiss HWGXXX0009100S kits for converting the 350 Big Ride hubs to Torque Caps.

The only downside to including 31mm dropouts is that without Torque Cap end caps on the hub the wheel won’t self-center on the axle making wheel installation a little bit fiddly. In practice this isn’t a problem, and Newmen made stick-on Torque Cap Fork Reducers to mitigate it, but I wanted to see if I could get some actual Torque Caps for my DT Swiss 350 Big Ride Center Lock hubs (H350DCIXR32SA6259S) to do it right.

After a bit of email with Logan, one of the ever-helpful folks at DT Swiss, I learned that unlike all their other hubs, these have equal-length end caps and until now there weren’t any fat bike forks with 31mm dropouts, so DT doesn’t have a Torque Cap kit for these hubs. Logan suggested that I pick up two of the HWGXXX0009100S kits for regular 350 hubs, then use the longer pieces on each side of the hub, figuring this should fit. While this was a bit pricey (~$65), it felt like the right choice so the wheel would match the fork.

Torque Cap end caps fitted to a DT Swiss 350 Big Ride front hub.

The kits arrived and just as Logan had calculated these caps dropped right in and now the end caps and fork match. Hopefully in the future DT Swiss will offer a kit that has just the necessary parts so others won’t have to buy two as well.

Comments closed