伊豆の坂に囚われて

伊豆半島をめぐるサイクリングを中心としたブログです。

  • サイコンのエラーはあれど走ったんですよ。大観山から明神・三国峠。

    この人たちは、今日どこまで走るんだろう。そんなことを思いました。

    時刻は朝8時過ぎ。

    前を行くローディーのサドルバッグにつけられたAudax Japanのロゴ入りリフレクターを見送りながら、真鶴に向かう海岸線を走っていました。

    みんなサドルバッグやトップチューブバッグに反射ベストという出立ちなので一目でブルベイベントだとわかります。フロントライトやリアライトを複数装備している事から、夜間走行も含めかなりの距離を走るんだろうなぁ、と。

    僕の今日のルートは自走で定番となってきている、明神・三国峠ループ。これまでにもルートを何パターンか変えたりして、ぐるっと周ってきました。

    富士山が日の光に輝いて。足柄峠から明神・三国峠。

    春の夏日は富士山が吉。足柄峠から明神・三国峠に道坂峠をトッピング。

    いつもは松田側から足柄峠経由で小山の上り口に向かうルートなのですが、今回は大分アレンジして、湯河原から大観山経由の上御殿場から上り口にアプローチする事にしました。

    最近上っていなかった大観山に行きたかったというのもあり、それだけで帰るのもなんなので。と思ったかどうかは今となっては定かではありません。

    いずれにせよ総距離は250km、獲得標高3500mとなかなかのボリュームだと思っている自分の前を通り過ぎて135号線を熱海方面に向かうブルベの人たち。500kmとかかなぁ、すごいなぁ、と彼らを見送りながら僕は135号線から離れて、湯河原駅の前を通って大観山に向かいました。後で調べたところ、どうやら神奈川起点に中伊豆を経て諏訪まで行って帰るという600kmのイベントのようでした。凄すぎる…

    湯河原駅は朝という事もあり人もまばら。温泉街ではありますが、熱海に比べると格段に落ち着いていて、いい街だなあと思います。美味しいものも色々。ちなみに、湯河原のご当地グルメのタンタン焼きそばは賛否ある様ですが、僕は好きです。

    湯河原名物 担々やきそば ちょっとピリ辛 クセになる!

    二店舗訪れた事がありますが、お店によって結構違う模様。なんなら、この日も大観山から折り返して行ってないお店で食べて帰っても良いな、とふと思ったり。

    あるいは真鶴との間ぐらいの港近くにあるブルワリーも。

    HUMANSBEER | Craft beer brewery | 人類麦酒醸造所

    ここの屋上テラスで呑むクラフトビールは最高です。

    とはいえ自転車ではダメですな。ふと、自転車代行サービスとかあったらいいのに、と思ったり。呑んだ自転車乗りは徒歩。2名体制の代行員が一人は呑兵衛の自転車を担当。もう一人はタンデムの自転車で後をついて行く。帰りは代行員二人でタンデムに跨る。絵面が面白そう。

    タンデムって、公道走れるんだっけ…

    閑話休題。

    大観山。湯河原の温泉街をなだらかに上って行くと万葉公園という渓谷沿いの散策路がある公園があり、その入り口前がストラバ上で使われているスタートです。そこから16km程のロングクライミング。

    ボリュームとしては先週訪れた丹波山村からの柳沢峠と同じぐらいですね。激坂はなく、比較的淡々と上る中に、平坦に近い区間が続いたり9%ぐらいまでの勾配が程よく体力を試しにかかる。

    僕はあんまりロングクライミングが得意ではありません。まあ上れる人であれば、より短時間でサクッと上れるのでしょうから、これをロングクライミングとするかは人それぞれ。

    いずれにせよ、僕にとってはロングクライミングの部類の大観山。実は案外好きな上りなのです。後半6km程は高度も上り、相模湾や東伊豆に大島まで見渡せる絶大なる開放感に浸りながらハアハアできます。

    クライマックス感が満載なんですね。仁科峠と似た感じになれる。

    路面も一部舗装が良くなり、ダウンヒルもより快適になってきた大観山。万葉公園を出発したのが8時40分だったので10時に着く感じなら良いかな、と思って踏みすぎずかと言ってゆるポタでもない感触で続けていたら9時57分にピークのアネスト岩田の入り口に到着しました。最近作っているロングライド予測システム要らず。あれは未踏のルートでは役立つと思うので引き続きテストしたいところなのですが…

    今回はテストのための走行ログが取れませんでした。

    朝4時過ぎにスタートして5km行かないうちにサイコンのマップ上の現在地が全く動かなくなってしまったのです。GPS信号は受信しているっぽく、走行距離自体は加算されていくので、マップの表示が更新されないだけなのか?と思い、そのまま走っていましたが、結論から言うと走行ログは取れずじまい。

    Screenshot

    一応距離とサイコンアプリ上で獲得標高は記録されていますが、走行ルートは反映されず仕舞い。

    Screenshot

    走った後に走行ログを見るのは楽しみの一つなのですが、今回はそれが得られないとは梅雨知らず。あ、関東は梅雨入りでしたね。

    さて。大観山と言えばそこから富士山を望むのが楽しみなのですが、これが結構打率が低い。基本あんまり綺麗に見えたことがありません。

    富士山が見える。ハズ…大観山

    さて、今回は。

    御多分に洩れず、山頂の一部がちょろっと雲の隙間に見える程度。という事で芦ノ湖側にそそくさとダウンヒルして仙石原から長尾峠に向かいます。そこから御殿場に抜け、明神・三国峠に向かう訳です。とはいうものの、何となく明神・三国峠に向かうかちょっと迷っていました。

    なんだかんだ言っても激坂なので、ゆるポタモードでは上れません。半強制的に全力で上る羽目になります。

    大観山を上った時点で結構満足したのもありますし、尚かつまだ行程の半分にも届いていない事に怖気づいたのもあります。

    ブルベ、むいてねー、と思いながらも長尾峠に到着。

    このトンネルを抜けてダウンヒルすると御殿場。ここで引き返して小田原に戻るか、進むか。実際のところ、自宅への近道は明神・三国峠から道志みち。

    さらば箱根!

    トンネルを抜けたら正面に富士山があるはずですが、あいにくの曇り空で全く見えずじまいのまま御殿場方面へ下りました。

    御殿場側に下りるのは確か2回目です。随分前に、足柄峠を小山から上るために御殿場を経由して以来。

    不慣れな街でサイコンにルートを落とせないので、ちょくちょくスマホを確認しながら明神・三国峠の入り口をめざします。

    いつも小山側から向かうのと反対からアプローチするんだよなー、と思いながら進んでいたら、富士スピードウェイのゲート前に出ました。

    峠を上っている時に、下の方でウォンウォンいってるなー、とは思ってましたが、コレか。オリンピックのロードレースのゴールでもあるんですよね。ちょっとした聖地巡り。

    では、本日の聖地に向かいましょう。

    いつもとは逆側から。左折したらば1時間程かけてヘロヘロに。

    はい。到着。

    あ、途中の記憶がないわけではないですよ。18%区間は立ち漕ぎしましたし、途中で御殿場とか見下ろして一瞬最高の気分に浸ってみたりしました。激坂抜けてからの区間からの丹沢山系の眺めも良かったし。

    そういえば途中にある明神峠18%を讃えるオリンピック記念碑の辺りに真新しいフェンスが貼られていました。どうやら不法投棄防止の為のようです。残念ですね。

    峠着は14時。下って山中湖を14時半に出れば17時に津久井湖付近。という事は19時頃帰宅かな、と計算してダウンヒル。

    富士山は見えません。

    当然山中湖からも。

    さあ、道志みちを下りましょう。と、その前にちょっぴり上って山伏峠。

    今日の峠終了。後は細かいアップダウンを残すのみ。

    午後からはやや南風が出る予報でしたが、幸い追い風基調で下れたので久しぶりに気持ち良いロングダウンヒル。途中で少しだけ通り雨に遭い路面が濡れている瞬間もありましたが順調に進み、橋本の街に入った辺りで17時になりました。

    尾根幹で多摩川に抜けるいつものルート。最後の小さい上りを全力で越えて、すっからかんになりながら、ZEBRA Coffeeの前を通過。カフェラテ飲みたいなーと思いながらも立ち寄らず。

    家まで1時間ぐらいなので、手持ちのジェルでいいやと思ったのですが、どうしても我慢できずセブンイレブンでアイスカフェラテとサンドイッチをつまんでしまいました。

    満足して多摩川に出て18時半に帰宅。

    結局走行ルートは記録されずガッカリではありますが、こんなルートだったんですな。

    Screenshot

    翌日軽く走った際にサイコンを立ち上げたら問題なくGPS信号を受信したので、故障ではなさそうです。今後はおかしくなったら再起動ですな。スマホで予備計測するのはバッテリーが持たないかもなので。

  • 予測時間を出したいだけなのに、スクリプトが次々と増殖していく

    〜AIに手伝ってもらったロングライド予測ツール開発記 2〜

    前回は、「日没前に帰るには何時に出発すればいいのか」を知るために、自分用のロングライド予測ツールを作ろうと思った経緯を書きました。

    STRAVAで距離や獲得標高はわかりますが、自分がそのルートを走った時に、休憩や信号待ち、後半の疲労まで含めて何時間かかるのかはよくわかりません。そこで、自分の過去走行データを使って、もう少し自分に即した予測ができないだろうか、と考えたわけです。

    今回は、ChatGPTに相談しながら実際に試作を始めていきます。

    過去の走行データを分析し、STRAVAで作ったGPXルートから予測時間を出し、補給プランやステムシートのようなものを作る。そうやって試行錯誤しながら進めていったら、次から次へと分析スクリプトやデータが増殖し、だんだん収拾がつかなくなったというお話しです。

    まずは予測移動時間を出したい

    最初にやりたかったのは、STRAVAで作ったルートを読み込ませて、自分が走った場合にどのくらい時間がかかりそうかを出すことでした。

    STRAVAから書き出したGPXファイルには、ルート上の位置や標高などの情報が入っています。詳しい人には当たり前なのだと思いますが、こちらとしては、GPXというファイルに何が入っているのかもよく知りません。

    そこで、ChatGPTに「STRAVAのGPXから距離や勾配を読み取り、自分の過去データをもとに予測時間を出したい」と相談しました。

    すると、GPXを読み取るためのPythonスクリプトが出てきます。

    言われた通りにファイルを置いて実行してみると、CSVファイルが作られました。中には、距離や勾配、予測速度、到達時刻のような数字が並んでいます。

    おお、なんか出た。

    この時点では、それが正しい予測なのかどうかもよくわかっていません。ただ、自分ではプログラムを書けないのに、相談して言われた通りに進めたら、それらしい数字が出てきたことには少し感動しました。

    勾配ごとの速度から予測する

    予測の基本になったのは、自分の過去ログから見た勾配ごとの速度です。

    平坦ではどのくらいの速度で走っているのか。緩い登りではどのくらい落ちるのか。5%を超える登りならどうか。下りではどのくらい速度が出ているのか。

    過去の走行ログを分析すれば、自分がそれぞれの勾配でどのくらいの速度になりやすいかは、ある程度見えてきます。

    新しく走るルートを細かい区間に分け、それぞれの勾配に応じた自分の予測速度を当てはめる。それを積み上げていけば、ルート全体の移動時間を計算できる、という考え方です。

    もちろん、実際の速度は路面や交通量、信号、風などにも左右されます。それでも、一般的な平均値ではなく、自分の過去データを基準にすることで、少なくとも自分なりの予測には近づきそうです。

    そこで、過去データから勾配と速度の関係を分析するスクリプトを作り、それを使ってGPXルートの予測を出してみることになりました。

    過去の走行ログを区間ごとに分け、平均勾配と区間速度の関係をプロットしたもの。

    とりあえず数字は出た

    試しに伊豆イチのルートを読み込ませた時には、こんな結果が出ました。

    Route: 260508_伊豆イチ.gpx
    Route points: 47447
    Distance: 274.1 km
    Predicted moving time: 13.27 h
    Predicted avg speed: 20.7 km/h
    GPXルートを読み込ませ、最初に得られた予測結果。

    距離274.1kmに対して、予測移動時間は13.27時間。予測平均速度は20.7km/h。

    数字としてはそれっぽい。

    距離と獲得標高を眺めて頭の中で考えるよりも、だいぶ具体的です。少なくとも「このルートを走ったら、とんでもなく遅くなるのか、それなりに走れそうなのか」という大まかな感触は掴めそうでした。

    ただし、ここで出ているのは移動時間です。

    信号待ちやコンビニ休憩、食事休憩、写真を撮るために止まった時間などは入っていません。

    僕が本当に知りたいのは、出発してから帰着するまでのグロス時間です。自宅発着の場合もあれば、輪行先の駅などを拠点にする場合もありますが、移動時間が13時間だからといって、出発から13時間後に戻ってこられるわけではありません。

    では、休憩込みでは何時間になるのか。

    ここから少し話がややこしくなります。

    休憩時間は予測なのか、提案なのか

    ロングライドの休憩時間は、その日の状況によってかなり変わります。

    コンビニでドリンクを買うだけなら数分で済みますが、食事をすれば長くなります。暑ければ日陰で休みたくなりますし、景色が良ければ写真も撮りたい。特に理由はなくても、カフェを見つけて吸い込まれる場合もあります。

    そう考えると、休憩時間を正確に当てるのはかなり難しい。

    そこで、休憩は予測するというより、最初に休憩パターンを決めてグロス時間を計算する方が現実的なのではないか、という話になりました。

    たとえば、1時間ごとに10分休憩する。2時間ごとに短い休憩を入れ、4時間ごとに少し長めの休憩を取る。あるいは、コンビニのある場所や長い登坂の前を休憩地点として提案する。

    実際のライドで予定通りに休む必要はありませんが、こうした休憩プランを置いておけば、移動時間からグロス時間を見積もることはできます。

    予測時間が出たことで一歩前進したと思ったら、今度は「休憩をどう扱うか」という問題が出てきました。

    せっかくなら補給プランも欲しい

    休憩のことを考え始めると、当然ながら補給のことも気になってきます。

    10時間以上走るなら、どこで何を食べるかはかなり重要です。補給が遅れて後半に大きく崩れたら、日没前に帰るための予測も意味がなくなってしまいます。

    最初は、1時間ごとの予想到達地点がわかれば十分だと思っていました。しかし、時間ごとの地点が出るなら、そこに補給の目安も載せられるのではないか、と考えてしまいます。

    1時間あたり何kcalくらい摂ればいいのか。長い登坂に入る前に何か食べておくべきか。コンビニがしばらくない区間へ入る前に、水や補給食をどれくらい買っておけばいいのか。

    そこまで出せれば、単なる所要時間の予測表ではなく、ライド中に使える計画表になりそうです。

    そこで、補給プランも作り始めました。

    予想到達地点へ補給とコンビニ情報を重ねた補給プラン。

    予測CSVに加えて、補給プラン、心拍分析、勾配と心拍の分析、ステムシート用のPDF、グラフや表など、出力されるものが徐々に増えていきます。

    何かを思いついて「これも出せない?」と聞けば、ChatGPTはだいたい何かしら作ってくれます。

    便利なのを良いことに調子に乗っていたら、だんだん困った状況になり始めました。

    分析スクリプトが増殖する

    AIに相談しながら作っていると、「こうしたい」という希望に応じて、次々に新しいスクリプトが出てきます。

    GPXを読むもの、勾配別速度モデルを作るもの、補給プランを作るもの、PDFにするもの、グラフを出すもの。

    最初は、それぞれに役割があるので便利に見えます。

    ところが、修正を重ねていくうちに、だんだん自分でもわからなくなってきました。

    今使っているスクリプトはどれなのか。これは古いものなのか、修正版なのか。このCSVは何から出力されたものなのか。このPDFを作った時には、どんな設定を使っていたのか。

    ChatGPTから新しいスクリプトを受け取るたびに保存していましたが、どれが現在の正解なのかを管理する仕組みはありません。

    途中で修正を頼んだ結果、以前に作ったものへ逆戻りしているように見えることすらありました。

    実際、チャットの中でも僕は、「なんか、だいぶ前に作ってもらったものに逆戻りしてるかもな」と言っています。

    完全に迷子です。

    希望を追加するたびに、分析スクリプトと出力ファイルが増えていった。

    これはAIが悪いというより、自分の側に開発やプロジェクト管理の知識がなく、出てきたものをとりあえず保存して進めていたことが大きいと思います。

    普通に開発している人なら、ファイルの役割を整理し、変更履歴を管理し、どれが最新版なのかわかるようにするのでしょう。しかし、こちらは言われたコードを貼り付けて実行するだけで精一杯です。

    便利なものは増えているのに、全体像はどんどん見えなくなっていきました。

    ステムシートに収まらない

    一方、出力側にも問題がありました。

    ステムシートへ載せたい情報を増やしていくと、当然ながら紙面が足りなくなります。

    ステムに貼れるサイズは限られています。そこへ1時間ごとの到達距離、到着予定時刻、補給、コンビニの有無、ルートの種類などを入れようとした結果、最初に出てきた表では文字が重なっていました。

    Fuelが列からはみ出している。文字同士が重なって読めない。画面上で大きく表示すれば見えるものでも、ステムに貼るサイズまで縮めると使い物になりません。

    狭いステムシートへ情報を詰め込み、文字が重なった改良前の状態。

    そこで、表示する言葉を短くしていきました。

    MountainはM、コンビニはCVS、水はWTR、ジェルはGEL、おにぎりはONI。

    こうして、前回の記事に出てきた謎の記号だらけのステムシートが生まれました。

    M350、ONI+GEL/WTR、CVS NO。

    長い言葉を略号へ置き換え、実際のステムシートへ収めた。

    知らない人が見たら何の暗号かと思いますが、自分が見る分には問題ありません。むしろ走行中に確認するなら、長い説明より短い記号の方が読みやすい。

    ただ、この作業を通して、情報を増やせば便利になるとは限らないことにも気づきました。

    限られた場所へ載せるなら、何を追加するかと同じくらい、何を載せないかも大事です。

    「ビジュアライゼーションを表示できません」

    試作中には、よくわからない表示にも何度も遭遇しました。

    「ビジュアライゼーションを表示できません」

    ChatGPTがグラフや表を作ったようなのに、こちらでは表示できない。何かが出るはずなのに何も起こらず、処理だけが終了しているように見えることもありました。

    さらに、画面に謎の「403r」のような文字が出て、これは何なんだ、という話にもなります。

    試作中に繰り返し遭遇した、ビジュアライゼーションを表示できない状態。

    プログラミングに慣れていれば、ログを読んだり、原因を切り分けたりするのでしょう。しかし、こちらから言えることは「何も起こらないんだけど」くらいです。

    画面の状態や表示された文字をChatGPTへ伝え、必要なら出力されたテキストを貼り付け、修正案をもらってもう一度試す。

    少し動いて、少し壊れて、また聞いて、また直す。その繰り返しでした。

    AIに頼めば魔法のように一発で完成する、という感じではありません。かなり泥臭いですが、素人がAIに手伝ってもらいながら何かを作る実際のところは、たぶんこういうものなのだと思います。

    それでも形にはなっていく

    ファイルは増えました。出力も増えました。何が最新版なのかわからなくなることもありました。

    それでも、少しずつ最初に欲しかったものへ近づいていきます。

    GPXを読み込めば、距離と勾配から予測移動時間が出る。過去データをもとに、自分の勾配別速度を当てはめられる。休憩込みのグロス時間や補給の目安、1時間ごとの到達地点も出せるようになり、ステムシートとして印刷できる形も見えてきました。

    自分ではコードを書けず、仕組みをすべて理解しているわけでもありません。それでも、「こうしたい」と伝え、結果を見て修正を頼むことを繰り返すと、少しずつ形になっていきます。

    これはかなり面白い体験でした。

    一方で、このまま整理せずに機能を増やし続ければ、どこかで完全に破綻することもわかってきました。

    ここで一回整理しよう

    チャットの中でも、僕はこう言っています。

    「ちょっと色々スクリプトやらデータが湧いてきすぎちゃって、色々ごっちゃ混ぜになってきた。ここで一回整理しようよ」

    まさに、その通りでした。

    必要なものを残して、それ以外は削除する。どのスクリプトが何をするのか整理する。入力ファイルと出力ファイルを分け、最終的に使う流れを一本にする。

    入力・処理・出力を分け、実行の流れを一本にしようとした。

    ここまで来ると、ChatGPTとの会話の中だけで試作を続けるのは、少し厳しくなってきます。

    会話の中でコードを受け取り、手元で実行し、結果を貼って、また直してもらう。その方法でも進められますが、ファイルが増え、複数の機能が関係し始めると、だんだん管理しづらくなります。

    特に、毎回スクリプトを個別に実行するのではなく、ルートを選べば必要な出力がまとめて作られる簡単なアプリにしたいと思い始めると、チャットだけで進めることには限界を感じました。

    そこで次に出てくるのが、GitHubです。

    ただし、僕はGitHubも初めてでした。アカウントを作り、GitHub Desktopも入れてみたものの、当然のようによくわからない画面が出ます。

    どうすれば良い?

    プロジェクト整理のためにGitHub Desktopを開いたものの、まず使い方から始まった。

    次回は、ChatGPTで作った試作品をいったん整理し、簡単なアプリの形にまとめながら、Codexを使った開発へ移っていく話です。

    ここからようやく、「予測表を作る」から「実際に使えるツールにする」方向へ話が変わっていきます。

  • 200km走って日没前に帰るには、何時に出ればいいんだろう?

    ~AIに手伝ってもらったロングライド予測ツール開発記 1~

    前回、AIに手伝ってもらいながらロングライドの予測ツールを作り、それを使って西伊豆までテストライドしてきた話を書きました。

    STRAVAで作ったルートをツールに読み込ませると、グロスの走行時間や1時間ごとの予想到達地点を出してくれる。さらに、補給の目安やコンビニの有無をステムシートにまとめ、スマホで見られるマップまで作る。

    実際に使ってみると、220km、獲得標高4000mほどのルートで、予測グロス時間が13時間17分、実際の経過時間が13時間23分。誤差6分という、実戦投入初回にして上出来な結果になったのは前回お話しした通り。

    ただ、前回はライドの話が中心だったので、肝心の「どうやってそんなものを作ったのか」については、かなり端折りました。

    今回はその開発編です。

    あらかじめ最初にお断りしておきますが、予測ツールの中でAIが走行判断をしているわけではありません。AIに相談しながら、設計やコード作成、修正を手伝ってもらい、自分用の予測ツールを作っていった、という話です。僕はプログラミングができるわけでもなく、AIを今回のような目的で使うのも初めてです。

    そもそも、なぜそんなものを作ろうと思ったのか。

    ロングライドの予定を立てる時に、「このルート、実際どれくらい時間がかかるんだろう」と考えることはよくあります。

    STRAVAでルートを作ると、距離や獲得標高はわかります。ざっくりした予測時間のようなものも出ます。ただ、それはあくまで目安のようなものだと思っていました。自分がそのルートを走った時に、休憩や信号待ち、補給、後半の疲労まで含めて何時間かかるのかまでは、なかなかわかりません。

    特に10時間を超えるようなロングライドになると、単純な距離と獲得標高だけでは読めないことが増えてきます。

    同じ200kmでも、獲得標高が2000mなのか4000mなのかで全然違います。前半に大きな峠があるのか、後半に登りが固まっているのか、あるいは、アップダウンが連続するのか。市街地で信号によく捕まるのか、40km信号がない道なのか。そういう要素が重なって、走行時間はかなり変わります。

    そういうことを前提に、もう少し自分用に予測できたら便利だな、と思っていました。

    そもそも日没前に帰りたい

    この予測ツールを作ろうと思った発想の根っこにあるのは、「何時に帰ってこられるか」というより、「日没前に帰るには何時に出発すればいいのか」でした。同じじゃないの?と思う向きもあるでしょうが、僕にとってはここはかなり重要なところです。

    自宅近くは市街地なので、深夜や早朝でない限り交通量はそれなりにあります。ロングライドの終盤、疲労が溜まった状態で日暮れの時間帯に市街地を走るのは、できれば避けたい。

    郊外や山間部を走る場合でも、街灯のない道を暗くなってから走るのは避けたいところです。特に知らない道や、路面状況が読みにくい道ではなおさら。

    つまり、20時でも23時でも構わないから帰着時刻が予測できる、という目的というより、日没までに安全に戻ってくるために、どのくらい余裕を見て出発するべきかを知りたい、という目的ですね。

    もちろん、せっかくルート全体の予測を作るなら、それだけに留まらず、ライド中に役立つ情報も一緒に盛り込みたい。

    何時間後にどのあたりにいるのか、補給はどこでできそうか、コンビニのない区間はどこか。さらには、どのあたりで大きめの休憩を入れるべきか、このペースで走ると後半に崩れそうなのか。そういった情報をまとめて、走行前にも走行中にも確認できる形にしたい、という欲がだんだん出てきたわけです。

    STRAVAだけでは少し足りない

    STRAVAのルート作成は便利です。

    距離もわかる。獲得標高もわかる。コースの全体像も見える。知らない道を繋いでロングライドの計画を立てるには、かなり頼りになります。

    ただ、もう少し細かく刻んだ情報や、自分の走力に即した予測などはなかなか難しい。

    例えば、休憩や信号待ちを含めたグロスの所要時間。1時間ごとの予想到達地点。補給すべきカロリーや、水を補充するタイミング。コンビニがしばらくない区間。走行予定日の天気や降雨リスク。長い登坂に入る前に、どのくらい補給をしておけば良いのか。

    そういうものは、一般的な平均値だけではなかなか見えてきません。

    同じ200kmでも、コースプロファイルや、走る人の特性によってかかる時間は様々です。

    平坦は得意だけど登りで大きく落ちる人もいれば、速くはないけれど後半まで淡々と走れる人もいます。こまめに休憩した方が安定する人もいれば、止まりすぎると逆に身体が重くなる人もいる。当然年齢も大いに関係しますし、自転車歴・運動歴の長さも影響するのはいうまでもありません。STRAVAのデータはそういった点で全体的な傾向はざっくり出してくれるのですが、「自分に特化した予測」は出してくれないなぁと感じていました。

    だったら、自分の過去の走行データを使って、自分用の予測ができないだろうか。

    そう考えました。

    まずAIに相談してみた

    ここまで考えたところで、AIに相談し始めました。

    プログラミングも、データ分析も、運動生理学も詳しくありません。なので、最初からかなり丸投げです。

    10時間以上のロングライドルートを作った時に、休憩込みの予測時間や1時間ごとの到達地点を知りたい。自分の過去データはある。心拍、ケイデンス、スピードはあるけれど、パワーメーターはない。最終的にどういうシステムにするかはわからないけれど、相談しながら作りたい。

    そんな感じで投げてみました。

    すると、AIは妙に乗り気でした。

    単なるルート完走予測ではなく、自分専用の疲労モデル、補給モデル、停止傾向、地形適応、天候耐性を積み上げれば、ロングライド用の個人適応ペース戦略エンジンのようなものが作れるかもしれない、と言うのです。

    個人適応ペース戦略エンジン。

    急に大げさです。

    でも、言いたいことはわかります。

    要するに、一般的なサイクリストの平均ではなく、自分の過去ログから作る予測です。5%の登りで自分はどれくらいの速度になるのか。150kmを過ぎるとどれくらい落ちるのか。気温が高い日に心拍はどう上がるのか。夜間や疲労時にペースはどれくらい落ちるのか。休憩はどのくらいの間隔で入れると安定するのか。

    そういう情報が積み重なれば、「一般的にはこのくらい」ではなく、「自分ならこのくらい」という予測に近づいていくはずです。

    もちろん、この時点ではまだ何もできていません。会話の中で、夢だけが膨らんでいる状態です。

    ただ、最初の一歩としては十分でした。

    パワーメーターはない

    少し気になっていたのは、パワーメーターがないことでした。

    僕が使っているのは、心拍センサー、ケイデンスセンサー、スピードセンサーくらいです。最初は、それだと大したことはできないのかな、と思っていました。

    でも、AIに相談してみると、パワーメーターがなくてもロングライド予測にはかなり使える情報がある、という話になりました。

    心拍がどう変化するか、勾配ごとに速度がどれくらい落ちるか、疲れてきた時にケイデンスがどう変わるか。長時間走った後の巡航速度の低下や停止頻度、休憩後にちゃんと回復しているかどうかも、過去ログから見えてくるかもしれません。

    パワーがなくても、そういう変化を追えば「どれくらい崩れずに走れるか」はある程度見えてくるのではないか、というわけです。

    これはかなり面白いと思いました。

    自分がロングライドでどこまで安定して走れるのか。どこで落ちやすいのか。どういう条件で削られるのか。

    日没前に帰るためには、それらがわかれば良いのです。レースに出るわけではないのです。

    欲しいものを並べてみる

    最初に欲しいと思っていたのは、休憩や信号待ちを含めたグロスの所要時間でした。そして1時間ごとの予想到達地点も欲しい。

    さらに考えていくと、15分以上の大休憩をどこで入れるべきか、補給食をどれくらい持てばいいのか、走行予定日の天気や降雨リスクはどうか、といった情報も気になってきます。長い登坂がどこにあるかを見た上で、そこまでにどのくらい補給をしておくべきかまで提案してくれたら、かなり助かります。

    書き出してみると、ずいぶん欲張りです。

    でも、ロングライドの計画としては、どれも実際に知りたい情報です。

    特に、10時間以上走るようなルートでは、途中の判断が後半に効いてきます。序盤に飛ばしすぎる。補給が遅れる。暑さを軽く見る。コンビニがあると思って進んだらしばらく何もない。そういう小さなことが、後半大きく崩れる原因となります。

    だから、単なる「到着時刻予測」ではなく、もう少し広い意味でのロングライド用の計画ツールが欲しかったのだと思います。

    ロングライドは脚力より崩れ方

    もう一つ、大事な視点があります。

    ロングライドは、脚力より崩れ方の方が難しい。

    これもAIとの会話の中で出てきた言葉ですが、かなり本質的だと思いました。

    もちろん脚力は大事です。速く走れるに越したことはありません。登りに強ければ選べるルートも広がります。

    でも、ロングライドで本当に難しいのは、前半にどれだけ速く走れるかではなく、後半でどれだけ崩れないかです。

    同じ5%の坂でも、30km地点で登るのと、180km地点で登るのではまるで違います。

    前半なら淡々と登れる坂が、後半では急に脚に来る。気温が高ければ体力を削られます。補給が遅れれば力が出なくなります。長時間休憩を挟んだら身体が重くなることもあります。深夜になれば眠気も出ます。

    そういうものが積み重なって、ある地点から急にペースが落ちる。

    たぶん、ロングライドで怖いのはそこです。

    予定より少し遅れるくらいならいい。でも、疲労や補給不足で後半に大きく崩れると、日没前に帰るための計画そのものが崩れます。

    だから本当に予測したいのは、単に「この勾配ならこの速度」ではなく、「この距離まで走った後、この状態で、この登りに入ったらどうなるか」なのかもしれません。

    いきなり難しくなってきました。

    最初から全部は無理

    ここまで考えると、欲しいものはどんどん膨らんでいきます。

    疲労や補給、休憩の影響はもちろん、天気、風、気温、日没、コンビニの位置、市街地の走りにくさ、信号、長い登坂、後半失速。考え始めると、入れたい要素はいくらでも出てきます。

    何やら大変なことになってきました。

    ただ、最初から全部を作ろうとすると、たぶん破綻します。

    なので、まずはかなりシンプルに考えることにしました。

    最初に作るべきものは、ルートを読み込んで、自分の過去データをもとに完走予測時間と区間ごとの予測速度を出すことです。そこに1時間ごとの予想到着地点と、できれば補給の目安を添える。

    まずはそれだけでいいはずです。

    それだけでも、ロングライド前の不安はかなり減るはずです。

    この時点で、なんとなく最初の形が見えてきました。

    STRAVAで作ったルートを読み込み、過去の自分の走行データをもとに勾配や距離から速度を予測する。そこに休憩込みのグロス時間や1時間ごとの到達地点、補給やコンビニ情報を重ねていけば、少なくとも「日没前に帰るには何時に出ればよいか」は、かなり考えやすくなりそうです。

    ステムシートに貼りたい

    そして、出力の形として最初に思い浮かんだのがステムシートでした。

    プロの選手がステムにコース情報や補給計画を貼っているのを見て、前から少し憧れがありました。

    ロングライドで同じことをやるなら、1時間ごとの予想到達地点、補給タイミング、コンビニの有無、休憩の目安あたりが小さくまとまっていると便利そうです。

    スマホを出して確認するより、ステムに貼ってある方が走りながら見やすい。少なくとも、最初の発想としてはかなり現実的です。

    ここでようやく、最初の目標が決まりました。

    STRAVAで作ったGPXルートを読み込み、自分の過去走行データをもとにグロスの走行時間を予測する。そこから1時間ごとの予想到達地点を出し、補給やコンビニ情報もできる範囲で載せて、最終的にはステムシートとして印刷できる形にする。

    まずはここまで。

    今思えば、この時点ではまだ平和でした。

    「日没前に帰るために、何時に出発すべきか」

    そこから始まった話が、いつの間にか「自分専用のロングライド予測ツール」になってきました。

    さて、では実際にどう作るのか。

    ここからが大変でした。

    次回は、ChatGPTと一緒に過去の走行データを分析し、勾配別速度や補給プラン、ステムシートを作ろうとして、スクリプトや出力ファイルがどんどん増えていく試作編です。

    この時点ではまだ、後にスマホで現在地つきのマップまで作ることになるとは思っていませんでした。

  • ライドスケジュール予測システムを作ってテストしてみた

    やってみたかったんです。こういうの。

    よくプロの人達がステムシートに補給プランやコースプロファイルなどを貼ってますよね。あれを真似してみようと。

    いつもロングライドをする際には、休憩時間など込みのグロス走行時間を予想して出発時刻を決めたり、走行中でも、今いる場所から次の峠まで何時間かかるかなどを予測したりしていました。また、走行経験のないルートなどでは、コンビニなどがあるかどうかなどもリサーチした上で補給食をどの程度携行するかも考えたり。

    それらについて、うまいこと予測が立てられて、ステムシートに計画を貼れたら便利だな、と思ってはいましたが、そういったことをできるアプリがあるのかどうか定かではありませんでした。

    調べてもいいんですが、最近はAIもとんでもなく進歩しているようで、プログラミングとかの知識がなくても「こういうことやりたい」でアプリみたいなものが出来るとか。試しに自分で作れないか?と思ったのがコトの発端です。

    一時が万事、こんなノリでチャットを重ねていきました。

    さて。目標としてはSTRAVAで作成したルートを元にグロスの走行時間と、1時間ごとの到達距離をステムシートに貼れるサイズでpdfに出力させることにしました。

    使ったのはChatGPTの一ヶ月期間限定無料アップグレード版PlusというプランとCodexというやつ。なんかよくわからないけど「スゴい」とか。僕のAIについての知識なんて、そんな程度。いまだに知りたい情報は、ググって検索結果を上位から眺めて情報に辿り着くような、”ITリテラシーの低い人”であります。

    この辺りの経緯は試行錯誤してめちゃくちゃ混乱しているので、別の機会に追々書ければ良いかなと思っていますが、大まかな流れはざっくり下記。

    1. 自分の走行傾向を知る

    予測を立てるためには自分を知らなければなりません。過去の自分の走行データをSTRAVAからダウンロードして色々分析してもらいました。その手順も聞いたら色々教えてくれました。

    2. 分析結果を元に予測行程をpdfに出す

    当初は1時間毎の予測到達距離を一覧に出してもらえたら良いな、と思っていたのですが、やっていくうちに色々出来ることがわかってきて「じゃあこの区間にコンビニあるかどうかも出して」「補給するべきカロリーとか出して」などやっていくうちに情報が膨れ上がり、ステムシートに収まりきらなくなったりしました。

    3. 欲が出てmapにも表示させたくなった

    ステムシートがうまく行ったことでつい欲が出て、スマホでマップを出力してもらって、1時間毎の到達地点や、コンビニの有無、さらには現在地表示までお願いしてみたり。この部分もわからないことだらけで、試行錯誤しましたが、なんとか着地できました。

    とにかく「こうしたいんだけどどうやるの?」に対して「これを〇〇に貼り付けてください」みたいなやりとりを重ねた結果。

    こんな感じの入力画面でSTRAVAで作ったマップを選択すると、結果が手に入ります。

    これがスタート時刻をAM4時にした場合のステムシート。

    何やら、謎の記号がありますが、それは単語をそのまま表記すると列幅を超えて文字が重なり合ってしまい、使い物にならなかったため省略表記させているためです。例えば9hの行で言えば、M350はMountainのルート(つまり峠など本格的なクライミングが含まれる)かつ、推奨補給カロリー数。ONI+GEL/WTRとは、おにぎり(Onigiri)とジェルに水を補給しよう、ということを意味します。おにぎりは別にマストではないのですが、ChatGPTはおにぎりを推してきたのでそのまま採用しています。

    CVS NOとはコンビニがルート上でこの近辺にないことを表しています。これは今回色々作り込んでいく中で欲しいなと思ったものの一つです。これを見て「あ、ここで2時間分はオヤツを買っておかなきゃ」と出来るので便利。

    そうやって作り込んでいったら、ある時点で1時間毎の予測到達点のルート上にあるコンビニをマップで表示させたらさらに良いんじゃないか?と思って、コンビニマップの有無をポイント毎に表示させるマップを作りはじめる始末。

    さらには、予想到着時刻や、現在地も表示させるという、大分詰め込んだ仕様になってしまいました。

    色々作れてしまうのでついつい”あれもこれも”と盛り込みたくなりますが、キリがなくなってしまうので一旦良いところでテストライドして見ることにしました。

    pdfをネットワークプリントサービスでプリントアウトしてステムに貼り付けます。ちょっと贅沢して光沢紙でカラー印刷してみました。一枚120円。高いな。

    さて。今回のテストルートは片道自走。西伊豆まで向かう途中、熱海で荷物を預け、西伊豆をぐるっと回って熱海に戻る、という220km獲得標高4000mのルートです。

    4時スタートを計画してステムシートやマップはそれを基準にして出力していましたが、実際は1時間早い3:04にスタート。

    夜明け前の中原街道を南下していきます。1時間後には18km進んでいる予測ですが、果たしてどうだろう、と思いながらアップダウンを繰り返す道を進んでいきます。すると、ほぼ予測通り18km地点で1時間となりました。我ながらびっくり。

    2時間後もほぼ予測通りで進んでいきます。陽も既に昇り、快晴の中を進んで金目川の辺りまで。

    富士山も霞みながらもよく見えます。この先も雲に隠れなければ良いな、と思いながら、スマホで作成したマップを確認してみました。

    こんな感じで現在地や予測最終地点到着時刻(ETA)などがわかります。Scheduleが64分先行となっているのは、作成時点では4時スタートとして出力したからです。実際には3:04スタートなので8分早く進んでいるということになります。ややこしい。この辺りはちょっと工夫しなくては。

    そんなことを思いつつ、小田原を過ぎ穏やかな相模湾を横目にご機嫌になりながら熱海駅に到着しました。ようやくバックパックを下ろして身軽になれました。

    さて。ここから伊豆多賀の山伏峠を越えていくわけですが、そこでふと思いました。

    今回のルートではこの熱海から修善寺までのルートは往路と復路が重なります。マップ上で現在地は取得できても、それが往路か復路かが判別できなければ、場合によってはまだ前半の走行であるにも関わらず復路として到着予定時刻を弾き出してしまうかも、ということです。

    うーむ、そんなこと考慮に入ていないな、と思いながら久しぶりの山伏峠を登っていきます。なかなかの激坂仕様ですが、4km程と短く、峠手前では相模湾を見下ろす最高の区間もあるので、好きな上りです。

    往路の山伏峠終了。この時点で8時40分でした。予測マップを見たところ、ETAが午前9時過ぎとなっていたので、復路の山伏峠にいることになっているようです。

    これは修正しなくちゃなー、と思いながら修善寺に向かってダウンヒル。マップはさておき、ステムシート上の予定時刻では15分ほど先行している程度で、出発から6時間過ぎても比較的良い予測精度になっていました。

    修善寺から月ヶ瀬の道の駅に向かいます。今回は土肥から宇久須に南下した後仁科峠を登って西伊豆スカイライン北上、という定番のルートです。仁科峠へのクライミングルートはちょうど今、工事により一部通行規制がかかる期間なのですが、それは平日のみだったことがわかり、ルートに組み込めました。

    月ヶ瀬の道の駅に休憩で立ち寄り、特に長居するつもりはなかったものの「究極の生ジュース」のキッチンカーを目にして飲んでみることにしました。

    みかんだ!みかんだ!すっごくうまい!っとSサイズを瞬殺。

    Lにしてもよかったか?とも思いましたが、お腹がたぷんたぷんになると、この後船原峠までの緩いながらの上りで込み上げちゃうかもなので、良い選択だったかと。

    そんなこんなでリスタートして土肥に向かいます。船原トンネルを越えて、土肥へのダウンヒルを気持ちよくこなし、土肥に着いたのは10:30。この時点で予測より30分ほど先行していました。

    ここで休憩して11時ぐらいに出たら、宇久須には11:30~45に着くと思われ、そこのコンビニで休憩と補給を済ませて仁科峠の上りに1時間15分程度かかるとして13時に仁科峠。おそらく熱海帰着は遅くとも17:00前かな、とざっくり計算してみました。

    実際、ステムシートの予測にこだわりすぎると、それに縛られる感じもあり、ちょっと本末転倒な気もしてきたので、休憩したい時には休憩するし、必要がなければ軽く止まって補給食を食べる、で良いよね、と思い始めました。

    トーストセットのトーストから牛乳の風味が感じられてなかなか美味しかったです。

    駿河湾を眺めながらしばし、ぼーっとします。

    この時点で140km走っているので、距離で言えば2/3近く進んでいます。ただ、ここから先は仁科峠、西伊豆スカイラインが控えているので、気分的にはまだ半分手前の感じです。

    11時に再スタートして宇久須へ。

    途中で振り返れば富士山がよく見える穏やかな上りを進み、予測通り11時半に宇久須に到着しました。予測システムもいい感じですが、従来の自分の予測も悪くない。

    ドリンクと補給食を追加して、いよいよ仁科峠へ。

    正面にそびえる仁科峠の稜線に向かってしばしの平坦区間。いきなり勾配ズドン、ではなく気持ち昂る序章としても申し分ない演出です。キツいの知っていてもワクワク。

    勾配が本格的になってしばらくは比較的木々に覆われて入るものの確実に夏日の強い日差しが照りつけ、満タンにした700ml容量のボトルもみるみる減っていきます。インサイドは30%あるらしいカーブも切り抜け、わずかにある平坦区間に差し掛かります。そして再び二桁以上の勾配に戻り、やがて駿河湾が見下ろせる開けた区間にたどり着けばそこが天城高原牧場。

    途中牛舎の横を通り過ぎるのですが、今回初めて放牧された牛さんたちが牧草地でのんびりとくつろいでいました。みんな怪訝そうな面持ちでこちらを眺めております。

    そんなこんなで、仁科峠到着。時刻はちょうど13時。自分の予測ぴったりです。ステムシートでは、この先下って風早峠の先の登り返しの辺りに到着している予定なので数分ビハインドぐらいかな、と思いながら途中で買った一口わらび餅を頬張ります。

    ここまで来れば、西伊豆スカイラインの達磨山への上りと大仁線の山伏峠への上りを残すのみ。距離にして60kmで熱海に到着です。

    修善寺には2時間あれば着くかな?という計算をして西伊豆スカイラインに向かって再スタート。一時は雲に隠れていた富士山も要所要所で見えていて、定番スポットでは良い具合に眺めることができそう。

    西伊豆スカイラインに入る前にそれなりに下ってのち、達磨山に向かって30分ほどの上り。途中で朝下っていた土肥へのダウンヒルの道が遥か下に見えたりして、ずいぶん走ってきたなぁ、と感慨深くなります。

    上りが終了する辺りで振り返ると仁科峠が遠くに望めます。そこから一旦ダウンヒルして達磨山の手前の戸田を見下ろせる駐車場へ。

    そして軽く登り返して達磨山を回り込み再びダウンヒル。

    ここまで自走で来た!以前は沼津や修善寺、もしくは伊東などを起点にしないと無理だと思っていたのが、まさか自走で来るようになるとは。

    修善寺駅に着いたら併設の「いずーら」でしいたけそばを食べようと思いながら駅に向かってダウンヒル。標高が下がってくるとだんだん暑さが戻ってきて、冷やしそばに気分が傾いてきます。

    大盛りはなかなかのボリュームですが冷えたお蕎麦の心地よい喉越しに、するりと食べきってしまいました。

    ひと心地ついて再スタート。山伏峠は本格的な上りの手前まで7kmほどはなだらかな上りです。その後4km弱10%程度を交えた上りをこなせば終わるので、キツイのもあと僅か。

    いつの間にかこちら側から西陽が照りつける山伏峠に到着。この時点で15:50となり進行予定からは数分遅れ程度。16:30頃に熱海駅に着くかな、と思いながら最後のダウンヒルに入ります。

    山伏峠といえば、この陸橋からの相模湾。ロングライドの最高の締めにホッと一息。

    135号線に戻って、熱海まで。熱海の街中を進んでいたら思いのほか信号に捕まりましたが、16:28に駅のコインロッカーの前に到着してサイコンの計測を終了。

    グロスの走行予測では13時間17分なのに対して、13時間23分という経過時間だったので、作成した予測システムは中々の出来栄えであります。

    何よりも、途中コンビニ休憩以外にもカフェ休憩やお蕎麦休憩など、ロングライドならではの不確定要素も盛り込んでこの精度なのが驚きでした。もちろん、予測システムを作る段階で、そういった要素も含めてグロスでの走行時間や途中経過を予測するように仕立てたのですが、案外使えそう。

    あとは、マップの改修とステムシートの内容の見直しなど、色々手入れをしていって使い勝手が良くなれば良いかな、と思案中です。