<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: vmodal_ai</title>
    <description>The latest articles on DEV Community by vmodal_ai (@vmodal_ai).</description>
    <link>https://dev.to/vmodal_ai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4052446%2F2fcb63ba-7be8-4ffd-93ce-f4f00223ddfa.jpeg</url>
      <title>DEV Community: vmodal_ai</title>
      <link>https://dev.to/vmodal_ai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vmodal_ai"/>
    <language>en</language>
    <item>
      <title>Building an Android SDK for Search Inside Video Content</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Tue, 18 Aug 2026 14:03:24 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/building-an-android-sdk-for-search-inside-video-content-1n4o</link>
      <guid>https://dev.to/vmodal_ai/building-an-android-sdk-for-search-inside-video-content-1n4o</guid>
      <description>&lt;p&gt;Searching inside video is usually limited to metadata: titles, descriptions, filenames, tags, or manually added captions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiirof0djypqtdwv2d5dg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiirof0djypqtdwv2d5dg.png" alt=" " width="800" height="804"&gt;&lt;/a&gt;&lt;br&gt;
But what if an Android application could search for something that actually &lt;strong&gt;appears inside the video itself&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Search for "car" → find the moments where a car appears in the video.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This concept explores building a small Android SDK that makes this type of video-content search possible.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Traditional video search often looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Query
    ↓
Video Metadata
    ↓
Title / Description / Tags
    ↓
Search Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works well when the required information exists in the metadata.&lt;/p&gt;

&lt;p&gt;However, metadata doesn't tell you everything that happens inside a video.&lt;/p&gt;

&lt;p&gt;A more powerful approach is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Video
  ↓
Analyze Video Frames
  ↓
Understand Visual Content
  ↓
Create Searchable Data
  ↓
User Query
  ↓
Matching Video Moments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of searching &lt;em&gt;about&lt;/em&gt; the video, we're searching &lt;strong&gt;inside the visual content of the video&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Example
&lt;/h2&gt;

&lt;p&gt;Imagine a 10-minute video containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A person walking&lt;/li&gt;
&lt;li&gt;A car driving past&lt;/li&gt;
&lt;li&gt;A dog running&lt;/li&gt;
&lt;li&gt;A laptop being used&lt;/li&gt;
&lt;li&gt;A person drinking coffee&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A traditional metadata search might only know:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Title: My Daily Vlog
Description: A day in my life
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A visual-content search could potentially return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"car"

00:02:14 → 00:02:21
Car detected

"dog"

00:05:32 → 00:05:41
Dog detected

"laptop"

00:07:10 → 00:07:45
Laptop detected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This transforms a video from a simple media file into a &lt;strong&gt;searchable visual dataset&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Android SDK
&lt;/h2&gt;

&lt;p&gt;The goal of the SDK is to hide the complexity of video processing behind a simple Android API.&lt;/p&gt;

&lt;p&gt;The application developer shouldn't need to implement frame extraction, processing, indexing, and searching themselves.&lt;/p&gt;

&lt;p&gt;Conceptually, the SDK could provide an API similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;video&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VideoSearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;videoUri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"car"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Found at ${it.startTime} - ${it.endTime}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi09cwzt69pbgxty0jchg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi09cwzt69pbgxty0jchg.png" alt=" " width="800" height="807"&gt;&lt;/a&gt;&lt;br&gt;
The exact implementation can vary depending on the computer-vision and AI models being used.&lt;/p&gt;
&lt;h2&gt;
  
  
  How Video Analysis Works
&lt;/h2&gt;

&lt;p&gt;A practical implementation doesn't necessarily need to process every single video frame.&lt;/p&gt;

&lt;p&gt;Instead, the SDK can sample frames at a configurable interval.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Video
─────────────────────────────────────&amp;gt;
  0s     1s     2s     3s     4s
   ↓      ↓      ↓      ↓      ↓
 Frame   Frame  Frame  Frame  Frame
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each selected frame can then be analyzed using an object-detection or vision model.&lt;/p&gt;

&lt;p&gt;The result might look conceptually like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"objects"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"car"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"road"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK can store these results in an index that can later be searched.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Detection to Search
&lt;/h2&gt;

&lt;p&gt;The important part isn't just detecting objects.&lt;/p&gt;

&lt;p&gt;The SDK needs to connect detections with their timestamps.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00:01:10 → person
00:01:12 → person, car
00:01:14 → car
00:01:16 → car
00:01:18 → road
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the user searches for &lt;code&gt;car&lt;/code&gt;, the SDK can combine nearby detections into a meaningful video segment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00:01:12 → 00:01:16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application can then jump directly to that point in the video.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Integration
&lt;/h2&gt;

&lt;p&gt;An Android SDK like this can be integrated into applications such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Video management apps&lt;/li&gt;
&lt;li&gt;Media players&lt;/li&gt;
&lt;li&gt;Surveillance applications&lt;/li&gt;
&lt;li&gt;Educational platforms&lt;/li&gt;
&lt;li&gt;Sports analysis tools&lt;/li&gt;
&lt;li&gt;E-learning applications&lt;/li&gt;
&lt;li&gt;Video libraries&lt;/li&gt;
&lt;li&gt;AI-powered media applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical architecture could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android Application
        │
        ▼
 Video Search SDK
        │
        ├── Video Frame Extraction
        │
        ├── Vision / AI Processing
        │
        ├── Content Index
        │
        └── Search Engine
                │
                ▼
        Matching Video Moments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Important Performance Considerations
&lt;/h2&gt;

&lt;p&gt;Video processing can be expensive on mobile devices.&lt;/p&gt;

&lt;p&gt;Processing every frame of a long video can consume significant CPU, memory, battery, and storage.&lt;/p&gt;

&lt;p&gt;A production SDK therefore needs to consider:&lt;/p&gt;

&lt;h3&gt;
  
  
  Frame Sampling
&lt;/h3&gt;

&lt;p&gt;Instead of analyzing 30 or 60 frames per second, the SDK can analyze selected frames.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background Processing
&lt;/h3&gt;

&lt;p&gt;Analysis should run away from the main Android UI thread so that the application remains responsive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental Processing
&lt;/h3&gt;

&lt;p&gt;Large videos can be processed in chunks instead of loading the entire video into memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local vs Cloud Processing
&lt;/h3&gt;

&lt;p&gt;There are two major approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On-device processing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Video → Android Device → AI Model → Search Index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Advantages include privacy and offline operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud processing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Video → Server → AI Model → Search Index
                    ↓
                 Android
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can provide access to larger models but introduces network requirements and potentially higher processing costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build This as an SDK?
&lt;/h2&gt;

&lt;p&gt;Building this functionality as an SDK makes it reusable.&lt;/p&gt;

&lt;p&gt;Instead of implementing video understanding separately in every application, developers can integrate the SDK and focus on their application's user experience.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Video Search SDK
                           │
          ┌────────────────┼────────────────┐
          ↓                ↓                ↓
     Video Player     Security App     Education App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same underlying video-search capability can support completely different products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Possibilities
