<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Gagandeep Reehal: Technical Essays]]></title><description><![CDATA[Technical Blogs]]></description><link>https://www.gagandeepreehal.com/s/technical-essays</link><image><url>https://substackcdn.com/image/fetch/$s_!D1df!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd8e1b3-2111-4f69-8951-e1698fa0d341_747x747.png</url><title>Gagandeep Reehal: Technical Essays</title><link>https://www.gagandeepreehal.com/s/technical-essays</link></image><generator>Substack</generator><lastBuildDate>Wed, 19 Aug 2026 19:07:58 GMT</lastBuildDate><atom:link href="https://www.gagandeepreehal.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Gagandeep Reehal]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[gagandeepreehal@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[gagandeepreehal@substack.com]]></itunes:email><itunes:name><![CDATA[Gagandeep Reehal]]></itunes:name></itunes:owner><itunes:author><![CDATA[Gagandeep Reehal]]></itunes:author><googleplay:owner><![CDATA[gagandeepreehal@substack.com]]></googleplay:owner><googleplay:email><![CDATA[gagandeepreehal@substack.com]]></googleplay:email><googleplay:author><![CDATA[Gagandeep Reehal]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The MCAP Dilemma Because Your Robot Data Has Three Jobs]]></title><description><![CDATA[MCAP is not a bad training format. It is a recording format, and most of these arguments are two people describing different layers of the same stack.]]></description><link>https://www.gagandeepreehal.com/p/the-mcap-dilemma-because-your-robot</link><guid isPermaLink="false">https://www.gagandeepreehal.com/p/the-mcap-dilemma-because-your-robot</guid><dc:creator><![CDATA[Gagandeep Reehal]]></dc:creator><pubDate>Mon, 03 Aug 2026 08:44:45 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/78918627-0572-4b9f-86d8-9eaea79bb057_1200x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have some version of this argument about once a month. Someone tells me MCAP is the wrong way to store robotics data for foundation model training, usually with the air of correcting a common mistake.</p><p>They&#8217;re right, and they&#8217;re arguing past the person they&#8217;re arguing with.</p><p>Robot data gets asked to do three unrelated things. It has to survive being written on a machine that might lose power mid-session. It has to sit in cold storage long enough that the message definitions get refactored twice and still decode. And it has to keep eight GPUs busy with shuffled batches pulled out of object storage. Append-only and self-describing for the first. Immutable and cheap for the second. Columnar, sharded, randomly addressable for the third.</p><p>MCAP nails one of those, is defensible on another, and is the wrong shape for the last. Which one someone has in mind is almost never stated, and that&#8217;s the whole fight.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lGF8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lGF8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!lGF8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!lGF8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!lGF8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lGF8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png" width="1456" height="910" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:910,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:352701,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/209082625?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lGF8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!lGF8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!lGF8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!lGF8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd62a428-a6e9-4ca8-8f8a-103dd1a599a3_3200x2000.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Capture, archive, train. Same bytes, three different demands.</em></figcaption></figure></div><h3>The part nobody actually disputes</h3><p>Open an <code>.mcap</code> file and the layout announces its purpose. Magic bytes, header, then a data section of chunks, each holding a batch of messages under zstd or lz4, with a message index record written right after each chunk that maps timestamps to offsets inside it. Summary section at the end with the chunk index and statistics, then a summary offset section, footer, magic bytes again.</p><p>All of that is append-only. The writer never seeks backward. So when a robot browns out mid-recording, and it will, you lose the tail and nothing else; a reader scans forward through chunks and recovers every message up to the instant the write stopped. Formats that assemble their structure in memory and serialise on close hand you a zero-byte file instead.</p><p>People underrate the index. Chunk indexes and statistics get written last, on clean close, which buys you seeks by time and topic without scanning the file. Only on clean close, though. <code>rosbag2_storage_mcap</code> ships a <code>fastwrite</code> preset that skips index writing to cut recording overhead, and its own docs warn the output isn&#8217;t suitable for long-term storage: no index, no topic-subset reads, no seeking. Worth checking whether anyone on your team turned that on to save CPU and whether anything downstream quietly assumes it can seek.</p><p>Schemas live inside the file. That reads like a footnote and it&#8217;s the most valuable property MCAP has, because data outlives code by years. Whoever wrote <code>MyCustomState.msg</code> has left, the definition changed twice since, and the 2023 logs still decode.</p><p>It&#8217;s also heterogeneous. ROS 2 CDR, Protobuf, FlatBuffers, JSON, one timeline, one seek. Anyone who has tried to align five sensor streams sitting in five files against five clocks knows the value of that without being told.</p><p>ROS 2 made it the default bag format, NVIDIA Isaac ships it as the default log format, and writing your own binary capture format in 2026 is solving a problem that closed.</p><h3>Flip the query</h3><p>A dataloader never asks for every topic at instant <em>t</em>. It asks for one field, from a million random instants, ordered by a shuffle buffer, streamed out of S3, across four hundred workers.</p><p>Different question, different disk layout, and no amount of engineering makes one file answer both.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7HXJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7HXJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!7HXJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!7HXJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!7HXJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7HXJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png" width="1456" height="910" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:910,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:278983,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/209082625?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7HXJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!7HXJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!7HXJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!7HXJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ca4e015-c3f2-41e1-9834-f6d23c9c2863_3200x2000.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A log answers &#8220;everything at this instant.&#8221; A dataloader asks for the inverse.</figcaption></figure></div><p>The mechanism deserves precision, because &#8220;row-oriented is slow&#8221; gets repeated by people who couldn&#8217;t say why.</p><p>Chunk-granularity compression is the culprit, and it&#8217;s also the feature. You&#8217;re not compressing per message, you&#8217;re amortising over a block, which is exactly what makes MCAP cheap to write. But zstd hands you the whole block or nothing. Your chunk holds six camera topics, lidar, IMU, CAN frames, and the 100 Hz control vector you actually wanted, and you decompress all of it to get the last one. Rough arithmetic on a modest rig: total log bitrate around 10 MB/s, control maybe 0.1 MB/s of it. Roughly a hundred bytes decompressed per byte used. Columnar layouts land somewhere near 1&#8211;3&#215; on the same data because column chunks and dictionary encoding let you skip what you never read.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZJ5X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png" width="1456" height="910" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:910,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:240135,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/209082625?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!ZJ5X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F180ab193-20d9-4a1a-963f-16f68306fc80_3200x2000.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Chunk-level compression is what makes the log cheap to write and one field expensive to read.</em></figcaption></figure></div><p>The index is optimised for the wrong axis, too. It answers &#8220;where is topic X at time T in this file.&#8221; Training asks for a random sample across forty thousand shards. Unrelated lookups.</p><p>Then there&#8217;s object storage, which punishes small random reads in a way that surprises people the first time. First-byte latency in the tens of milliseconds, per-request overhead dominating anything under a few megabytes. Training formats shard at roughly 100 MB to 1 GB specifically to amortise that: one request, then stream. WebDataset&#8217;s entire design is sequential reads inside a shard and randomness between shards, which approximates a global shuffle through shard ordering plus an in-memory buffer without ever issuing a small random GET. Point a naive reader at MCAP files in a bucket and the request overhead will find you before the decompression overhead does.</p><p>And the one that actually shows up in your utilisation graph, which almost nobody talks about: multi-rate alignment gets paid every epoch instead of once. Cameras at 30 Hz, proprioception at 200 Hz or 1 kHz, control at whatever the loop runs, GNSS at 10 Hz. Some of those timestamps are software-stamped at receipt rather than hardware-triggered or PTP-disciplined, if you&#8217;re honest about your stack. A log preserves that mess faithfully, which is correct; it&#8217;s the raw truth. A training format resamples and aligns it into fixed tensors once, at transcode time. Do that interpolation inside the dataloader instead and you burn it again on every epoch of every run, in Python, on the critical path.</p><h2>What the field ships</h2><p>If training off the log were workable, someone would be doing it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yXAK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yXAK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!yXAK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!yXAK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!yXAK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yXAK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png" width="1456" height="910" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:910,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:285311,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/209082625?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yXAK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 424w, https://substackcdn.com/image/fetch/$s_!yXAK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 848w, https://substackcdn.com/image/fetch/$s_!yXAK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 1272w, https://substackcdn.com/image/fetch/$s_!yXAK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80e2835-59c0-497a-9ded-d823851adf4d_3200x2000.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Five efforts, five training formats, no MCAP.</em></figcaption></figure></div><p>Open X-Embodiment, DROID, LeRobot, Waymo, NVIDIA&#8217;s own robotics stack: five efforts, five different training formats, no MCAP. Every one has a conversion step, and several throw away fidelity on purpose. DROID&#8217;s RLDS training copy is downscaled, left-camera only, motor torques dropped, 1.7 TB sitting beside an 8.7 TB raw MP4 archive. Somebody decided a batch shouldn&#8217;t carry bytes the model never looks at.</p><p>NVIDIA&#8217;s version convinces me most. Isaac uses MCAP as its default logging format and emits LeRobot- and RLDS-compatible data for training. Same org, same stack, line drawn between layers without any fuss about it.</p><p>Worth admitting the training layer is unfinished rather than glossing over it. openpi falls back to RLDS for full DROID training because LeRobot&#8217;s format wasn&#8217;t scalable enough at that size, by Physical Intelligence&#8217;s own account. LeRobot v3 concatenates episodes per file to stop drowning in small files. Lance exists because Parquet&#8217;s random access is mediocre. Nobody has settled this. What is settled is that it&#8217;s a separate layer from the log.</p><h2>The video sub-argument</h2><p>Someone always says just use encoded video instead.</p><p>MCAP is a container, H.264 is a codec, and they aren&#8217;t alternatives. Encoded video goes inside MCAP.</p><p>The real argument underneath is older and correct: don&#8217;t put raw frames in a bag. 1920&#215;1080 RGB8 at 30 fps runs about 6.2 MB a frame, 186 MB/s per camera. Six cameras clears a gigabyte per second, four terabytes an hour, per vehicle. The same footage at 10 Mbit/s H.264 is 1.25 MB/s. Call it 150&#215; per camera. Teams who learned that in 2021 have the invoices.</p><p>The fix was never abandoning the container. It was <code>CompressedVideo</code> message types carrying H.264/H.265/VP9/AV1 frames inside MCAP, so you keep the codec&#8217;s compression and the cross-sensor alignment together. Writing <code>sensor_msgs/Image</code> to disk at fleet scale is the bug.</p><p>Bare <code>.mp4</code> with a timestamp sidecar does genuinely win in one configuration: single camera, no other sensors, browser-first review UI. MCAP&#8217;s synchronisation is worth nothing there and you&#8217;re paying for a feature you don&#8217;t use. Though I&#8217;d note that describes a webcam more than a robot.</p><p>One constraint follows you into any container. Seek cost on video is governed by GOP structure, not by whatever wraps it &#8212; you can&#8217;t decode an arbitrary frame without walking back to the last IDR, so long GOPs save storage and make scrubbing miserable. Teams that need frame-accurate replay force short keyframe intervals and eat the bitrate. That&#8217;s an encoder decision, and it wants making before you&#8217;ve recorded a petabyte you can&#8217;t scrub.</p><h2>The pipeline</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uwuf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uwuf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 424w, https://substackcdn.com/image/fetch/$s_!uwuf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 848w, https://substackcdn.com/image/fetch/$s_!uwuf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 1272w, https://substackcdn.com/image/fetch/$s_!uwuf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uwuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:215608,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/209082625?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uwuf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 424w, https://substackcdn.com/image/fetch/$s_!uwuf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 848w, https://substackcdn.com/image/fetch/$s_!uwuf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 1272w, https://substackcdn.com/image/fetch/$s_!uwuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd05fa43-e56c-4cda-9775-4e6e8c70dfa5_3200x1800.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Record once. Curate before you copy. Transcode only what earns a place in a batch.</em></figcaption></figure></div><p>Encode at the source, in hardware, before anything touches the bus. Record MCAP at the edge. Keep raw MCAP as the immutable cold tier, because being able to re-derive a dataset three years out beats the storage line item, particularly the first time a model does something inexplicable and you need the unmodified bytes.</p><p>Then curate before you transcode. Teams skip this step and it&#8217;s the expensive one. Egress and compute for a full-corpus transcode can rival what you pay to store the corpus: Robo-DM&#8217;s authors put an 8.9 TB Open-X slice at roughly $172/month on GCP against $172&#8211;$1,540 for a single full download. Index the MCAP, search it, work out which fraction deserves to go in front of a model, transcode that.</p><p>(For most fleets the fraction worth training on is small, and nobody enjoys saying so in the data meeting.)</p><p>Pick the training format from your model stack rather than from a blog post. WebDataset for streaming large image or video corpora sequentially. Parquet plus MP4 inside the LeRobot ecosystem. RLDS where you need Open X-Embodiment compatibility. Lance when random access and dataset versioning dominate.</p><p>Keep lineage from shard back to source file. The day someone asks what data trained a given checkpoint, and in anything safety-relevant someone will, you either have the answer or you have an incident.</p><h2>What I&#8217;d measure instead</h2><p>Read amplification first: bytes decompressed and read per byte the model consumes. Near 1 and you can stop reading. At 50&#215; the transcode step has already paid for itself.</p><p>Then data-stall percentage, the wall-clock fraction where GPUs sit idle waiting on input. It&#8217;s the only number that decides whether your storage layer is a real problem, and most teams never instrument it. &#10216;YOUR NUMBER GOES HERE &#8212; what yours was before and after. This is the single line that makes the post yours rather than a literature review.&#10217;</p><p>Time-to-first-batch on a cold cache is the third, and I care about it more than the other two combined. How long from wanting to train on a slice to the first gradient step. Iteration speed lives there, and it&#8217;s dominated by curation and transcode rather than by anything in your model code.</p><div><hr></div><p>Everyone in Physical AI agrees data operations are the moat now. Fine. A moat is a set of unglamorous decisions about where bytes live and how fast you can reshape them into a batch. The advantage doesn&#8217;t go to whoever collects the most; it goes to whoever has the shortest path from <em>a robot did something interesting</em> to <em>that experience is in a training batch</em>. That path runs through the transcode step nobody wants to own.</p><p>So, is MCAP a bad format for foundation model training data? It&#8217;s the best format for recording robot data and the wrong shape for training on it, and those two claims were never in tension.</p><p>Whether that holds is the part I&#8217;m less sure about. Foxglove is pushing MCAP-native search at petabyte scale, and if curation moves into the log format itself the transcode step gets narrower and later. It doesn&#8217;t vanish, since the dataloader still wants columns and shards and physics doesn&#8217;t negotiate. But the boundary moves, and I don&#8217;t have a confident read on where it lands.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.gagandeepreehal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[TOPS Is a Vanity Metric]]></title><description><![CDATA[Peak compute tells you almost nothing about how your robot will actually perform]]></description><link>https://www.gagandeepreehal.com/p/tops-is-a-vanity-metric</link><guid isPermaLink="false">https://www.gagandeepreehal.com/p/tops-is-a-vanity-metric</guid><dc:creator><![CDATA[Gagandeep Reehal]]></dc:creator><pubDate>Tue, 07 Jul 2026 17:37:39 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5df781a3-5d87-4b45-81b9-44ce36c010b1_1252x946.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Walk into any edge AI product launch and one specification dominates the marketing slide: TOPS </p><p>TOPS is the most abused number in edge AI.</p><p>It looks objective. It looks comparable</p><p>TOPS isn't a lie. It answers a real but narrow question: how many low-precision operations an accelerator can execute per second <em>if</em> every arithmetic unit stays perfectly fed. That "if" is doing enormous work. It says nothing about whether your workload can actually feed those units, whether your model survives the compiler intact, whether memory movement swamps the math, or whether the rest of the system keeps pace.</p><p>Most edge workloads aren't matrix-multiply problems anyway. They're streaming pipelines: sensors, copies, preprocessing, quantization, scheduling, synchronization, post processing, all of it running against a control deadline. Peak compute touches one slice of that. So the equation people carry in their heads,</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{performance} = \\text{TOPS}&quot;,&quot;id&quot;:&quot;HFOIEYWILM&quot;}" data-component-name="LatexBlockToDOM"></div><p>is really</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\n\\text{end-to-end latency} ={}&amp; \\text{sensor} + \\text{preprocessing} + \\text{queueing} \\\\\n&amp;+ \\text{data movement} + \\text{inference} + \\text{postprocessing} \\\\\n&amp;+ \\text{host sync} + \\text{application}\n\\end{aligned}\n&quot;,&quot;id&quot;:&quot;CCKFQVJJML&quot;}" data-component-name="LatexBlockToDOM"></div><p>and TOPS only bends one term.</p><h4>Compute-bound is the exception, not the rule</h4><p>The roofline model is the cleanest way to see why. Every workload has two numbers: operations it needs, and bytes it moves. Divide them and you get arithmetic intensity.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot; \\text{arithmetic intensity} = \\text{operations} / \\text{bytes moved}&quot;,&quot;id&quot;:&quot;MGJNAPWLRC&quot;}" data-component-name="LatexBlockToDOM"></div><p>High intensity means you're compute-bound, and more TOPS can help. Low intensity means you're memory-bound, and TOPS barely moves the needle. Here's the trap in every TOPS pitch: it quietly assumes your model lives on the compute-bound side. A lot of real pipelines don't. A fat convolution might keep the array busy, but resize, normalization, layout conversion, feature-map shuffling, NMS, tracking, and the small dynamic ops mostly spend their time shoving bytes around, not multiplying them.</p><p>Your real ceiling is whichever wall you hit first:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\n\\begin{aligned}\n\\text{effective Performance} = \\min \\bigl(&amp;\\text{compute},\\ \\text{memory bandwidth}, \\\\\n&amp;\\text{runtime/software}\\bigr)\n\\end{aligned}&quot;,&quot;id&quot;:&quot;UOEMHOQJNO&quot;}" data-component-name="LatexBlockToDOM"></div><p>A 100-TOPS part can behave like something a quarter its size the moment bandwidth, data layout, or host-device transfers become the binding constraint.</p><div><hr></div><h4>DGX Spark - an interesting analogy to understand this</h4><p>The cleanest public proof of this isn&#8217;t an edge board at all. It&#8217;s NVIDIA&#8217;s DGX Spark, a desktop AI box, and it argues the point better than any robotics part because every number is out in the open.</p><p>The headline spec is 1,000 TOPS of FP4. A literal petaflop on your desk. Then you read the next line: 128 GB of unified LPDDR5x at 273 GB/s. If you do hands-on, you would only touch that petaflop in half-second bursts before memory bandwidth choked it off. Not that FP4 units running slow, but because the chip starving for data. That gap between the sticker number and the sustained number is the entire thesis of this essay, printed on one spec sheet.</p><p>Every independent review landed in the same spot. One of them called the unified bandwidth the key bottleneck and clocked Llama 3.1 70B decoding at under three tokens per second on a machine rated for a petaflop. Another split it more precisely: prefill, which chews through the whole prompt at once, stayed competitive because it&#8217;s compute-bound; decode, which emits one token at a time and re-streams the weights for each one, fell off a cliff because it&#8217;s memory-bound. Same silicon, same model, two phases, two completely different ceilings. That&#8217;s the roofline model doing its job in public.</p><p>Now shrink it to something that ships on a robot. The Spark runs in a ~200 W envelope with active cooling and no deadline. Your Jetson or Hailo has a fraction of that power budget, a fraction of that bandwidth, and a control loop that will not wait. If a plugged-in desktop holding a petaflop of FP4 gets pinned by memory movement, a battery-powered perception stack gets pinned harder and sooner. The physics doesn&#8217;t care that one sits on a desk and the other sits on an axle.</p><div><hr></div><h4>- Utilization is the number nobody prints</h4><p>Peak TOPS assumes 100% utilization. You will not see 100% utilization.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{effective TOPS} = \\text{peak} &#215; \\text{utilization}&quot;,&quot;id&quot;:&quot;FQVQNGSZUY&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Run a 100-TOPS accelerator at 20% and you have a 20-TOPS device wearing a bigger label. Utilization bleeds out through unsupported operators, small tensors, dynamic shapes, memory stalls, kernel-launch overhead, CPU fallback, sync gaps, thermal throttling, and batch-1 execution. This is the whole reason a smaller accelerator sometimes beats a larger one on a specific job: less peak compute, but far more of it actually used.</p><h4>- The tensor doesn't just get multiplied. It gets moved.</h4><p>Inference is as much data logistics as arithmetic. Trace one camera frame:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cj78!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cj78!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 424w, https://substackcdn.com/image/fetch/$s_!cj78!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 848w, https://substackcdn.com/image/fetch/$s_!cj78!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 1272w, https://substackcdn.com/image/fetch/$s_!cj78!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cj78!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png" width="1456" height="667" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/adec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:667,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:953554,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/205716735?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cj78!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 424w, https://substackcdn.com/image/fetch/$s_!cj78!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 848w, https://substackcdn.com/image/fetch/$s_!cj78!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 1272w, https://substackcdn.com/image/fetch/$s_!cj78!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadec9d41-95ae-41b4-8f59-ebc82b0a106b_1852x849.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Every arrow is latency: copies, cache misses, DMA setup, driver overhead, synchronization, layout conversion. And the intermediate activations are often much larger than the input frame, so they, not the image, dominate memory traffic. A lot of the time the accelerator isn't waiting on math. It's waiting on data. Move your tensors too much and the TOPS number stops meaning anything.</p><h4>- Batch size flatters the wrong systems</h4><p>The most flattering benchmarks are throughput benchmarks, and throughput loves batching: more work per scheduling event, higher utilization, prettier FPS. But a robot, drone, camera, or inspection rig lives and dies on batch-1 latency. You can't wait to collect eight future frames. You need this frame now.</p><p>So the numbers that matter aren't max FPS. They're p50, p90, p99, jitter, dropped frames, and how latency holds once the part is hot. A device that screams at batch 8 can be useless to a robot that needs steady batch-1 timing.</p><h4>- Operator coverage is a performance feature</h4><p>Hardware doesn't run models. It runs supported graphs. Map every operator cleanly and things fly. Leave a few unsupported and the graph gets partitioned between accelerator and CPU, and that's where performance dies. The usual offenders: custom NMS, dynamic reshape, oddball interpolation, LayerNorm, attention blocks, deformable convolutions, unusual activations, quantization patterns the compiler won't take.</p><p>The damage isn't that one operator runs slow. It's fragmentation:</p><div class="callout-block" data-callout="true"><p><code>accelerator &#8594; CPU &#8594; accelerator &#8594; CPU</code></p></div><p>Every boundary is another round of copies and synchronization. One unsupported op can drag down the whole graph around it.</p><h4>- Quantization isn't free</h4><p>Almost every edge TOPS figure is an INT8 figure. But models are usually trained in FP32 or FP16, and dropping to INT8 trades accuracy for speed. "Can this chip run INT8?" is the wrong question. "Can <em>my model</em> run INT8 without losing accuracy I care about?" is the right one. Classifiers usually quantize cleanly. Detection can, with effort. Depth, segmentation, pose, transformers, and regression-heavy heads are touchier. A monster INT8 accelerator loses its shine if your model needs FP16 to stay correct.</p><h4>- Post processing eats your gains</h4><p>Detection benchmarks love to hide the tail. The network emitting tensors isn't the finish line. You still owe box decode, confidence filtering, NMS, class filtering, track association, coordinate transforms, and temporal smoothing. On a lot of platforms, inference is accelerated and all of that runs on the CPU. Cut inference from 10 ms to 5 ms and you've saved nothing if postprocessing still burns 8. The product feels total latency, not the slice you optimized.</p><div><hr></div><h4>Benchmark the pipeline, not the part</h4><p>Stop asking how many TOPS. Ask what the sustained, end-to-end p99 latency of your actual workload is. A real answer looks like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oX6N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oX6N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 424w, https://substackcdn.com/image/fetch/$s_!oX6N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 848w, https://substackcdn.com/image/fetch/$s_!oX6N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 1272w, https://substackcdn.com/image/fetch/$s_!oX6N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oX6N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png" width="296" height="369.8680926916221" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1402,&quot;width&quot;:1122,&quot;resizeWidth&quot;:296,&quot;bytes&quot;:1199286,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/205716735?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oX6N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 424w, https://substackcdn.com/image/fetch/$s_!oX6N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 848w, https://substackcdn.com/image/fetch/$s_!oX6N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 1272w, https://substackcdn.com/image/fetch/$s_!oX6N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf882f65-a451-444b-9b5c-83b92471b898_1122x1402.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now the bottleneck is visible, and inference is 11 of 40. Double the accelerator's TOPS and, at best, you shave part of that one slice. You cannot double the application.</p><p>A benchmark worth trusting reports batch-1 latency, p99, power, temperature, dropped frames, CPU utilization, memory-bandwidth pressure, post-quantization accuracy, operator fallback count, and host-device transfer time.</p><p>TOPS is a real number. The inference people draw from it usually isn't. The fastest chip on paper loses, routinely, to a smaller one that keeps data local, maps the whole graph cleanly, avoids CPU fallback, and holds stable latency when it's hot.</p><p>So next time you choice a silicon for your robot, or are perplexed why you are not able to achieve advertised specs, remember this.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.gagandeepreehal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Why TensorRT Is Not Your Biggest Latency Problem]]></title><description><![CDATA[From Camera DMA to Control Commands: Where your milliseconds really go?]]></description><link>https://www.gagandeepreehal.com/p/why-tensorrt-is-not-your-biggest</link><guid isPermaLink="false">https://www.gagandeepreehal.com/p/why-tensorrt-is-not-your-biggest</guid><dc:creator><![CDATA[Gagandeep Reehal]]></dc:creator><pubDate>Sun, 05 Jul 2026 15:04:03 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/edc65c12-461d-4f2a-ac92-80f8995b4e66_1510x941.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A robotics engineer spends a week converting a model to TensorRT - fusing layers, tuning kernels, enabling FP16, maybe running INT8 calibration. The benchmark looks great: inference drops from 20ms to 18ms. They deploy it expecting the robot to feel noticeably sharper.</p><p>It doesn&#8217;t. The robot still reacts late, still misses fast-moving objects, still feels a beat behind in closed-loop operation.</p><p>TensorRT didn&#8217;t fail. Inference was never the biggest latency problem to begin with - it&#8217;s just the only one anyone bothered to measure.</p><p>That&#8217;s the strange thing about robotics perception pipelines in 2026: the neural network is usually the most heavily optimized component in the entire chain, and almost everything around it is still running on default settings from three years ago.</p><p>Here&#8217;s what actually happens between a photon hitting the sensor and a steering command reaching the wheels:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eZhk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eZhk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!eZhk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!eZhk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!eZhk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eZhk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png" width="590" height="295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:590,&quot;bytes&quot;:1283846,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/204516278?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eZhk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 424w, https://substackcdn.com/image/fetch/$s_!eZhk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 848w, https://substackcdn.com/image/fetch/$s_!eZhk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 1272w, https://substackcdn.com/image/fetch/$s_!eZhk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F572209c2-aed4-4ef3-95cb-b9aeb4ebef3f_1774x887.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Most benchmark decks show one box from this chain. The other eleven don&#8217;t make it into the slide.</p><p>Take a real profile - an engineer reports 18ms inference and feels good about it. Then someone times the whole pipeline:</p><pre><code><code>Camera DMA              8 ms
Image decode            4 ms
Color conversion        3 ms
Memory copies           5 ms
Resize &amp; normalize      5 ms
Inference               18 ms
NMS                     7 ms
ROS publish             6 ms
Controller interface    4 ms
------------------------------
Total                   60 ms
</code></code></pre><p>Now the same pipeline after several weeks of TensorRT work:</p><pre><code><code>Camera DMA               8 ms
Image decode             4 ms
Color conversion         3 ms
Memory copies            5 ms
Resize &amp; normalize       5 ms
Inference                16 ms
NMS                      7 ms
ROS publish              6 ms
Controller interface     4 ms
--------------------------------------------
Total                    58 ms
</code></code></pre><p>Two milliseconds saved, on a pipeline that&#8217;s still burning over 40ms on everything that <em>isn&#8217;t</em> the model. Most of the engineering hours went into the smallest slice of the problem.</p><h4>Why often teams still ignore it?</h4><p>It&#8217;s not carelessness - it&#8217;s tooling. TensorRT ships with profilers. CUDA has timelines. Every framework spits out an inference number, and every paper leads with one. The rest of the pipeline is scattered across drivers, middleware, the OS scheduler, and hardware interfaces that were never built to be measured together. Getting an honest end-to-end number means stitching timestamps across four or five layers of the stack by hand, and almost nobody does that work.</p><p>So teams optimize what they can see. It&#8217;s a completely rational response to bad visibility - it&#8217;s just optimizing the wrong thing.</p><h4>- Memory copies are where a lot of latency hides.</h4><p>One of the least glamorous parts of a perception pipeline is how many times an image gets copied before the GPU ever sees it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SkSr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SkSr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 424w, https://substackcdn.com/image/fetch/$s_!SkSr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 848w, https://substackcdn.com/image/fetch/$s_!SkSr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 1272w, https://substackcdn.com/image/fetch/$s_!SkSr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SkSr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png" width="1456" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1425767,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/204516278?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SkSr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 424w, https://substackcdn.com/image/fetch/$s_!SkSr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 848w, https://substackcdn.com/image/fetch/$s_!SkSr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 1272w, https://substackcdn.com/image/fetch/$s_!SkSr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbde71f5-6d69-4c5b-b625-0d515ee11ab3_2172x724.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Every hop costs time and bandwidth, and none of it improves the prediction by a single percentage point. I&#8217;ve seen teams cut more latency by removing one unnecessary copy than by dropping from FP32 to FP16 - and that fix never shows up in a conference talk, because there&#8217;s no leaderboard for &#8220;deleted a memcpy.&#8221;</p><h4>- Cameras aren&#8217;t really instant.</h4><p>&#8220;Camera latency&#8221; gets treated as basically zero, which is wrong. Sensor exposure, readout, DMA transfer, driver buffering, synchronization - all of that happens before a single pixel reaches software. If exposure alone costs 10ms, no amount of TensorRT tuning gets those milliseconds back. You can&#8217;t infer on pixels that haven&#8217;t arrived yet.</p><p>Preprocessing eats time too - resizing, RGB conversion, normalization, undistortion, stereo rectification. None of it touches the model, all of it happens before the model runs, and on a lot of setups the GPU actually finishes inference before the CPU has fed it the next frame. Utilization looks low and everyone blames the model, when the model&#8217;s been sitting idle waiting on preprocessing the whole time.</p><h4>- Middleware and the scheduler take a major cut.</h4><p>Most robotics stacks aren&#8217;t one process - messages get serialized, copied, queued, deserialized, and rescheduled as they move through ROS or DDS. Each hop is a few milliseconds. Six here, four there, a context switch somewhere else, and the robot is reacting 30ms later than the raw compute numbers would suggest. No amount of model optimization touches any of that.</p><p>The OS scheduler adds its own tax. Perception finishes a frame, but the controller doesn&#8217;t necessarily run next - logging might be flushing, a background thread might wake up, a network interrupt might steal a few cycles. Average latency barely moves, but worst-case latency can blow out badly. And for a physical robot, worst case usually matters more than average: a car that responds in 20ms most of the time but occasionally stalls for 80ms is more dangerous than one that&#8217;s a steady, boring 40ms every time. Determinism beats raw speed.</p><p>Even after perception is done, the command still has to pass through safety checks, interface layers, the CAN bus, motor controllers, and firmware before anything physically moves. The robot is always acting on slightly stale information - the only question is how stale.</p><h4>How should one approach benchmarking?</h4><p>Instead of asking &#8220;<em>how fast is our model?&#8221;</em>, the better question to ask us is &#8220;<em>how old is the information by the time the actuator receives it?&#8221;</em></p><p>That single number - call it perception-to-action latency - captures camera time, preprocessing, inference, middleware, scheduling, planning, and control all at once. It&#8217;s what the robot actually experiences. The robot has no idea whether 20ms disappeared inside TensorRT or inside a memcpy; it only knows when the command arrived.</p><p>The most useful exercise I&#8217;ve found is building a real waterfall chart per frame:</p><pre><code><code>Camera Exposure        &#9608;&#9608;
DMA                    &#9608;&#9608;&#9608;
Decode                 &#9608;&#9608;
Color Conversion       &#9608;
Memory Copies          &#9608;&#9608;
Preprocessing          &#9608;&#9608;
Inference              &#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;
Post-processing        &#9608;&#9608;&#9608;
ROS/DDS                &#9608;&#9608;
Planning               &#9608;&#9608;&#9608;
Controller             &#9608;&#9608;
</code></code></pre><p>Once you actually look at the full bar, it&#8217;s obvious where the effort should go. Sometimes it really is the model. More often, it isn&#8217;t.</p><p>TensorRT is genuinely excellent engineering - but its own visibility has created a blind spot. Because inference is the easiest thing to profile, it becomes the thing everyone obsesses over, while camera pipelines, memory movement, scheduling, and controller interfaces quietly eat the rest of the budget with nobody watching.</p><p>The fastest robots don&#8217;t come from the teams with the fastest models. They come from the teams that&#8217;ve bothered to account for every millisecond between the sensor and the actuator.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.gagandeepreehal.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Your Robot Is Fine. Your Data Infrastructure Isn't]]></title><description><![CDATA[The bug that doesn't look like a bug - until you've lost six months, and the unglamorous work which determines whether your robot ships]]></description><link>https://www.gagandeepreehal.com/p/your-robot-is-fine-your-data-infrastructure</link><guid isPermaLink="false">https://www.gagandeepreehal.com/p/your-robot-is-fine-your-data-infrastructure</guid><dc:creator><![CDATA[Gagandeep Reehal]]></dc:creator><pubDate>Tue, 30 Jun 2026 12:44:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/33b87be8-86c9-458c-896c-bb24458663ed_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After spending 5 years building foundational models for autonomous driving at Minus Zero, I learnt all this a hard way - because this was never the coolest thing to talk about.</p><p>Ask a senior engineer at Waymo, Tesla, or any Physical AI startup how they actually spend their time. The answer never matches the conference talks.</p><p>Control algorithms, perception architectures, planning systems - these are what get written about, presented, and funded. They&#8217;re maybe 15&#8211;20% of where engineering hours actually go. The rest disappears into data collection, labeling pipelines, dataset versioning, calibration tracking, validation scripts, evaluation infrastructure, and debugging corruptions that produce no error messages whatsoever.</p><p>Nobody talks about this at NeurIPS. It&#8217;s not glamorous. But it&#8217;s where the work is.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Ad9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Ad9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 424w, https://substackcdn.com/image/fetch/$s_!6Ad9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 848w, https://substackcdn.com/image/fetch/$s_!6Ad9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 1272w, https://substackcdn.com/image/fetch/$s_!6Ad9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Ad9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png" width="480" height="599.7860962566845" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1402,&quot;width&quot;:1122,&quot;resizeWidth&quot;:480,&quot;bytes&quot;:2170305,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/203547783?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6Ad9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 424w, https://substackcdn.com/image/fetch/$s_!6Ad9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 848w, https://substackcdn.com/image/fetch/$s_!6Ad9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 1272w, https://substackcdn.com/image/fetch/$s_!6Ad9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64f0ca7b-7788-4f13-89f5-bfdb921ba35e_1122x1402.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>How complicated it can be?</h2><p>To appreciate the hidden complexity, follow a single camera frame from capture to its eventual use in a training run six months later.</p><p>If you already know this, feel free to skip to the next section : ) </p><pre><code><code>&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
PHYSICAL LAYER
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
1.  Image sensor captures photons (1/30 second exposure)
2.  Image Signal Processor: demosaicing, white balance, noise reduction
3.  Hardware timestamp generated by camera's internal oscillator
    &#9888; NOTE: This clock is NOT the system clock. It drifts 1&#8211;5ppm.