&lt;/h2&gt;

&lt;p&gt;Once video content becomes searchable, many interesting features become possible.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search for objects inside videos&lt;/li&gt;
&lt;li&gt;Search for people or activities&lt;/li&gt;
&lt;li&gt;Find specific scenes&lt;/li&gt;
&lt;li&gt;Automatically generate video highlights&lt;/li&gt;
&lt;li&gt;Create searchable video libraries&lt;/li&gt;
&lt;li&gt;Build AI-powered video navigation&lt;/li&gt;
&lt;li&gt;Jump directly to relevant moments&lt;/li&gt;
&lt;li&gt;Combine visual search with speech transcription&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bigger idea is to move from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Search for videos"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Search inside videos."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Android SDK
&lt;/h2&gt;

&lt;p&gt;The Android SDK for this concept is available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/v-modal/vmodal_sdk_android?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;v-modal Android SDK on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project provides a foundation for experimenting with video processing and content-aware functionality on Android.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Video contains far more information than its title, description, and metadata.&lt;/p&gt;

&lt;p&gt;By analyzing the actual visual content of video frames and associating detected content with timestamps, we can turn ordinary videos into &lt;strong&gt;searchable visual experiences&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An Android SDK can make this capability easier to integrate into mobile applications while hiding much of the underlying video-processing complexity.&lt;/p&gt;

&lt;p&gt;The long-term vision is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't just search for the video. Search for what happens inside it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;Website: &lt;a href="http://www.v-modal.com" rel="noopener noreferrer"&gt;www.v-modal.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcclpe2qcobdsolrzbcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffcclpe2qcobdsolrzbcp.png" alt=" " width="800" height="809"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>v</category>
    </item>
    <item>
      <title>Hello,

Concept:

Building a small Android SDK for search inside video content
(inside the real image content , not just metadata),
Android SDK: https://github.com/v-modal/vmodal_sdk_android</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Tue, 18 Aug 2026 13:59:29 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/hello-concept-building-a-small-android-sdk-for-search-inside-video-content-inside-the-11mc</link>
      <guid>https://dev.to/vmodal_ai/hello-concept-building-a-small-android-sdk-for-search-inside-video-content-inside-the-11mc</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://github.com/v-modal/vmodal_sdk_android" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2Fb0af8083e98e45556f7dac838cb0c6c6fdd78ab3bab635fb4a241b4f90a498fb%2Fv-modal%2Fvmodal_sdk_android" height="600" class="m-0" width="1200"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer" class="c-link"&gt;
            GitHub - v-modal/vmodal_sdk_android: Video Search SDK for Android Kotlin. Integrate in any video app · GitHub
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Video Search SDK for Android Kotlin. Integrate in any video app - v-modal/vmodal_sdk_android
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.githubassets.com%2Ffavicons%2Ffavicon.svg" width="32" height="32"&gt;
          github.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Object Detection on Android for Autonomous Robots</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:36:47 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/object-detection-on-android-for-autonomous-robots-5hf0</link>
      <guid>https://dev.to/vmodal_ai/object-detection-on-android-for-autonomous-robots-5hf0</guid>
      <description>&lt;h1&gt;
  
  
  Object Detection on Android for Autonomous Robots
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Autonomous robots need to recognize objects in their environment. Object detection can identify people, vehicles, tools, signs, and obstacles from camera frames.&lt;/p&gt;

&lt;p&gt;Android can perform edge inference locally, reducing dependency on network connectivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CameraX
   |
Preprocessing
   |
Object Detection Model
   |
Postprocessing
   |
Detection Results
   |
Robot Perception Gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Detection Model
&lt;/h2&gt;

&lt;p&gt;Define a reusable result type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Detection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the rest of the application independent from a particular model runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  CameraX Analysis
&lt;/h2&gt;

&lt;p&gt;The camera analyzer should process frames asynchronously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;imageAnalysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAnalyzer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a latest-frame strategy when real-time responsiveness is more important than processing every frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model Runtime
&lt;/h2&gt;

&lt;p&gt;The detector can be implemented behind an interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ObjectDetector&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ImageFrame&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Detection&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible mobile inference approaches include TensorFlow Lite or ONNX Runtime, depending on the model and deployment requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confidence Filtering
&lt;/h2&gt;

&lt;p&gt;Not every prediction should be passed to the navigation system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;valid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.6f&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The threshold should be evaluated against the target environment rather than chosen arbitrarily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non-Maximum Suppression
&lt;/h2&gt;

&lt;p&gt;Detection models may produce overlapping predictions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Prediction A  ───────
Prediction B    ───────
        ↓
       NMS
        ↓
Single Detection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the postprocessing method expected by your selected model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot Integration
&lt;/h2&gt;

&lt;p&gt;The Android device can send detections to the robot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bbox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For autonomous navigation, the robot should combine this with physical measurements such as depth or LiDAR when distance matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking
&lt;/h2&gt;

&lt;p&gt;Instead of detecting every object from scratch at every stage, an additional tracking layer can maintain object identities between frames.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Detection
   ↓
Tracking
   ↓
Object ID
   ↓
Navigation / Behavior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tracking can reduce redundant processing and provide temporal context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization
&lt;/h2&gt;

&lt;p&gt;Important optimization techniques include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use an appropriately sized model&lt;/li&gt;
&lt;li&gt;Reduce input resolution when acceptable&lt;/li&gt;
&lt;li&gt;Reuse buffers&lt;/li&gt;
&lt;li&gt;Avoid bitmap copies&lt;/li&gt;
&lt;li&gt;Run inference off the main thread&lt;/li&gt;
&lt;li&gt;Drop stale frames&lt;/li&gt;
&lt;li&gt;Measure end-to-end latency&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Autonomous Decision Making
&lt;/h2&gt;

&lt;p&gt;Keep AI perception separate from robot control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera
  ↓
Object Detection
  ↓
Perception State
  ↓
Navigation / Behavior
  ↓
Safety Controller
  ↓
Robot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation makes the system easier to test and safer to operate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Evaluate the system using representative scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static objects&lt;/li&gt;
&lt;li&gt;Moving people&lt;/li&gt;
&lt;li&gt;Multiple objects&lt;/li&gt;
&lt;li&gt;Low light&lt;/li&gt;
&lt;li&gt;Bright light&lt;/li&gt;
&lt;li&gt;Partial occlusion&lt;/li&gt;
&lt;li&gt;Camera vibration&lt;/li&gt;
&lt;li&gt;Device thermal throttling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Measure both detection accuracy and real-time performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Object detection on Android can provide useful edge perception for autonomous robots. Kotlin, CameraX, and a mobile inference runtime create a flexible foundation that can later be connected to ROS 2, sensor fusion, navigation, and Physical AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>ai</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Building a Voice-Controlled Robot with Kotlin and LLMs</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:36:38 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/building-a-voice-controlled-robot-with-kotlin-and-llms-4mn0</link>
      <guid>https://dev.to/vmodal_ai/building-a-voice-controlled-robot-with-kotlin-and-llms-4mn0</guid>
      <description>&lt;h1&gt;
  
  
  Building a Voice-Controlled Robot with Kotlin and LLMs
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Natural-language interfaces can make robots easier to operate. Instead of selecting individual buttons, an operator can say commands such as asking a robot to move, inspect an area, or report its status.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will design an Android application that captures speech, sends the text through an LLM-based command parser, and converts the result into validated robot actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Voice
    ↓
Android Speech Recognition
    ↓
Command Text
    ↓
LLM Intent Parser
    ↓
Structured Robot Command
    ↓
Safety Validator
    ↓
Robot Gateway
    ↓
ROS 2 / Robot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM should not directly control motors. It should produce structured intent that a deterministic safety layer validates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Voice Input
&lt;/h2&gt;

&lt;p&gt;Android provides speech-recognition APIs that can be used to convert spoken commands into text.&lt;/p&gt;

&lt;p&gt;A simplified flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onSpeechResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ViewModel can then pass the text to the command-processing layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command Model
&lt;/h2&gt;

&lt;p&gt;Define a strict command structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Stop&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;

    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;distanceMeters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;

    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;degrees&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a structured representation prevents the robotics layer from receiving arbitrary natural-language instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM Intent Parsing
&lt;/h2&gt;

&lt;p&gt;The LLM can transform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Move forward two meters"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into structured data such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"move"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"forward"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"distance_meters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use structured output or a schema-constrained response where the selected LLM/API supports it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation Layer
&lt;/h2&gt;

&lt;p&gt;Never send the LLM result directly to the robot.&lt;/p&gt;

&lt;p&gt;Validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM Output
    ↓
Schema Validation
    ↓
Range Validation
    ↓
Robot State Check
    ↓
Safety Policy
    ↓
Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Stop&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Move&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distanceMeters&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;
        &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;RobotCommand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rotate&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;degrees&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;180.0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mf"&gt;180.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact limits should be determined by the robot's capabilities and safety requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot Gateway
&lt;/h2&gt;

&lt;p&gt;After validation, the Android app sends a structured command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"move"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"forward"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"distanceMeters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gateway converts this command into the appropriate ROS 2 service, action, or topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot Feedback
&lt;/h2&gt;

&lt;p&gt;The robot should return status information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"executing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"battery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.3&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Android application can show this in a Compose dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Ambiguous Commands
&lt;/h2&gt;

&lt;p&gt;Natural language can be ambiguous.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Go over there."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system should not guess what "there" means.&lt;/p&gt;

&lt;p&gt;Instead, the application can request clarification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"I need a destination before I can move the robot."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially important for physical actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice + Vision
&lt;/h2&gt;

&lt;p&gt;The system becomes more powerful when voice and vision are combined.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User:
"Follow the person wearing a red shirt."

Voice → Intent
Vision → Person Detection
       ↓
Robot Navigation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM can coordinate high-level intent while deterministic robotics components handle perception and navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offline and Cloud Options
&lt;/h2&gt;

&lt;p&gt;Speech recognition and LLM inference can be deployed in different ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android
  |
  +-- Local speech recognition
  |
  +-- Cloud LLM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android
  |
Local/Edge AI
  |
Robot / Jetson
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose the architecture based on latency, privacy, connectivity, and hardware constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety Architecture
&lt;/h2&gt;

&lt;p&gt;A recommended control hierarchy is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Natural Language
       ↓
LLM
       ↓
Structured Intent
       ↓
Deterministic Planner
       ↓
Safety Controller
       ↓
Robot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM should remain outside the final safety-critical control loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Test commands using a simulated robot before physical deployment.&lt;/p&gt;

&lt;p&gt;Include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Valid commands&lt;/li&gt;
&lt;li&gt;Invalid commands&lt;/li&gt;
&lt;li&gt;Ambiguous commands&lt;/li&gt;
&lt;li&gt;Extreme values&lt;/li&gt;
&lt;li&gt;Network failures&lt;/li&gt;
&lt;li&gt;LLM failures&lt;/li&gt;
&lt;li&gt;Speech-recognition errors&lt;/li&gt;
&lt;li&gt;Emergency stop&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Combining Android, Kotlin, speech recognition, LLMs, and robotics creates a natural interface for Physical AI systems. The key design principle is to use AI for interpretation and high-level planning while deterministic software remains responsible for validation and safe physical execution.&lt;/p&gt;

&lt;p&gt;This architecture can be extended toward multimodal robot agents that combine voice, vision, maps, sensors, and autonomous task planning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>llm</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Android + NVIDIA Jetson + ROS 2: Building an AI Robot</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:36:31 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/android-nvidia-jetson-ros-2-building-an-ai-robot-1jjd</link>
      <guid>https://dev.to/vmodal_ai/android-nvidia-jetson-ros-2-building-an-ai-robot-1jjd</guid>
      <description>&lt;h1&gt;
  
  
  Android + NVIDIA Jetson + ROS 2: Building an AI Robot
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A practical Physical AI system often separates the user interface, AI compute, robotics middleware, and hardware control.&lt;/p&gt;

&lt;p&gt;In this architecture, Android provides the operator interface, an NVIDIA Jetson provides edge AI compute, and ROS 2 coordinates robotics workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Android / Kotlin
                    |
             Secure Gateway
                    |
                  ROS 2
             /      |              Vision     Nav       Control
          |
    NVIDIA Jetson
          |
     AI Inference
          |
    Robot Sensors
          |
     Robot Hardware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation makes it possible to upgrade individual components without rebuilding the entire system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Application
&lt;/h2&gt;

&lt;p&gt;The Android application can provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Robot connection status&lt;/li&gt;
&lt;li&gt;Camera stream&lt;/li&gt;
&lt;li&gt;AI detections&lt;/li&gt;
&lt;li&gt;Battery information&lt;/li&gt;
&lt;li&gt;Navigation controls&lt;/li&gt;
&lt;li&gt;Emergency stop&lt;/li&gt;
&lt;li&gt;Robot diagnostics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use Jetpack Compose to build the operator interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jetson AI Computer
&lt;/h2&gt;

&lt;p&gt;The Jetson can run computationally intensive workloads such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Object detection&lt;/li&gt;
&lt;li&gt;Object tracking&lt;/li&gt;
&lt;li&gt;Depth estimation&lt;/li&gt;
&lt;li&gt;Visual SLAM&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;Sensor fusion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Android device does not need to perform every AI operation itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  ROS 2 Layer
&lt;/h2&gt;

&lt;p&gt;ROS 2 provides communication between robotics components.&lt;/p&gt;