4.  Frame transmitted over GigE Vision to compute unit
5.  OS receives frame, applies software timestamp
    &#9888; NOTE: This is a SECOND timestamp. The two will diverge.
6.  DMA copy into shared memory ring buffer

MIDDLEWARE LAYER
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
7.  ROS 2 node reads frame, wraps in sensor_msgs/Image
8.  Publishes to /camera/front_left/image_raw (~1MB per frame)
9.  Subscribers: perception node, recorder node, visualization node
10. Three independent subscribers receive the same message.
    &#9888; Each applies processing with unknown latency jitter.

RECORDING LAYER
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
11. Recorder serializes to MCAP format with LZ4 compression
12. Writes to local NVMe in 30-second segments
13. Session metadata: robot_id, session_id, operator, timestamp range
14. Segment complete &#8594; MD5 checksum computed on in-memory buffer
    &#9888; NOTE: If the NVMe has a bad sector, the write is "successful"
    but the data is corrupted. The checksum passes.
15. Segment pushed to upload queue

SENSOR FUSION ASSOCIATION
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
16. LiDAR arriving at 10Hz (different oscillator, different clock)
17. IMU at 200Hz (yet another clock)
18. GPS at 10Hz (UTC-synchronized via PPS signal &#8212; most accurate)
19. To fuse: what was the robot's pose at this exact camera timestamp?
    &#9888; Requires sub-10ms alignment. Uncompensated drift &#8594; wrong geometry.
20. Calibration lookup: where is this camera relative to LiDAR?
    &#9888; Is the calibration from this session? Or last week's? Did it drift?
    &#9888; Calibration changes with temperature. No one tracked today's temp.

UPLOAD AND INGEST
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
21. Upload to object storage via chunked multipart upload
22. Upload job written to message queue (Kafka / SQS)
23. Ingest service parses MCAP, extracts metadata
24. Frame indexed: timestamp_ns, robot_id, session_id,
    scenario_type, GPS_bbox, weather_tag, calibration_id
    &#9888; NOTE: "weather_tag" was added to the schema in month 4.
    &#9888; All frames before month 4 have NULL weather_tag.
    &#9888; Training code does not handle NULL. Silent filter removes 40%
    &#9888; of your data and you don't notice.

VALIDATION PIPELINE
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
25. Timestamp monotonicity check             [PASS]
26. Frame drop detection (&gt;1% gap rate)      [PASS]
27. Calibration validity check               [FAIL &#8212; 3 frames]
    &#9888; Clock stutter caused those 3 frames to fall outside
    &#9888; the calibration validity window. Flagged for review.
28. Brightness range check                   [PASS]
29. Compression integrity check              [PASS &#8212; does not catch
    &#9888; bad-sector corruption, because checksum was wrong]

LABELING
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
30. Frame sampled for annotation (diversity heuristics)
31. Sent to annotation pipeline: objects, lanes, drivable area
32. Human annotation: ~8 minutes per frame
33. QA review by senior annotator
34. Labels written to database with annotator_id, QA_status
35. Labels joined to frame via (robot_id, timestamp_ns)
    &#9888; NOTE: Labeling team changed in month 6.
    &#9888; New team uses slightly different bounding box convention.
    &#9888; Mixed conventions now exist in the training set.

DATASET VERSIONING
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
36. Frame added to dataset v3.7.2 manifest
37. Train/val/test split assigned
    &#9888; Split is by session_id, not frame. Mostly prevents leakage.
    &#9888; But the robot drove the same route twice in different sessions.
    &#9888; Similar frames appear in both train and test.
38. Dataset committed to DVC remote with git hash

TRAINING
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
39. Training job: 64 A100s, dataset v3.7.2
40. Frame decoded, augmented, normalized
41. Forward pass. Gradient. Weight update.
    &#9888; The bad-sector-corrupted frame was included.
    &#9888; So were the frames with wrong bounding box convention.
    &#9888; So were the test-set-leaked frames.
    &#9888; The model trains successfully.

EVALUATION AND REGRESSION
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
42. mAP computed per class, per condition
43. Regression detected: pedestrian mAP dropped 2.3% in construction zones
44. Root cause hunt: Is it the model? The data? A labeling issue?
    &#9888; Debugging this takes 3 engineer-weeks.
    &#9888; The answer: bad-sector corruption + mixed bounding box convention
    &#9888; + 40% data loss from NULL weather_tag filter.
    &#9888; None of these produced a single error message.

SIX MONTHS LATER
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
45. Engineer queries data lake for construction zone, night, rain frames
46. Returns 8,000 results
47. 340 have corrupted calibration (calibration service bug in month 2)
48. 200 have labels from deprecated tool with different class definitions
49. Engineer spends 3 days reconstructing which frames are usable
50. Eventual usable frames: ~7,460 of 8,000 &#8212; but which 7,460?
    &#9888; No provenance trail. Must re-validate manually.
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
TOTAL TIME FROM CAPTURE TO USABLE TRAINING EXAMPLE: 6 months.
TOTAL ENGINEERING-DAYS LOST TO DATA ISSUES: ~20.
TOTAL ERROR MESSAGES PRODUCED BY ANY OF THESE ISSUES: 0.
&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;&#9552;
</code></code></pre><p>This isn&#8217;t a pathological story. This is Tuesday at a typical robotics startup.</p><div><hr></div><h2>So what poses as a problem?</h2><p>These are the data problems that don&#8217;t produce stack traces. They produce <em>models that fail in production</em> in ways that take months to diagnose.</p><ul><li><p><strong>Timestamp Drift -</strong> Camera hardware oscillators drift by 1&#8211;5 parts per million. After a 4-hour collection session, a sensor running at 2ppm drift is 29ms off from the system clock. During sensor fusion, your perception stack associates a LiDAR point cloud (captured at time T) with a camera frame (nominally at T, actually at T+29ms). At highway speeds (30 m/s), 29ms represents 87 centimeters of vehicle motion. You are training your model with a point cloud that doesn&#8217;t correspond to the image it thinks it does. This doesn&#8217;t crash anything. It silently corrupts your 3D bounding box training data, slightly but persistently - across every hour of data collected with that sensor.</p><p></p></li><li><p><strong>Schema Drift -</strong> You add a field to your custom protobuf message definition. You&#8217;re careful: it&#8217;s an optional field, backward compatible. But your MCAP recording tool hashes the message schema to identify the message type. Old bags reference the old hash. Your replay tool, written for the new schema, can&#8217;t find the message definition for the old hash. Three months of bags are now unreadable without a migration script. The migration script takes two weeks to write and test properly. During those two weeks, you discover that 4% of your bags also have a related issue with the companion metadata schema.</p><p></p></li><li><p><strong>Silent Disk Corruption -</strong> A frame is written to disk. The NVMe drive has a developing bad sector. The OS reports the write as successful. The checksum was computed on the in-memory buffer <em>before</em> the write. The corrupted frame sits on disk, looking exactly like a valid image, producing subtle artifacts that a labeler annotates as object detections. You&#8217;ve injected structured noise into your training set.</p><p></p></li><li><p><strong>Benchmark Leakage -</strong> Your evaluation set is sampled from the same routes as your training set, just at different timestamps. A rare sign type appears in both training and evaluation because you drove past it every morning during data collection. Your per-class mAP on that sign type looks excellent. Your production system fails at a different intersection with the same sign type, because it memorized the specific instance rather than the class.</p><p></p></li><li><p><strong>Calibration Drift -</strong> Camera intrinsics shift with temperature. LiDAR-camera extrinsic calibration can change after a minor collision that leaves no visible damage. If calibration is recorded once weekly, every datum collected between calibration sessions is tagged with potentially incorrect geometry. Models trained on this data learn the wrong spatial relationships - consistently, invisibly.</p><p></p></li><li><p><strong>Label Inconsistency -</strong> Labeling vendor A annotates occluded pedestrians with a <code>partially_visible</code> flag. Labeling vendor B, hired when the first vendor couldn&#8217;t scale, annotates only fully visible pedestrians. You merge their outputs without reconciling the conventions. Your model now receives the same visual stimulus with different ground truth depending on which batch the frame came from. You&#8217;ve permanently injected irreducible label noise.</p><p></p></li><li><p><strong>Duplicate Data -</strong> A recorder bug causes 2% of sessions to be written twice under different session IDs. Your training set contains tens of thousands of effectively duplicated frames. The model overfits to these examples. Evaluation performance looks inflated - the test set also contains duplicates. The effect is invisible until you deploy to a new environment and the model catastrophically fails on distributions it&#8217;s never actually generalized to.</p><p></p><p>None of these produce error messages. They produce models with mysterious behavior, regressions that can&#8217;t be explained, and debugging sessions that last months.</p></li></ul><div><hr></div><h2>Physical AI is in its Pre-Git Era</h2><p>Consider where software engineering was in 1990. Code on network drives. No version history. &#8220;Works on my machine&#8221; was an acceptable bug report. Reproducing a build meant manually reconstructing the environment. Merging two developers&#8217; work meant emailing patches.</p><p>That&#8217;s where robotics data is today.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vSny!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vSny!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 424w, https://substackcdn.com/image/fetch/$s_!vSny!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 848w, https://substackcdn.com/image/fetch/$s_!vSny!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 1272w, https://substackcdn.com/image/fetch/$s_!vSny!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vSny!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png" width="1456" height="904" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:904,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1302518,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/203547783?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vSny!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 424w, https://substackcdn.com/image/fetch/$s_!vSny!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 848w, https://substackcdn.com/image/fetch/$s_!vSny!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 1272w, https://substackcdn.com/image/fetch/$s_!vSny!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2192eabb-1512-4ddc-b66a-5001d6b1970c_1592x988.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Datasets live on shared NFS mounts without versioning. There&#8217;s no history of which data produced which model. Training runs aren&#8217;t reproducible because no one tracked which files were actually used. &#8220;The model trained on my workstation&#8221; is common. Merging two teams&#8217; datasets means copying files and hoping for no conflicts.</p><p>The ML world partially solved this for static image data. Weights &amp; Biases tracks experiments. DVC versions datasets. Hugging Face hosts models. But these tools were built for static datasets of labeled images or tabular rows. They don&#8217;t understand time-synchronized multi-modal sensor streams, calibration dependencies, coordinate frame transforms, or the need to replay a scenario to debug a failure. They&#8217;re the right shape of solution applied to the wrong problem structure.</p><p>Robotics needs purpose-built tooling. Not a reskin of MLflow. Something designed around what embodied physical data actually is.</p><p>MCAP - developed by Foxglove, now the default format in ROS 2 - is a good start: self-contained, corruption-resistant, schema-embedded, multi-language. But MCAP solves the storage format. It doesn&#8217;t solve versioning, provenance, calibration tracking, scenario search, or continuous evaluation. We have one good brick. The building doesn&#8217;t exist yet.</p><div><hr></div><h2>Why Foundation Models Make This Worse?</h2><p>There&#8217;s a seductive belief that as models scale and become more capable, messy data becomes less of a problem - the model will figure it out. This is exactly backwards.</p><p>Physical Intelligence&#8217;s &#960;0 is trained on data from seven different robot hardware platforms, across eight task types, mixed with internet-scale vision-language pretraining. The hard work isn&#8217;t the architecture - &#960;0 builds on existing VLM foundations. The hard work is making data coherent across robot morphologies with different action spaces, different observation definitions, and different physical constraints. That is not a modeling problem. It is a data harmonization problem that precedes any modeling work.</p><p>Waymo&#8217;s recent scaling law research puts a sharper point on it. Their finding: for autonomous driving tasks, unlike language models, optimal systems tend to be &#8220;relatively smaller in size, while requiring significantly more data to train.&#8221; More data is the path to better systems - which means more data collection, more data operations, and more quality control, not less.</p><p>Scaling model capacity without scaling data infrastructure doesn&#8217;t plateau gracefully. It fails in ways that look like training instability, unexplained regressions, or evaluation results that don&#8217;t transfer to production. The root cause is usually in the data. The debugging path is usually weeks long.</p><div><hr></div><h2>What the Leaders Actually Built?</h2><p>Tesla&#8217;s data engine - described by Andrej Karpathy at multiple public presentations - is the clearest public acknowledgment that data infrastructure, not model architecture, is the core competitive advantage in autonomous systems.</p><p>Trigger classifiers run on the production fleet, detecting situations where the current model and a candidate model diverge, or where the model&#8217;s output conflicts with the driver&#8217;s behavior. Those triggers route specific clips for annotation and retraining. New models run silently on production vehicles in &#8220;shadow mode&#8221; - outputs compared against the production model, never actually controlling the car. This is a continuous evaluation system running at fleet scale across millions of vehicles. At AI Day 2022, Tesla described datasets on the order of 1.5 petabytes for training their occupancy network alone.</p><p>None of that is model architecture. All of it is data infrastructure.</p><p>Waymo maintains 500,000+ hours of driving data. New software release candidates are automatically evaluated against millions of simulated miles. Their simulation system generates scenarios from real-world logs - which requires log management, scenario indexing, and closed-loop evaluation infrastructure of considerable sophistication. Dedicated teams work on sensor simulation, scenario search, and evaluation tooling. Not just perception and planning.</p><p>Karpathy, at a CVPR workshop, made it plain: &#8220;The only sure certain way I have seen of making progress on any task is, you curate the dataset that is clean and varied and you grow it and you pay the labeling cost.&#8221;</p><p>The algorithm is almost secondary. The machine that creates and validates training data is the real product. The robotics organizations that have achieved meaningful scale haven&#8217;t done it primarily through algorithmic novelty. They&#8217;ve done it by building industrial-grade data operations.</p><div><hr></div><h2>So how does it affect a typical robotics startup trajectory?</h2><ul><li><p><strong>Months 1&#8211;3</strong>: The robot moves. The demo works. The team is energized.</p></li><li><p><strong>Months 4&#8211;6</strong>: A model trains. It works in the lab. Investors are interested.</p></li><li><p><strong>Months 7&#8211;9</strong>: Real-world deployment. Performance degrades. Debug manually. Fix cases individually.</p></li><li><p><strong>Months 10&#8211;12</strong>: Retrain the model with new data. Performance is worse than before. The team doesn&#8217;t know why.</p></li><li><p><strong>Months 13&#8211;18</strong>: A senior engineer joins. She discovers: no dataset versioning, no reproducible training, evaluation set contaminated with training data, calibration not tracked, labeling conventions inconsistent across vendors. Six months of reconstruction work begins.</p></li></ul><p>The reason founders underestimate data operations is that early success doesn&#8217;t require them. Two engineers can build a demo that impresses investors with zero data infrastructure. The failure modes only surface when you need to reproduce a training run, when a calibration change corrupts months of data you didn&#8217;t know was invalid, or when your evaluation set has silently leaked into your training set and you&#8217;ve been measuring the wrong thing for half a year.</p><p>The first dedicated data infrastructure engineer - someone who designs the schema before you have data, builds the validation pipeline before you have regressions, creates the reproducible evaluation framework before you establish a baseline - often has more total leverage than the third ML researcher. The ML researcher improves the current model. The infrastructure engineer makes all future models improvable faster. The second is harder to justify to a board. It&#8217;s more important.</p><div><hr></div><h2>But if we do X then it&#8217;s not a problem?</h2><p><strong>&#8220;Simulation solves the data problem.&#8221;</strong></p><p>Simulation reduces the need for some real-world data collection. It doesn&#8217;t eliminate the data problem - it adds a parallel one. Simulation asset management requires versioning. Domain randomization parameters require tracking. Sim-to-real gap requires characterization against real-world benchmarks. Synthetic data generation pipelines fail in ways that look exactly like real data pipeline failures: schema drift, coverage gaps, distribution mismatch, evaluation leakage. Waymo runs millions of simulated miles per software release candidate. That infrastructure - scenario management, parameter tracking, results storage, regression detection - is a data operations problem of comparable complexity to the real-data problem.</p><p><strong>&#8220;Foundation models trained on internet data will generalize to robotics.&#8221;</strong></p><p>Internet-scale pretraining provides genuine value for visual recognition and language grounding. It doesn&#8217;t help with calibration tracking, multi-modal timestamp synchronization, or the physical geometry of sensor fusion. The &#8220;last mile&#8221; of embodied AI - grounding general knowledge in precise physical sensor data - requires exactly the infrastructure this article describes. Physical Intelligence&#8217;s &#960;0, which makes aggressive use of VLM pretraining, still required building a multi-robot data collection and harmonization infrastructure as the core technical work.</p><p><strong>&#8220;This is just MLOps with extra steps.&#8221;</strong></p><p>MLOps tools were designed for static datasets. Robotics data is time-synchronized, calibration-dependent, multi-modal, spatially grounded, and replay-dependent. Applying MLflow to manage a dataset that includes MCAP files with associated per-session calibration metadata, LiDAR-camera extrinsics, GPS trajectories, and scenario tags reveals immediately that the abstractions don&#8217;t transfer. The tooling gap is real and purpose-built solutions are needed.</p><p><strong>&#8220;Big companies have this problem. Startups should focus on shipping product.&#8221;</strong></p><p>This is precisely backwards. Big companies can absorb three months of debugging a data corruption issue. Startups cannot. The startup that establishes data discipline in months 1&#8211;3 compounds its learning rate for the entire subsequent trajectory. The one that defers it will spend months 12&#8211;18 in reconstruction mode while competitors iterate. Early investment in data infrastructure is not a distraction from building the product - it is the infrastructure on which the product&#8217;s learning rate depends.</p><p><strong>&#8220;Better sensors and hardware will reduce calibration and sync problems.&#8221;</strong></p><p>Better hardware reduces but doesn&#8217;t eliminate calibration drift. More importantly, tracking calibration state over time - associating every data frame with the calibration that was valid at that moment, flagging data when calibration may have changed, managing calibration as a versioned artifact - is not a sensor problem. It&#8217;s a data management problem. Even perfect sensors require a calibration management system.</p><div><hr></div><h2>How should we solve it?</h2><p>DevOps emerged when shipping code without operational discipline stopped scaling. MLOps emerged when deploying models without infrastructure discipline stopped scaling. RobotOps is next - and the path is legible.</p><p>It all starts with changing how we approach a robotics problem - and try giving a serious thought through the &#8216;DevOps for Robotics&#8217; perspective.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JAPy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JAPy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!JAPy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!JAPy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!JAPy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JAPy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1417759,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.gagandeepreehal.com/i/203547783?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JAPy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!JAPy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!JAPy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!JAPy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F903d8fba-e407-4e89-9b7f-42d433629119_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Standardize before you tool up.</strong> MCAP is a good start, but the next step is a robotics dataset format analogous to Parquet - purpose-built for time-synchronized multi-modal sensor data, with versioning and calibration baked in. The community needs to converge on this before every company keeps reinventing it privately. At the team level, this means defining canonical sensor schemas, a timestamp policy (hardware timestamps only, sync mechanism documented), calibration tracking (every file references a calibration session ID with a validity window), and a session metadata standard - written down before you have data. Two weeks of work that saves six months.</p><p><strong>Build the platform layer, not five duct-taped tools.</strong> Early entrants - Foxglove, Rerun, Scale AI, HuggingFace via LeRobot - are solving pieces of the puzzle. The gap is integration: schema management, calibration tracking, dataset lineage, and scenario search in one coherent platform.</p><p><strong>Treat data like code: validate, checksum, test.</strong> Every model commit should automatically validate datasets, check timestamp and calibration integrity, run scenario regression benchmarks, and compare against historical results - the same discipline software teams built into CI/CD two decades ago. In practice, this starts small: checksum every recorded file in-memory before upload and verify after (one engineering-day, catches silent corruption before it reaches training), and run a validation script before every training job - timestamp monotonicity, frame drop rate, calibration validity, label schema compliance, duplicate detection. Fail loudly, automatically.</p><p><strong>Make scenario search the primary interface.</strong> Manual log inspection should be as archaic as grepping server logs. The target: query petabyte-scale sensor archives the way you&#8217;d query a database - by scenario type, condition, failure mode, time window. The scenario library becomes more valuable than any individual model checkpoint. Build your evaluation set first as part of this discipline: sample deliberately, freeze it, version it, never train on it, and store every result against it with model version, dataset version, and timestamp.</p><p><strong>Formalize the discipline and hire for it.</strong> Robot Data Engineer needs to be a real job title with a real career path, not a responsibility absorbed by whoever has bandwidth. Counterintuitively, the first data infrastructure hire often has more leverage than the third ML engineer - and is the recommendation most consistently ignored despite having the highest ROI.</p><p>A better model architecture can be published and reproduced in six months. A decade of well-organized operational data cannot.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.gagandeepreehal.com/p/your-robot-is-fine-your-data-infrastructure?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.gagandeepreehal.com/p/your-robot-is-fine-your-data-infrastructure?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.gagandeepreehal.com/p/your-robot-is-fine-your-data-infrastructure?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h2>References and Resources</h2><p><strong><sup>Foundational Papers</sup></strong></p><ul><li><p><sup>Open X-Embodiment Collaboration (2024). </sup><em><sup>Open X-Embodiment: Robotic Learning Datasets and RT-X Models.</sup></em><sup>ICRA 2024. https://robotics-transformer-x.github.io/</sup></p></li><li><p><sup>Black et al. (Physical Intelligence, 2024). </sup><em><sup>&#960;0: A Vision-Language-Action Flow Model for General Robot Control.</sup></em><sup>https://physicalintelligence.company/download/pi0.pdf</sup></p></li><li><p><sup>Brohan et al. (Google, 2022). </sup><em><sup>RT-1: Robotics Transformer for Real-World Control at Scale.</sup></em><sup> arXiv:2212.06817</sup></p></li><li><p><sup>Chi et al. (TRI / Columbia, 2023). </sup><em><sup>Diffusion Policy: Visuomotor Policy Learning via Action Diffusion.</sup></em><sup>arXiv:2303.04137</sup></p></li><li><p><sup>Sun et al. (Waymo, 2020). </sup><em><sup>Scalability in Perception for Autonomous Driving: Waymo Open Dataset.</sup></em><sup> CVPR 2020.</sup></p></li><li><p><sup>Waymo (2026). </sup><em><sup>Scaling Laws Research: Data-Driven Autonomous Driving.</sup></em><sup>https://datacenterdynamics.com/en/news/waymo-research-confirms-self-driving-scaling-laws/</sup></p></li></ul><p><strong><sup>Engineering Blogs and Talks</sup></strong></p><ul><li><p><sup>Karpathy, A. (Tesla Autonomy Day, 2019). </sup><em><sup>Tesla Data Engine.</sup></em></p></li></ul><div id="youtube2-Ucp0TTmvqOE" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Ucp0TTmvqOE&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/Ucp0TTmvqOE?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><ul><li><p><sup>Karpathy, A. (Tesla AI Day, 2021). </sup><em><sup>Autopilot and Auto-Labeling.</sup></em></p></li></ul><div id="youtube2-j0z4FweCy4M" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;j0z4FweCy4M&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/j0z4FweCy4M?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><ul><li><p><sup>Karpathy, A. (CVPR 2021 Workshop on Autonomous Driving). </sup><em><sup>Lessons learned from deploying neural networks at Tesla.</sup></em></p></li><li><p><sup>Waymo Engineering. </sup><em><sup>Industry Best Practices in Robotics Software Engineering.</sup></em><sup> arXiv:2212.04877</sup></p></li><li><p><sup>Foxglove Blog. </sup><em><sup>Introducing the MCAP File Format.</sup></em><sup> https://foxglove.dev/blog/introducing-the-mcap-file-format</sup></p></li><li><p><sup>Rerun Blog. </sup><em><sup>Introducing Experimental MCAP Support.</sup></em><sup> https://rerun.io/blog/introducing-experimental-support-for-mcap-file-format</sup></p></li><li><p><sup>Segments.ai. </sup><em><sup>MCAP vs ROS bag: Simplifying Multi-Modal Sensor Data.</sup></em><sup> https://segments.ai/blog/mcap-vs-ros-bag-simplifying-multi-modal-sensor-data-in-robotics/</sup></p></li></ul><p><strong><sup>Community and Discussion</sup></strong></p><ul><li><p><sup>ROS Discourse: https://discourse.ros.org/ </sup><em><sup>(Active community discussions on data management, MCAP, and tooling evolution)</sup></em></p></li><li><p><sup>Papers With Code &#8212; Robot Learning: https://paperswithcode.com/task/robot-learning</sup></p></li><li><p><sup>ScenarioNet (open-source scenario management): arXiv:2306.12241</sup></p></li></ul><div><hr></div><p><em><sub>Technical claims in this article about engineering time allocation represent informed analysis based on public statements from industry engineers, published engineering blogs, and the author&#8217;s experience in Physical AI development. Where specific figures are cited (e.g., Waymo&#8217;s 500,000 hours of driving data, Tesla&#8217;s 1.5PB dataset scale), sources are linked above. Claims presented as analysis are clearly identified as such.</sub></em></p><p><em><sub>The argument that data infrastructure determines competitive outcomes in Physical AI is not a prediction about the future. It is an observation about the present, backed by every major organization that has achieved meaningful scale in autonomous systems.</sub></em></p>]]></content:encoded></item></channel></rss>