&lt;p&gt;A possible topic layout is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cmd_vel
/odom
/scan
/camera/image
/detections
/battery_state
/robot_status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the topic structure small and intentional for the mobile interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android-to-ROS Gateway
&lt;/h2&gt;

&lt;p&gt;Rather than making Android responsible for ROS 2 internals, use a gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android
   |
WebSocket / MQTT / ROS bridge
   |
ROS 2 Gateway
   |
ROS 2 Nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gateway can authenticate clients, validate commands, and expose only approved functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Perception Pipeline
&lt;/h2&gt;

&lt;p&gt;The Jetson can process camera frames:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera
   ↓
ROS 2 Image Topic
   ↓
Jetson AI Node
   ↓
Detection / Tracking
   ↓
ROS 2 Detection Topic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Android app can subscribe to summarized results rather than receiving raw sensor data when bandwidth is limited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Dashboard
&lt;/h2&gt;

&lt;p&gt;The dashboard can display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robot: ONLINE
Battery: 87%
Mode: AUTONOMOUS
Objects: 4
Position: X 2.3 / Y 4.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compose state can be backed by Kotlin &lt;code&gt;StateFlow&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command Flow
&lt;/h2&gt;

&lt;p&gt;For manual control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android
   ↓
Velocity Command
   ↓
Gateway
   ↓
ROS 2
   ↓
Safety Controller
   ↓
Robot Base
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The safety controller should remain authoritative over the physical robot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autonomous Mode
&lt;/h2&gt;

&lt;p&gt;For autonomous operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sensors
   ↓
Jetson Perception
   ↓
Localization
   ↓
Navigation
   ↓
Safety Controller
   ↓
Robot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Android becomes a monitoring and supervisory interface rather than the primary controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;A production system should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Device authentication&lt;/li&gt;
&lt;li&gt;Encrypted communication&lt;/li&gt;
&lt;li&gt;Command authorization&lt;/li&gt;
&lt;li&gt;Network segmentation&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Robot-side safety limits&lt;/li&gt;
&lt;li&gt;Emergency stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never assume that a mobile application being inside the same Wi-Fi network makes the robot network trusted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Use simulation before deploying to hardware.&lt;/p&gt;

&lt;p&gt;Validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ROS 2 topic communication&lt;/li&gt;
&lt;li&gt;AI inference&lt;/li&gt;
&lt;li&gt;Android connectivity&lt;/li&gt;
&lt;li&gt;Command timeouts&lt;/li&gt;
&lt;li&gt;Network interruptions&lt;/li&gt;
&lt;li&gt;Camera streaming&lt;/li&gt;
&lt;li&gt;Safety behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scaling to Robot Fleets
&lt;/h2&gt;

&lt;p&gt;The same architecture can support multiple robots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android
   |
Fleet Gateway
   |
+--+---------+---------+
|            |         |
Robot 01   Robot 02  Robot 03
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each robot can expose a controlled namespace and telemetry stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Android, NVIDIA Jetson, and ROS 2 form a strong architecture for Physical AI applications. Android handles human interaction, Jetson handles demanding edge AI workloads, and ROS 2 coordinates perception, navigation, and control.&lt;/p&gt;

&lt;p&gt;This architecture can later be extended with LLM-based planning, voice interaction, computer vision, and autonomous task execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>jetson</category>
      <category>ros2</category>
    </item>
    <item>
      <title>Android Computer Vision for Robot Navigation</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:36:24 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/android-computer-vision-for-robot-navigation-98n</link>
      <guid>https://dev.to/vmodal_ai/android-computer-vision-for-robot-navigation-98n</guid>
      <description>&lt;h1&gt;
  
  
  Android Computer Vision for Robot Navigation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Navigation requires a robot to understand its surroundings. Cameras can provide useful visual information such as obstacles, landmarks, people, road boundaries, and navigable regions.&lt;/p&gt;

&lt;p&gt;Android devices provide cameras and on-device compute that can be used for robotics prototypes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android Camera
     |
 CameraX
     |
 Image Processing
     |
 Vision Model
     |
 Navigation Features
     |
 Robot Gateway / ROS 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Android device should provide perception data while the robot's navigation stack remains responsible for safe movement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera Pipeline
&lt;/h2&gt;

&lt;p&gt;Use CameraX ImageAnalysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;imageAnalysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAnalyzer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Convert frame&lt;/span&gt;
    &lt;span class="c1"&gt;// Process image&lt;/span&gt;
    &lt;span class="c1"&gt;// Produce navigation features&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never perform expensive image processing on the UI thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation Features
&lt;/h2&gt;

&lt;p&gt;Computer vision can produce information such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Obstacle detected
Free-space region
Person detected
Lane boundary
Visual landmark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These features can be combined with robot sensors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obstacle Detection
&lt;/h2&gt;

&lt;p&gt;A simple perception pipeline is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera
  ↓
Object / Obstacle Detection
  ↓
Bounding Boxes
  ↓
Spatial Reasoning
  ↓
Navigation Layer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 2D detection alone does not provide reliable distance. For physical navigation, combine vision with depth, stereo cameras, LiDAR, calibration, or other sensors where appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Odometry
&lt;/h2&gt;

&lt;p&gt;Camera motion can also contribute to localization.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frame A
  ↓
Feature Extraction
  ↓
Feature Matching
  ↓
Motion Estimation
  ↓
Frame B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visual odometry is usually part of a larger localization system and should be fused with other sensors when possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Vision Data
&lt;/h2&gt;

&lt;p&gt;The Android application can publish compact perception messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"obstacles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.91&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A robot-side node can combine this information with LiDAR and odometry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;For real-time operation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce unnecessary frame conversions&lt;/li&gt;
&lt;li&gt;Process only the latest frame&lt;/li&gt;
&lt;li&gt;Use hardware acceleration where supported&lt;/li&gt;
&lt;li&gt;Choose an appropriate model size&lt;/li&gt;
&lt;li&gt;Measure inference latency&lt;/li&gt;
&lt;li&gt;Monitor device temperature&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Navigation Safety
&lt;/h2&gt;

&lt;p&gt;Vision should not directly command motors.&lt;/p&gt;

&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vision
  ↓
Perception
  ↓
Navigation Planner
  ↓
Safety Controller
  ↓
Motor Controller
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The safety controller should enforce speed, collision, and emergency-stop constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Test perception under:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different lighting&lt;/li&gt;
&lt;li&gt;Motion blur&lt;/li&gt;
&lt;li&gt;Shadows&lt;/li&gt;
&lt;li&gt;Crowded scenes&lt;/li&gt;
&lt;li&gt;Indoor and outdoor environments&lt;/li&gt;
&lt;li&gt;Camera orientation changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test the complete perception-to-action latency rather than only model inference time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Android computer vision can provide valuable perception capabilities for robot navigation. When combined with ROS 2, sensor fusion, and a dedicated safety controller, it becomes a useful component in a Physical AI robotics architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>computervision</category>
      <category>robotics</category>
    </item>
    <item>
      <title>YOLO Object Detection on Android for Robotics</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:36:18 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/yolo-object-detection-on-android-for-robotics-2bde</link>
      <guid>https://dev.to/vmodal_ai/yolo-object-detection-on-android-for-robotics-2bde</guid>
      <description>&lt;h1&gt;
  
  
  YOLO Object Detection on Android for Robotics
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Object detection is an important capability for autonomous robots. A robot can use detections to identify people, vehicles, tools, obstacles, and other objects in its environment.&lt;/p&gt;

&lt;p&gt;YOLO-family models are widely used for real-time object detection. In this tutorial, we will design an Android application that captures camera frames and performs YOLO inference locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  System Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CameraX
   |
Preprocessing
   |
YOLO Model
   |
Postprocessing
   |
Bounding Boxes
   |
Robot Perception Layer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact model format depends on the runtime you choose. For Android edge deployment, an exported model may be converted to a mobile-compatible format and executed using an appropriate inference runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Project
&lt;/h2&gt;

&lt;p&gt;Organize the project into separate layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vision/
├── CameraManager.kt
├── YoloDetector.kt
├── Detection.kt
└── DetectionOverlay.kt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents camera handling, inference, and rendering from becoming tightly coupled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection Model
&lt;/h2&gt;

&lt;p&gt;Create a Kotlin model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Detection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;classId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;boundingBox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RectF&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Camera Pipeline
&lt;/h2&gt;

&lt;p&gt;Use CameraX &lt;code&gt;ImageAnalysis&lt;/code&gt; to obtain frames.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;imageAnalysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAnalyzer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For real-time robotics, use a backpressure strategy that drops stale frames rather than allowing an inference queue to grow indefinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preprocessing
&lt;/h2&gt;

&lt;p&gt;Most object-detection models expect a fixed input size.&lt;/p&gt;

&lt;p&gt;The preprocessing stage normally performs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rotation correction&lt;/li&gt;
&lt;li&gt;Resize&lt;/li&gt;
&lt;li&gt;Color conversion&lt;/li&gt;
&lt;li&gt;Normalization&lt;/li&gt;
&lt;li&gt;Tensor creation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera Frame
   ↓
Resize
   ↓
Normalize
   ↓
Tensor
   ↓
YOLO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The preprocessing code must match the model's training/export requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Inference
&lt;/h2&gt;

&lt;p&gt;Create a detector abstraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YoloDetector&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ImageFrame&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Detection&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// preprocess&lt;/span&gt;
        &lt;span class="c1"&gt;// inference&lt;/span&gt;
        &lt;span class="c1"&gt;// postprocess&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run inference outside the Android main thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postprocessing
&lt;/h2&gt;

&lt;p&gt;Object detectors can return multiple candidate boxes. Postprocessing commonly includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confidence filtering&lt;/li&gt;
&lt;li&gt;Class filtering&lt;/li&gt;
&lt;li&gt;Bounding-box conversion&lt;/li&gt;
&lt;li&gt;Non-Maximum Suppression&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Raw Predictions
      ↓
Confidence Filter
      ↓
NMS
      ↓
Final Detections
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Drawing Bounding Boxes
&lt;/h2&gt;

&lt;p&gt;The Android UI can display detection results over the live camera preview.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------+
|                          |
|     +------------+       |
|     |   bottle   |       |
|     |    92%     |       |
|     +------------+       |
|                          |
+--------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to map coordinates correctly when the preview and model input have different aspect ratios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Detection for Robotics
&lt;/h2&gt;

&lt;p&gt;Detection results can be passed to a robot control layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bbox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The robotics layer can combine this information with depth, odometry, LiDAR, or other sensors.&lt;/p&gt;

&lt;p&gt;Do not treat a 2D bounding box as a physical distance measurement unless the system has additional calibration or depth information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization
&lt;/h2&gt;

&lt;p&gt;For edge robotics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a lightweight model where possible.&lt;/li&gt;
&lt;li&gt;Reduce inference resolution when acceptable.&lt;/li&gt;
&lt;li&gt;Reuse buffers.&lt;/li&gt;
&lt;li&gt;Avoid unnecessary bitmap allocations.&lt;/li&gt;
&lt;li&gt;Run inference off the UI thread.&lt;/li&gt;
&lt;li&gt;Process only the latest frame.&lt;/li&gt;
&lt;li&gt;Measure latency and thermal behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A smaller model running consistently can be more useful for robotics than a larger model with unstable frame rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Test the detector with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indoor scenes&lt;/li&gt;
&lt;li&gt;Outdoor scenes&lt;/li&gt;
&lt;li&gt;Low light&lt;/li&gt;
&lt;li&gt;Moving objects&lt;/li&gt;
&lt;li&gt;Multiple objects&lt;/li&gt;
&lt;li&gt;Camera rotation&lt;/li&gt;
&lt;li&gt;Network disconnected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For robotics, also measure end-to-end latency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Capture → Inference → Decision → Robot Command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;YOLO-style object detection can turn an Android device into a useful edge-vision component for robotics. Kotlin, CameraX, and a mobile inference runtime provide the foundation for building perception prototypes that can later integrate with ROS 2 and autonomous navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>yolo</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Streaming Robot Camera Feeds to Android with WebRTC</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:36:11 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/streaming-robot-camera-feeds-to-android-with-webrtc-1jol</link>
      <guid>https://dev.to/vmodal_ai/streaming-robot-camera-feeds-to-android-with-webrtc-1jol</guid>
      <description>&lt;h1&gt;
  
  
  Streaming Robot Camera Feeds to Android with WebRTC
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Remote robot operation often requires a live camera feed. Traditional HTTP streaming can introduce latency, while WebRTC is designed for real-time media communication.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will design an Android application that receives a robot camera stream using WebRTC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robot Camera
     |
 WebRTC Sender
     |
 Signaling Server
     |
 Android WebRTC Client
     |
 Compose UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signaling server exchanges connection information; the media path can then be established using WebRTC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android Components
&lt;/h2&gt;

&lt;p&gt;A typical implementation contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WebRtcClient
SignalingClient
VideoRenderer
RobotCameraViewModel
CameraScreen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep WebRTC lifecycle management outside the Compose UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peer Connection
&lt;/h2&gt;

&lt;p&gt;The client creates a peer connection and configures the required ICE servers.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WebRtcClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create peer connection&lt;/span&gt;
        &lt;span class="c1"&gt;// Configure ICE&lt;/span&gt;
        &lt;span class="c1"&gt;// Attach remote video track&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a maintained WebRTC Android library and follow its current API for peer-connection setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signaling
&lt;/h2&gt;

&lt;p&gt;WebRTC requires signaling to exchange session information.&lt;/p&gt;

&lt;p&gt;A simplified message flow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android             Robot
   |                   |
   | ---- Offer ------&amp;gt;|
   | &amp;lt;--- Answer ------|
   | &amp;lt;--- ICE --------&amp;gt;|
   | ---- ICE --------&amp;gt;|
   |                   |
   | === Media ========|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signaling transport can use WebSocket or another real-time messaging mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering Video
&lt;/h2&gt;

&lt;p&gt;The WebRTC video track should be connected to an Android-compatible video renderer.&lt;/p&gt;

&lt;p&gt;Keep the renderer lifecycle synchronized with the Activity or Compose screen lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compose Integration
&lt;/h2&gt;

&lt;p&gt;Compose can host the native video rendering surface using Android interoperability APIs.&lt;/p&gt;

&lt;p&gt;The Compose layer should mainly manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection state&lt;/li&gt;
&lt;li&gt;Loading indicator&lt;/li&gt;
&lt;li&gt;Error messages&lt;/li&gt;
&lt;li&gt;Full-screen mode&lt;/li&gt;
&lt;li&gt;Camera selection&lt;/li&gt;
&lt;li&gt;Robot selection&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Low-Latency Design
&lt;/h2&gt;

&lt;p&gt;For robot teleoperation, latency matters.&lt;/p&gt;

&lt;p&gt;Consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hardware-accelerated encoding&lt;/li&gt;
&lt;li&gt;Appropriate resolution&lt;/li&gt;
&lt;li&gt;Reasonable bitrate&lt;/li&gt;
&lt;li&gt;UDP connectivity where possible&lt;/li&gt;
&lt;li&gt;Avoiding unnecessary transcoding&lt;/li&gt;
&lt;li&gt;Measuring end-to-end latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not optimize for maximum resolution at the expense of control responsiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection Recovery
&lt;/h2&gt;

&lt;p&gt;Robot camera connections can fail when the robot moves between networks.&lt;/p&gt;

&lt;p&gt;Implement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Disconnected
    ↓
Reconnect
    ↓
Signaling
    ↓
ICE Negotiation
    ↓
Streaming
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Display the current state to the operator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Use authenticated signaling and encrypted WebRTC transport. Do not expose an unauthenticated robot camera endpoint to the public internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera + Telemetry
&lt;/h2&gt;

&lt;p&gt;A useful operator screen combines video with telemetry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------------------------+
|                              |
|       Robot Camera           |
|                              |
+------------------------------+
| Battery 82% | Speed 0.8 m/s  |
| Mode: AUTO  | Signal: Good   |
+------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;WebRTC is a strong technology for low-latency robot video. Combining it with Kotlin, Jetpack Compose, and a secure signaling service creates a foundation for remote robot monitoring and teleoperation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>webrtc</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Real-Time Robot Telemetry Visualization on Android</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:25:12 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/real-time-robot-telemetry-visualization-on-android-1893</link>
      <guid>https://dev.to/vmodal_ai/real-time-robot-telemetry-visualization-on-android-1893</guid>
      <description>&lt;h1&gt;
  
  
  Real-Time Robot Telemetry Visualization on Android
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Robots continuously generate telemetry such as position, velocity, battery level, temperature, sensor readings, and operating state. A mobile application can turn this data into a real-time monitoring interface.&lt;/p&gt;

&lt;p&gt;This tutorial demonstrates a clean Android architecture for receiving telemetry and rendering it efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robot Sensors
     |
 ROS 2 / Gateway
     |
 WebSocket / MQTT
     |
 Kotlin Repository
     |
 StateFlow
     |
 Compose Dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Telemetry Model
&lt;/h2&gt;

&lt;p&gt;Start with a strongly typed model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Telemetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strong typing makes the UI and processing layer easier to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming Data
&lt;/h2&gt;

&lt;p&gt;A repository can expose telemetry as a &lt;code&gt;Flow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;TelemetryRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Telemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ViewModel collects the stream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_telemetry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compose Visualization
&lt;/h2&gt;

&lt;p&gt;Display the latest values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;TelemetryPanel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Telemetry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Position: ${data.x}, ${data.y}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Velocity: ${data.velocity} m/s"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Battery: ${data.battery}%"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Temperature: ${data.temperature} °C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For historical values, keep a bounded buffer rather than storing unlimited telemetry in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-Time Charts
&lt;/h2&gt;

&lt;p&gt;Telemetry charts can visualize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Velocity
  |
  |       /\ 
  |  /\  /  \__
  |_/  \/       \_
  +---------------- Time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store only the amount of history required by the dashboard.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;history&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ArrayDeque&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Telemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove old samples when the configured buffer size is reached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling High-Frequency Data
&lt;/h2&gt;

&lt;p&gt;Robots may produce data much faster than the UI needs to refresh. Separate ingestion from rendering.&lt;/p&gt;

&lt;p&gt;A practical strategy is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robot:       100 Hz
Processing:   50 Hz
UI updates:   10-30 Hz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact rates depend on the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection State
&lt;/h2&gt;

&lt;p&gt;The dashboard should distinguish between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connected&lt;/li&gt;
&lt;li&gt;Connecting&lt;/li&gt;
&lt;li&gt;Disconnected&lt;/li&gt;
&lt;li&gt;Reconnecting&lt;/li&gt;
&lt;li&gt;Error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not display stale telemetry as if it were current.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Resilience
&lt;/h2&gt;

&lt;p&gt;Implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic reconnection&lt;/li&gt;
&lt;li&gt;Connection timeout&lt;/li&gt;
&lt;li&gt;Heartbeats&lt;/li&gt;
&lt;li&gt;Timestamp validation&lt;/li&gt;
&lt;li&gt;Backpressure&lt;/li&gt;
&lt;li&gt;Offline/error state&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Telemetry can reveal sensitive information about robot operations. Use encrypted transport and authenticated robot gateways in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Real-time telemetry visualization becomes manageable when streaming, state management, and rendering are separated. Kotlin Flow and StateFlow provide a natural foundation for reactive robot dashboards, while Jetpack Compose efficiently reflects the latest state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>robotics</category>
      <category>jetpackcompose</category>
    </item>
    <item>
      <title>Building an AI-Powered Robot Vision System with Android</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:24:44 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/building-an-ai-powered-robot-vision-system-with-android-1knb</link>
      <guid>https://dev.to/vmodal_ai/building-an-ai-powered-robot-vision-system-with-android-1knb</guid>
      <description>&lt;h1&gt;
  
  
  Building an AI-Powered Robot Vision System with Android
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Robot perception is one of the core components of Physical AI. A robot needs to understand its environment before it can make useful decisions.&lt;/p&gt;

&lt;p&gt;Android devices provide cameras, GPUs, neural-processing capabilities, and modern machine-learning runtimes, making them useful for prototyping mobile robot perception systems.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will build the architecture for an Android vision system that captures camera frames, runs an AI model, and exposes detection results to a robotics application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android Camera
      |
   Frame Pipeline
      |
   AI Inference
      |
 Detection Results
      |
+-----+------+
|            |
Android UI   Robot Gateway
             |
            ROS 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Android application performs perception while the robot middleware handles movement and navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera Setup
&lt;/h2&gt;

&lt;p&gt;Use CameraX to acquire frames from the device camera.&lt;/p&gt;

&lt;p&gt;A typical pipeline contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Preview
   |
ImageAnalysis
   |
Frame Conversion
   |
AI Model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep image processing away from the main UI thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frame Processing
&lt;/h2&gt;

&lt;p&gt;The image analyzer should process frames efficiently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;imageAnalysis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAnalyzer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;executor&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;imageProxy&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Convert frame&lt;/span&gt;
    &lt;span class="c1"&gt;// Run inference&lt;/span&gt;
    &lt;span class="c1"&gt;// Publish detections&lt;/span&gt;
    &lt;span class="n"&gt;imageProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always close &lt;code&gt;ImageProxy&lt;/code&gt; after processing. Otherwise, CameraX may stop delivering new frames.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Inference
&lt;/h2&gt;

&lt;p&gt;The inference layer should be independent of CameraX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;VisionModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;detect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ImageFrame&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Detection&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This abstraction lets you switch between TensorFlow Lite, ONNX Runtime, or another supported inference engine without rewriting the camera layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detection Model
&lt;/h2&gt;

&lt;p&gt;Define a common result structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Detection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI can draw these bounding boxes over the camera preview.&lt;/p&gt;

&lt;h2&gt;
  
  
  Showing Detections
&lt;/h2&gt;

&lt;p&gt;A Compose overlay can render detection information above the preview.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera Preview
+----------------------+
|     +--------+       |
|     | person  |       |
|     | 0.94    |       |
|     +--------+       |
|                      |
+----------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For high frame-rate applications, avoid unnecessary allocations during every frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Results to the Robot
&lt;/h2&gt;

&lt;p&gt;Detection results can be forwarded to a robot gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"person"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.51&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The robot can combine these results with its own sensors before making navigation decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge AI Considerations
&lt;/h2&gt;

&lt;p&gt;Running inference locally provides several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower latency&lt;/li&gt;
&lt;li&gt;Reduced network traffic&lt;/li&gt;
&lt;li&gt;Operation without cloud connectivity&lt;/li&gt;
&lt;li&gt;Better privacy&lt;/li&gt;
&lt;li&gt;More predictable response times&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, thermal throttling, battery consumption, and model size must be considered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frame Rate Optimization
&lt;/h2&gt;

&lt;p&gt;Do not necessarily run inference on every camera frame.&lt;/p&gt;

&lt;p&gt;A useful strategy is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera: 30 FPS
Inference: 10 FPS
Display: 30 FPS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The preview remains smooth while the AI model processes fewer frames.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot Safety
&lt;/h2&gt;

&lt;p&gt;Vision predictions should not directly trigger dangerous robot actions without validation.&lt;/p&gt;

&lt;p&gt;Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera
  ↓
AI Detection
  ↓
Decision Layer
  ↓
Safety Constraints
  ↓
Robot Command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decision and safety layers should be responsible for validating AI output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending the System
&lt;/h2&gt;

&lt;p&gt;The same architecture can support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Person detection&lt;/li&gt;
&lt;li&gt;Object tracking&lt;/li&gt;
&lt;li&gt;QR recognition&lt;/li&gt;
&lt;li&gt;Lane detection&lt;/li&gt;
&lt;li&gt;Obstacle detection&lt;/li&gt;
&lt;li&gt;Pose estimation&lt;/li&gt;
&lt;li&gt;Semantic segmentation&lt;/li&gt;
&lt;li&gt;Depth estimation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Android can act as a capable edge-perception platform for Physical AI prototypes. Combining CameraX, Kotlin coroutines, edge inference, and a robotics gateway creates a flexible foundation for intelligent robots.&lt;/p&gt;

&lt;p&gt;The next step is to combine vision with ROS 2 navigation and sensor fusion so that the robot can use perception results for autonomous behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>ai</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Building a Robot Dashboard with Jetpack Compose</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:24:40 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/building-a-robot-dashboard-with-jetpack-compose-1fb7</link>
      <guid>https://dev.to/vmodal_ai/building-a-robot-dashboard-with-jetpack-compose-1fb7</guid>
      <description>&lt;h1&gt;
  
  
  Building a Robot Dashboard with Jetpack Compose
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A robot dashboard gives operators a single interface for monitoring and controlling a Physical AI system. Jetpack Compose makes it possible to build a responsive dashboard using declarative Android UI.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will create the architecture for a dashboard that displays robot connectivity, battery, operating mode, telemetry, and control actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dashboard Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Robot / ROS 2
     |
 Robot Gateway
     |
 Kotlin Repository
     |
 ViewModel + StateFlow
     |
 Jetpack Compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI should observe state rather than communicate directly with the robot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot State
&lt;/h2&gt;

&lt;p&gt;Define a single state model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;RobotState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"IDLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ViewModel can expose it using &lt;code&gt;StateFlow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_robotState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableStateFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RobotState&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;robotState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_robotState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asStateFlow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compose Dashboard
&lt;/h2&gt;

&lt;p&gt;A simple dashboard can contain cards for each important metric:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;RobotDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RobotState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Robot Dashboard"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Status: ${if (state.connected) "&lt;/span&gt;&lt;span class="nc"&gt;ONLINE&lt;/span&gt;&lt;span class="s"&gt;" else "&lt;/span&gt;&lt;span class="nc"&gt;OFFLINE&lt;/span&gt;&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Battery: ${state.battery}%"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mode: ${state.mode}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Speed: ${state.speed} m/s"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a production application, split the screen into reusable components such as &lt;code&gt;StatusCard&lt;/code&gt;, &lt;code&gt;BatteryCard&lt;/code&gt;, &lt;code&gt;TelemetryCard&lt;/code&gt;, and &lt;code&gt;ControlPanel&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot Controls
&lt;/h2&gt;

&lt;p&gt;Controls should send commands through the ViewModel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopRobot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Emergency Stop"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep command execution outside composables so the UI remains testable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telemetry
&lt;/h2&gt;

&lt;p&gt;Telemetry can be collected from a repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RobotRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;observeState&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RobotState&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Connect to gateway&lt;/span&gt;
        &lt;span class="nc"&gt;TODO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ViewModel collects the stream and exposes it to Compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsive UI
&lt;/h2&gt;

&lt;p&gt;Robot dashboards may run on phones, tablets, rugged devices, or large operator displays. Use Compose adaptive layouts and avoid hard-coded dimensions.&lt;/p&gt;

&lt;p&gt;A useful layout is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----------------------------------+
| Robot Status        Battery 87%  |
+----------------------------------+
| Telemetry            Controls    |
| X: 2.4               ↑           |
| Y: 1.8            ← STOP →       |
| Speed: 0.8             ↓         |
+----------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Safety
&lt;/h2&gt;

&lt;p&gt;Never make the dashboard the only safety mechanism. Emergency-stop and motion limits should be enforced by the robot-side control system.&lt;/p&gt;

&lt;p&gt;Useful UI indicators include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connection status&lt;/li&gt;
&lt;li&gt;Autonomous/manual mode&lt;/li&gt;
&lt;li&gt;Battery level&lt;/li&gt;
&lt;li&gt;Current velocity&lt;/li&gt;
&lt;li&gt;Emergency-stop state&lt;/li&gt;
&lt;li&gt;Sensor warnings&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Jetpack Compose is a strong choice for modern Android robot dashboards. A state-driven architecture using Kotlin, StateFlow, ViewModel, and a dedicated robot gateway keeps the UI responsive and separates presentation from robotics communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>jetpackcompose</category>
      <category>robotics</category>
    </item>
    <item>
      <title>Android + ROS 2: Building a Robot Control App with Kotlin</title>
      <dc:creator>vmodal_ai</dc:creator>
      <pubDate>Mon, 17 Aug 2026 20:24:21 +0000</pubDate>
      <link>https://dev.to/vmodal_ai/android-ros-2-building-a-robot-control-app-with-kotlin-59m1</link>
      <guid>https://dev.to/vmodal_ai/android-ros-2-building-a-robot-control-app-with-kotlin-59m1</guid>
      <description>&lt;h1&gt;
  
  
  Android + ROS 2: Building a Robot Control App with Kotlin
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Physical AI is bringing together robotics, edge computing, computer vision, and intelligent mobile interfaces. Android is a useful companion platform because modern phones and tablets provide touch interfaces, cameras, sensors, networking, and strong edge-computing capabilities.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will design an Android application in Kotlin that communicates with a ROS 2 robot. The app will provide a simple control interface for sending movement commands and receiving robot telemetry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;A practical architecture can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android App
   |
   | ROS 2 bridge / WebSocket / MQTT
   v
ROS 2 Middleware
   |
   +---- /cmd_vel ----&amp;gt; Robot Base
   |
   +---- /odom -------&amp;gt; Telemetry
   |
   +---- /battery ----&amp;gt; Battery Status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Android application should not directly control motors. Instead, it communicates with a ROS 2 node or bridge responsible for validating commands and interfacing with the robot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;Create a Kotlin Android project using Android Studio.&lt;/p&gt;

&lt;p&gt;A clean package structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;com.example.robotcontroller
├── ui
├── ros
├── model
├── network
└── MainActivity.kt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the ROS communication layer separate from the Compose UI so that the application can later switch between a simulator, development robot, or production robot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robot Command Model
&lt;/h2&gt;

&lt;p&gt;Create a simple command model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;VelocityCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;linearX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;angularZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI can map buttons or a virtual joystick to these values.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;moveForward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VelocityCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;linearX&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;angularZ&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;VelocityCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;linearX&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;angularZ&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The communication layer then converts the command into the message format expected by your ROS 2 bridge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jetpack Compose Control UI
&lt;/h2&gt;

&lt;p&gt;A simple control panel can be created with Jetpack Compose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;RobotControls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;onForward&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;onBackward&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;onLeft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;onRight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;onStop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onForward&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Forward"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;Row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onLeft&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Left"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onStop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Stop"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onRight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Right"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onBackward&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Backward"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a real robot, replace these buttons with a joystick or gesture-based controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  ROS 2 Communication Layer
&lt;/h2&gt;

&lt;p&gt;The Android app needs a communication mechanism between the mobile device and ROS 2. A common architecture is to expose selected ROS 2 topics through a bridge or gateway.&lt;/p&gt;

&lt;p&gt;The Android client can then publish commands such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cmd_vel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and subscribe to telemetry topics such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/odom
/battery_state
/robot_status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avoid exposing the entire ROS graph directly to an untrusted mobile client. Expose only the topics and services required by the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receiving Telemetry
&lt;/h2&gt;

&lt;p&gt;Represent telemetry in Kotlin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;RobotTelemetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;battery&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;connected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use Kotlin coroutines and &lt;code&gt;StateFlow&lt;/code&gt; to expose updates to Compose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_telemetry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableStateFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;RobotTelemetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;telemetry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StateFlow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RobotTelemetry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_telemetry&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compose can collect this state and update the dashboard automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety Features
&lt;/h2&gt;

&lt;p&gt;A robot-control application should include a reliable stop mechanism.&lt;/p&gt;

&lt;p&gt;Implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emergency stop&lt;/li&gt;
&lt;li&gt;Automatic command timeout&lt;/li&gt;
&lt;li&gt;Connection-loss detection&lt;/li&gt;
&lt;li&gt;Maximum velocity limits&lt;/li&gt;
&lt;li&gt;Authentication between the app and robot&lt;/li&gt;
&lt;li&gt;TLS for network communication where supported&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A particularly useful technique is a command watchdog: if the robot does not receive a valid command within a defined interval, the control node should command zero velocity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with Simulation
&lt;/h2&gt;

&lt;p&gt;Before connecting physical hardware, test the Android application against a simulated ROS 2 robot.&lt;/p&gt;

&lt;p&gt;A simulator lets you verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Movement commands&lt;/li&gt;
&lt;li&gt;Telemetry&lt;/li&gt;
&lt;li&gt;Network failures&lt;/li&gt;
&lt;li&gt;Emergency stop behavior&lt;/li&gt;
&lt;li&gt;UI responsiveness&lt;/li&gt;
&lt;li&gt;Command limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This dramatically reduces the risk of testing incorrect commands on physical hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Architecture
&lt;/h2&gt;

&lt;p&gt;For a production system, consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Android / Kotlin
       |
   Secure Gateway
       |
      ROS 2
       |
 Navigation / Perception
       |
 Robot Hardware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separation allows the Android application to remain a user interface while ROS 2 handles robotics workloads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Android and Kotlin can provide a powerful human interface for Physical AI systems. By combining Jetpack Compose, Kotlin coroutines, secure networking, and ROS 2, you can build mobile applications that monitor and control robots without coupling the Android UI directly to robot hardware.&lt;/p&gt;

&lt;p&gt;The same architecture can later be extended with camera streaming, AI perception, voice commands, autonomous navigation, and LLM-based robot control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;p&gt;SDK Flutter: &lt;a href="https://github.com/v-modal/vmodal_sdk_flutter" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Android: &lt;a href="https://github.com/v-modal/vmodal_sdk_android" rel="noopener noreferrer"&gt;https://github.com/v-modal/vmodal_sdk_android&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord: &lt;a href="https://discord.gg/K72z28KUx" rel="noopener noreferrer"&gt;https://discord.gg/K72z28KUx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>robotics</category>
      <category>ros2</category>
    </item>
  </channel>
</rss>
