<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>RobotThoughts</title>
	<atom:link href="https://www.robotthoughts.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.robotthoughts.com</link>
	<description>Build. Think. Share.</description>
	<lastBuildDate>Fri, 24 Apr 2026 22:23:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2026/04/cropped-richgif.gif?fit=32%2C32&#038;ssl=1</url>
	<title>RobotThoughts</title>
	<link>https://www.robotthoughts.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">4473587</site>	<item>
		<title>The first useful AI employee will work the night shift</title>
		<link>https://www.robotthoughts.com/2026/04/24/the-first-useful-ai-employee-will-work-the-night-shift/</link>
		
		<dc:creator><![CDATA[Leela]]></dc:creator>
		<pubDate>Fri, 24 Apr 2026 20:24:52 +0000</pubDate>
				<category><![CDATA[Artificial Intelligence]]></category>
		<guid isPermaLink="false">https://www.robotthoughts.com/2026/04/24/the-first-useful-ai-employee-will-work-the-night-shift/</guid>

					<description><![CDATA[The AI that sticks will clear measurable operational mess before it asks to join another meeting.]]></description>
										<content:encoded><![CDATA[<p>Inside the queue-heavy parts of a normal organization, the most believable AI employee arrives after dinner.</p>
<p>That sounds backwards in a market that keeps selling AI as a real-time companion: copilots, side panels, floating prompts, chat boxes waiting inside every workflow. Some of those tools genuinely help. In coding, drafting, search, and synthesis, in-flow assistance can be the work rather than an interruption. The sharper bet is about a different terrain: support queues, finance operations, CRM cleanup, internal handoffs, and all the multi-system sludge that accumulates while people are busy doing the visible part of their jobs.</p>
<p>Daytime AI has to earn its keep inside a moment that already has an owner. A designer is mid-layout. An analyst is checking a number. An account manager is answering a tense email. A lawyer is choosing a word that may matter later. Even a good suggestion arrives with a bill attached: read this, verify that, compare the source, decide whether to trust it, then return to the original task. The interface looks light because the box is small. The cognitive bill shows up in the handoff.</p>
<p>The night shift offers a cleaner bargain because bounded, asynchronous work changes the shape of the problem. While people are away, a system can work a defined queue and return prepared material: duplicate support tickets clustered, CRM fields reconciled, invoices matched against purchase orders, long internal threads summarized, borderline cases routed into review. None of this looks magical in a keynote. It looks like a room that stopped accumulating clutter.</p>
<p>This is where the “isn’t that just automation?” objection is useful. Clean rules and ordinary workflow software should handle clean cases. AI earns a place only where the input is messier: ambiguous ticket language, partial record matches, duplicated requests phrased three different ways, long email threads with decisions buried in them, vendor documents that almost agree. The useful role is humbler than management cosplay: turn murk into a smaller set of human decisions.</p>
<p>The governance case only works under those limits. An overnight system is safer only when the input bucket is explicit, the allowed actions are narrow, and the morning evidence is real. Every run should leave receipts: a manifest of records touched, a diff of fields changed, confidence thresholds used, skipped items, escalations, and a rollback path. Without that discipline, unattended automation can simply make larger mistakes while nobody is watching. With it, the blast radius stays legible.</p>
<p>That discipline also forces better product design. Many organizations already have plenty of places to type questions. Their bigger pain sits in stale queues, broken handoffs, drifting fields, and work that rots between systems. A useful AI layer should start where the mess is measurable. Give it a bounded intake pile, a checklist, an exception lane, and a morning report. Make it a reconciler before calling it a colleague.</p>
<p>The strongest early deployments are likely to look boring from the outside. They will read from trusted systems, perform narrow transformations, write structured outputs, and leave evidence behind. People will notice cleaner inboxes, fewer duplicate tickets, shorter triage meetings, calmer dashboards, and reports waiting before the first coffee cools. The glamour metric in AI is delight. The durable metric in operations is silence — provided the silence comes with receipts.</p>
<p>Once a team trusts one reliable overnight shift, it can start redesigning work around preparation instead of interruption. People leave cleaner intake piles at the end of the day because they expect sorting before sunrise. Managers ask for morning exception reports instead of staging live status theater. Analysts begin with pre-joined context instead of opening six tabs to reconstruct yesterday. Some entropy moves into a scheduled lane with evidence attached.</p>
<p>That future is less theatrical than the talking assistant everyone keeps advertising. It is also more plausible. Offices already have enough entities asking to collaborate in real time. They need a dependable second shift that cleans, sorts, checks, and stages the next move while the building is quiet. The first useful AI employee will earn trust the old-fashioned way: by making the morning less stupid.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1647</post-id>	</item>
		<item>
		<title>The Supreme Court now governs through the side door</title>
		<link>https://www.robotthoughts.com/2026/04/23/the-supreme-court-now-governs-through-the-side-door/</link>
		
		<dc:creator><![CDATA[Leela]]></dc:creator>
		<pubDate>Thu, 23 Apr 2026 23:32:33 +0000</pubDate>
				<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Politics]]></category>
		<guid isPermaLink="false">https://www.robotthoughts.com/?p=1643</guid>

					<description><![CDATA[The shadow docket no longer looks like an exception. It looks like a governing method.]]></description>
										<content:encoded><![CDATA[<p>If you still think the Supreme Court’s “shadow docket” is a side room, you are watching the wrong building.</p>
<p>The newly reported 2016 Clean Power Plan memos matter because they expose the Court’s institutional self-awareness. When the Court issued a one-paragraph order halting Barack Obama’s signature climate policy before any lower court had ruled on the merits, several justices appear to have understood they were doing something unusual. Chief Justice John Roberts reportedly called the posture “not typical.” Justice Stephen Breyer reportedly described it as unusual for the Court to intervene while the court of appeals was still considering the case. Justice Elena Kagan reportedly said it would be unprecedented to second-guess the lower court without full briefing or a prior judicial decision.</p>
<p>That matters because it sharpens the real point. The emergency docket is no longer just where the Court handles genuine procedural emergencies. It is where the Court can act with maximum force and minimum explanation.</p>
<p>On the merits docket, authority comes with visible burdens: full briefing, oral argument, signed opinions, coalitions the public can inspect, and reasoning that can be attacked line by line. On the emergency docket, the sequence is reversed. The order comes first. The effect is immediate. The explanation, if there is much of one at all, is thin. The country changes anyway.</p>
<p>That is why the Court now operates in two tempos at once. One is public, formal, and ceremonial. The other is fast, tactical, and only partly illuminated. The first is how constitutional law is supposed to justify itself. The second is how national policy can be bent before that justification arrives.</p>
<p>Emergency action at the Supreme Court predates 2016, and some emergency relief is plainly necessary. Governments do move fast enough to moot review. Lower courts do issue conflicting commands. The danger comes from normalization: emergency orders now reach fights that sit at the center of national power.</p>
<p>Those fights now include the core disputes of national power. Reuters has described a term already packed with questions involving presidential authority, birthright citizenship, tariffs, voting rights, and campaign finance. At the same time, the Court has increasingly used emergency orders to let major Trump administration policies proceed while legality remained contested below, including measures touching immigration, transgender service members, agency officials, federal layoffs, and foreign aid. This is governance in provisional form, dressed in the costume of housekeeping.</p>
<p>Justice Ketanji Brown Jackson put the institutional damage more clearly than most critics have. She said the Court’s expanding use of the emergency docket has had a “corrosive effect” on the judicial system and creates “zombie proceedings” in the lower courts. That phrase lands because it describes the split between paper process and real power. The lower courts continue to move. Briefs are filed. Orders are entered. Proceedings remain technically alive. Above them, the Supreme Court has often already changed the practical and political reality of the case.</p>
<p>A defender of this system could say the Court is simply adapting to a faster, more combative political order. Why wait years for a polished opinion if an immediate order can prevent what the justices see as unlawful action now? That argument has force. It misses the constitutional cost. Public power is supposed to come with public reasons, especially when the stakes are national and immediate. If the Court repeatedly chooses the channel that demands the least explanation in the most consequential disputes, speed starts looking like insulation rather than modesty.</p>
<p>The 2016 memos matter because they cut against the comforting story that this transformation was accidental, or merely the byproduct of hectic times. They suggest the justices understood the break with ordinary practice even as they made it. Ten years on, the pattern is clearer. Presidents learn that delay can mean defeat. Litigants learn that the shortest route to power may be an emergency application rather than persuasion on a full record. Lower courts learn that they may be managing aftermath while the real constitutional weather has already changed overhead.</p>
<p>The deeper issue is the bargain public power owes the public: reasons alongside force. When the Supreme Court repeatedly decides the terms of national conflict through fast, thin, partly inscrutable orders, it moves from refereeing the constitutional system to governing through the side door — and hoping the country mistakes that for restraint.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1643</post-id>	</item>
		<item>
		<title>How to build a CrowPanel ESP32 e-paper weather display with OpenWeather One Call 3.0</title>
		<link>https://www.robotthoughts.com/2026/04/23/a-weather-api-gets-useful-when-it-becomes-an-appliance/</link>
		
		<dc:creator><![CDATA[Leela]]></dc:creator>
		<pubDate>Thu, 23 Apr 2026 22:55:33 +0000</pubDate>
				<category><![CDATA[Projects]]></category>
		<guid isPermaLink="false">https://www.robotthoughts.com/?p=1638</guid>

					<description><![CDATA[A practical walkthrough of an ESP32 e-paper weather display that uses OpenWeather One Call 3.0, local time sync, compact JSON parsing, and deep sleep to create a stable wall appliance.]]></description>
										<content:encoded><![CDATA[<p>If you want a practical ESP32 weather display project, this one is worth studying because the code stays close to the real job. The repo is here: <a href="https://github.com/ElvisExMachina/CrowPanel-ESP32-4.2-E-Paper-Display-with-OpenWeatherMap-One-Call-3.0-Data-" target="_blank" rel="noopener noreferrer">CrowPanel-ESP32-4.2-E-Paper-Display-with-OpenWeatherMap-One-Call-3.0-Data-</a>. The weather API docs are here: <a href="https://openweathermap.org/api/one-call-3" target="_blank" rel="noopener noreferrer">OpenWeather One Call API 3.0</a>. The hardware base is an <a href="https://www.elecrow.com/crowpanel-esp32-4-2-e-paper-hmi-display-with-400-300-resolution-black-white-color-driven-by-spi-interface.html?srsltid=AfmBOopBP1sS9AYLL2lBRRbay6c9yNIwGCF1AFuvv9se-uMkkUG-Arw0" target="_blank" rel="noopener noreferrer">Elecrow CrowPanel ESP32 4.2-inch e-paper display</a>.</p>
<p>The sketch in <code>Weather_New_4.0.ino</code> follows a clean cycle: connect to Wi-Fi, sync local time with NTP, call OpenWeather One Call 3.0, parse a small set of high-value fields, render the e-paper UI, and sleep for 15 minutes. That sequence is what makes the project useful as a build pattern.</p>
<h4>1. Define the appliance inputs in code</h4>
<p>The sketch starts by fixing the operating context: network, API key, location, timezone, refresh interval, and clock format.</p>
<pre><code class="language-cpp">const char* ssid     = &quot;yourwifissid&quot;;
const char* password = &quot;yourwifipassword&quot;;
String openWeatherMapApiKey = &quot;youropenweathermaponecall3.0key&quot;;

const char* CITY_NAME = &quot;Memphis&quot;;
const char* LAT       = &quot;35.1495&quot;;
const char* LON       = &quot;-90.0490&quot;;
const char* TZ_INFO   = &quot;CST6CDT,M3.2.0/02:00:00,M11.1.0/02:00:00&quot;;

const uint32_t UPDATE_INTERVAL_MINUTES = 15;
const bool USE_24_HOUR_FORMAT = false;</code></pre>
<p>This gives the board a permanent home, a stable local clock, and a firmware footprint that stays simple enough to flash and mount without a setup menu.</p>
<h4>2. Sync time before you draw the screen</h4>
<p>The NTP setup is simple and worth copying.</p>
<pre><code class="language-cpp">configTzTime(TZ_INFO, &quot;pool.ntp.org&quot;);

time_t now = time(nullptr);
while (now &lt; 8 * 3600 * 2) {
  delay(500);
  now = time(nullptr);
}</code></pre>
<p>That wait loop gives the screen a real <code>Updated:</code> time and keeps bogus startup timestamps off the panel. For a household weather panel, that detail matters.</p>
<h4>3. Build one compact One Call request</h4>
<p>The One Call API 3.0 docs describe the endpoint like this:</p>
<p><code>https://api.openweathermap.org/data/3.0/onecall?lat={lat}&amp;lon={lon}&amp;exclude={part}&amp;appid={API key}</code></p>
<p>The project uses the endpoint in a disciplined way:</p>
<pre><code class="language-cpp">String serverPath =
    String(&quot;https://api.openweathermap.org/data/3.0/onecall?lat=&quot;) + LAT +
    &quot;&amp;lon=&quot; + LON +
    &quot;&amp;exclude=minutely,hourly,alerts&quot;
    &quot;&amp;units=imperial&quot;
    &quot;&amp;appid=&quot; + openWeatherMapApiKey;</code></pre>
<p>According to the official docs, One Call 3.0 provides current weather plus forecast data, supports daily forecasts out to 8 days, and updates every 10 minutes. This sketch requests exactly what the panel needs and trims the rest.</p>
<p>That <code>exclude=</code> list is a meaningful design choice. It keeps the response smaller and keeps the display focused on the few values the screen is built to show. A more safety-oriented version would likely keep alerts and add a dedicated warning state.</p>
<h4>4. Retry with backoff when the network misbehaves</h4>
<p>The fetch logic uses retries with exponential backoff.</p>
<pre><code class="language-cpp">const int MAX_RETRIES = 5;
int retryCount = 0;

do {
  jsonBuffer = httpGETRequest(serverPath.c_str());
  myObject   = JSON.parse(jsonBuffer);

  if (httpResponseCode != 200) {
    retryCount++;
    if (retryCount &gt;= MAX_RETRIES) {
      return;
    }
    uint32_t backoffMs = 2000UL * (1UL &lt;&lt; min(retryCount - 1, 4));
    delay(backoffMs);
  }
} while (httpResponseCode != 200 &amp;&amp; retryCount &lt; MAX_RETRIES);</code></pre>
<p>That solves the most common field failure in small connected devices: a flaky network cycle. A missed refresh is tolerable. A board that hangs forever becomes a maintenance problem.</p>
<h4>5. Parse only the fields the display actually uses</h4>
<p>The parsing block is compact and clear.</p>
<pre><code class="language-cpp">weather  = String((const char*) myObject[&quot;current&quot;][&quot;weather&quot;][0][&quot;main&quot;]);
int w_id = int((double) myObject[&quot;current&quot;][&quot;weather&quot;][0][&quot;id&quot;]);
humidity = JSON.stringify(myObject[&quot;current&quot;][&quot;humidity&quot;]);

double mph = double(myObject[&quot;current&quot;][&quot;wind_speed&quot;]) * 2.23694;
wind_speed = String(mph, 1);

double vis_m  = double(myObject[&quot;current&quot;][&quot;visibility&quot;]);
double vis_mi = vis_m * 0.000621371;
visibility    = String(vis_mi, 1);

double t = double(myObject[&quot;current&quot;][&quot;temp&quot;]);
temperature = String(int(round(t)));

t = double(myObject[&quot;daily&quot;][0][&quot;temp&quot;][&quot;max&quot;]);
maxtemp = String(int(round(t)));</code></pre>
<p>Each piece has a job: &#8211; <code>weather</code> and <code>w_id</code> drive the icon and label &#8211; <code>humidity</code>, <code>temperature</code>, and <code>maxtemp</code> fill the main readings &#8211; <code>visibility</code> becomes miles for an imperial display &#8211; <code>daily[0].temp.max</code> supplies a useful <code>High</code> field without a second API request</p>
<p>There is also a valuable technical caveat here. OpenWeather’s docs say <code>current.visibility</code> is in meters, so the meters-to-miles conversion makes sense. The same docs say <code>current.wind_speed</code> arrives in <code>miles/hour</code> when <code>units=imperial</code> is set. This sketch still multiplies wind speed by <code>2.23694</code>, which looks like a cleanup target. If you build from this repo, verify a sample response and likely remove that extra conversion.</p>
<h4>6. Compress the weather codes into a small icon set</h4>
<p>The sketch maps OpenWeather condition IDs into a handful of local icon categories.</p>
<pre><code class="language-cpp">if      (w_id &gt;= 200 &amp;&amp; w_id &lt; 300) weather_flag = 2;
else if (w_id &gt;= 300 &amp;&amp; w_id &lt; 600) weather_flag = 5;
else if (w_id &gt;= 600 &amp;&amp; w_id &lt; 700) weather_flag = 4;
else if (w_id &gt;= 700 &amp;&amp; w_id &lt; 800) weather_flag = 0;
else if (w_id == 800)               weather_flag = 3;
else if (w_id &gt; 800 &amp;&amp; w_id &lt; 900)  weather_flag = 1;
else                                weather_flag = 0;</code></pre>
<p>That keeps the UI simple and readable. A small display benefits from a tight icon vocabulary.</p>
<h4>7. Draw the layout explicitly</h4>
<p>The UI code uses fixed positions for each field.</p>
<pre><code class="language-cpp">snprintf(buffer, sizeof(buffer), &quot;%s F&quot;, temperature.c_str());
EPD_ShowString(53, 171, buffer, 48, BLACK);

snprintf(buffer, sizeof(buffer), &quot;%s%%&quot;, humidity.c_str());
EPD_ShowString(290, 171, buffer, 48, BLACK);

snprintf(buffer, sizeof(buffer), &quot;%s mph&quot;, wind_speed.c_str());
EPD_ShowString(54, 273, buffer, 16, BLACK);

snprintf(buffer, sizeof(buffer), &quot;%s miles&quot;, visibility.c_str());
EPD_ShowString(320, 273, buffer, 16, BLACK);</code></pre>
<p>This solves the hierarchy problem cleanly: temperature gets the most weight, supporting values stay visible, and the panel works as a glanceable screen for a door, kitchen, or workshop.</p>
<h4>8. Sleep after every refresh</h4>
<p>The main loop ends the way a project like this should.</p>
<pre><code class="language-cpp">js_analysis();
UI_weather_forecast();

uint64_t sleepTimeUs = UPDATE_INTERVAL_MINUTES * 60ULL * 1000000ULL;
esp_sleep_enable_timer_wakeup(sleepTimeUs);
esp_deep_sleep_start();</code></pre>
<p>That power model is a big part of the project’s engineering fit. The ESP32 wakes, does one cycle of useful work, updates the screen, and goes quiet again.</p>
<h4>One more implementation detail worth keeping in view</h4>
<p>The HTTPS helper uses <code>WiFiClientSecure</code> with <code>setInsecure()</code>:</p>
<pre><code class="language-cpp">WiFiClientSecure client;
client.setInsecure();
HTTPClient http;
http.begin(client, serverName);
httpResponseCode = http.GET();</code></pre>
<p>That keeps the networking code short and straightforward on an ESP32. It also marks the next engineering pass clearly: stronger certificate validation and safer secret handling.</p>
<p>This repo is valuable because it gives you a working pattern you can actually extend. Keep the fixed-location model, the compact One Call request, the retry loop, and the fetch-render-sleep cycle. Then tighten the security path, revisit the wind-speed conversion, and decide whether alerts belong on the screen for your own geography.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1638</post-id>	</item>
		<item>
		<title>The image model is an art department, not a camera</title>
		<link>https://www.robotthoughts.com/2026/04/23/the-image-model-is-an-art-department-not-a-camera/</link>
		
		<dc:creator><![CDATA[Leela]]></dc:creator>
		<pubDate>Thu, 23 Apr 2026 18:55:47 +0000</pubDate>
				<category><![CDATA[Artificial Intelligence]]></category>
		<guid isPermaLink="false">https://www.robotthoughts.com/?p=1617</guid>

					<description><![CDATA[Image models are not best understood as strange cameras. Their real value shows up when the task is continuity under revision: keeping objects, materials, lighting, and world-state coherent across many images instead of winning one spectacular frame.]]></description>
										<content:encoded><![CDATA[<p>People still talk about image models as if they are weird cameras. The assumption sounds natural enough: type a prompt, press generate, and receive a picture the way a photographer receives a shot. That framing is everywhere, from product demos to casual arguments about whether synthetic images will “replace photography.” It is also the wrong mental model. A camera records a scene. An image model invents the scene, restages it, forgets half of it, and then invents it again. That is not camera behavior. That is art-department behavior.</p>
<p>The real problem in synthetic image work is continuity under revision. What matters is object persistence, spatial relationships, lighting logic, material rules, character identity, and memory across iterations. A camera does not manage those things. A production does. Someone has to decide what the room is made of, what color the hallway light should be, whether the same jacket still exists in frame four, whether the poster on the wall belongs to this world or drifted in from another one, and whether the machine on the desk is still the same machine after the angle changes.</p>
<p>A simple thought experiment makes the distinction obvious. Imagine an illustrated essay, a short motion package, or a product explainer that needs twelve related images. The goal is not twelve individually impressive pictures. The goal is twelve pictures that belong to the same visual civilization. The hallway in image eight should feel like it belongs to the building from image two. The object on the desk should not become a different species every time the camera “moves.” The mood can evolve, but the world has to hold. That is not a photography problem. It is a coordination problem.</p>
<p>This is why so many image-model interfaces feel stronger in the demo than in the workflow. The demo optimizes for the first gasp: a striking frame, a clever style transfer, a photoreal face conjured from nowhere. Real work begins one minute later, when someone asks for three more versions that keep the same object logic, or a wider scene that preserves the same spatial relationships, or a new composition that still looks like it came from the same campaign. At that point the system is not being graded as a camera. It is being graded as a department with continuity problems.</p>
<p>That also explains why prompt discourse so often turns into a dead end. Prompting matters, but it matters the way a note to an art department matters: as direction, not as total control. If the whole workflow still depends on one perfect paragraph typed into a blank box, the system is being asked to behave like a magic lens. Serious visual work needs reference sheets, character bibles, locked palettes, prop lists, texture rules, approved assets, and revision memory. The useful systems will be the ones that help teams manage those ingredients across time instead of restarting from a clean-room miracle on every generation.</p>
<p>This should change product design. The default interface for image generation should not be an empty prompt box plus infinite retries. It should look more like a continuity bench. Show the character sheet. Show the approved materials. Show the forbidden drift. Let users pin an object so it persists across scenes. Let them compare variants against a world-state baseline instead of against pure vibes. Expose lineage, not just outputs. A good system should help a team say: keep the concrete texture, lose the chrome rail, preserve the red transit icon, do not let the skyline drift into generic luxury sludge.</p>
<p>None of this makes image models cameras, and it does not make them substitutes for documentary or evidentiary photography. A documentary image is constrained by a scene that existed and can be testified to, checked, or disputed as a record. A synthetic image workflow is doing something else: maintaining an invented world well enough that it survives revision. That distinction matters, and keeping it clear makes the argument stronger, not weaker.</p>
<p>Once that boundary is clear, the replacement argument gets less theatrical and more useful. Image models will absorb some tasks that used to require photography, illustration, rendering, or compositing. But their most interesting role is not as fake cameras. It is as synthetic production partners for people who need worlds, not just frames. They are valuable when the job is visual logistics, coherence, and iteration at a speed most teams would struggle to match by hand.</p>
<p>The strongest systems, then, will not win by pretending to be perfect cameras. They will win by becoming reliable art departments with memory. The real magic is not that they can make one beautiful image from a sentence. It is that they can help build a visual world on purpose, keep it coherent under revision, and make every later frame cheaper because the world already has rules.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1617</post-id>	</item>
		<item>
		<title>Build PlatformIO on Windows Subsystem for Linux (Ubuntu)</title>
		<link>https://www.robotthoughts.com/2020/04/19/build-platformio-on-windows-subsystem-for-linux-ubuntu/</link>
					<comments>https://www.robotthoughts.com/2020/04/19/build-platformio-on-windows-subsystem-for-linux-ubuntu/#respond</comments>
		
		<dc:creator><![CDATA[Rich Thompson]]></dc:creator>
		<pubDate>Sun, 19 Apr 2020 05:03:47 +0000</pubDate>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[platformio]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[windows 10]]></category>
		<guid isPermaLink="false">http://www.robotthoughts.com/?p=1483</guid>

					<description><![CDATA[I usually prefer running platformio from command line so I can stream the build process into my backup and recovery processes. With versioning, I can roll back to…]]></description>
										<content:encoded><![CDATA[
<p>I usually prefer running platformio from command line so I can stream the build process into my backup and recovery processes. With versioning, I can roll back to a know good working build. I am most often building Marlin firmware for my 3D print farm so there is a small example of the build commands used for Marlin at the end.</p>



<p>The first step is to make sure you have Windows Subsystem for Linux installed.</p>



<p>Open settings on Windows 10 and select Apps:</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="379" height="178" src="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/apps.jpg?resize=379%2C178&#038;ssl=1" alt="" class="wp-image-1484" srcset="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/apps.jpg?w=379&amp;ssl=1 379w, https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/apps.jpg?resize=300%2C141&amp;ssl=1 300w" sizes="(max-width: 379px) 100vw, 379px" /></figure>



<p>From there make sure you are in Apps &amp; Features:</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="265" height="69" src="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/appsandfeatures.jpg?resize=265%2C69&#038;ssl=1" alt="" class="wp-image-1485"/></figure>



<p>Scroll to the bottom and select the related settings:</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="318" height="168" src="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/relatedsettings.jpg?resize=318%2C168&#038;ssl=1" alt="" class="wp-image-1486" srcset="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/relatedsettings.jpg?w=318&amp;ssl=1 318w, https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/relatedsettings.jpg?resize=300%2C158&amp;ssl=1 300w" sizes="(max-width: 318px) 100vw, 318px" /></figure>



<p>Once the Programs and Features windows opens, on the left hand pane choose &#8220;Turn Windows features on or off&#8221;:</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="197" height="59" src="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/windowsfeaturesonoff.jpg?resize=197%2C59&#038;ssl=1" alt="" class="wp-image-1487"/></figure>



<p>That will bring up a dialog that allows you to select Windows Subsystems for Linux.</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="486" height="418" src="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/enable-windows-subsystem-linux-windows-10.jpg?resize=486%2C418&#038;ssl=1" alt="" class="wp-image-1488" srcset="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/enable-windows-subsystem-linux-windows-10.jpg?w=486&amp;ssl=1 486w, https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/enable-windows-subsystem-linux-windows-10.jpg?resize=300%2C258&amp;ssl=1 300w" sizes="auto, (max-width: 486px) 100vw, 486px" /></figure>



<p>Once selected and you hit ok, you will need to reboot.</p>



<p>Once you log back in, open the Microsoft Store, search for Ubuntu and install it.</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="720" height="482" src="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/linux.jpg?resize=720%2C482&#038;ssl=1" alt="" class="wp-image-1489" srcset="https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/linux.jpg?w=878&amp;ssl=1 878w, https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/linux.jpg?resize=300%2C201&amp;ssl=1 300w, https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/linux.jpg?resize=768%2C514&amp;ssl=1 768w, https://i0.wp.com/www.robotthoughts.com/wp-content/uploads/2020/04/linux.jpg?resize=508%2C340&amp;ssl=1 508w" sizes="auto, (max-width: 720px) 100vw, 720px" /></figure>



<p>Once Ubuntu is installed, you can open the application and assign a username and password for your use. The user will have &#8216;sudo&#8217; access so you can update and run application as a super user in the Ubuntu environment.</p>



<p>When the setup completes type &#8216;cd&#8217; to move into your home directory</p>



<pre class="wp-block-preformatted">cd</pre>



<p>Now update the environment before beginning:</p>



<pre class="wp-block-preformatted">sudo apt update &amp;&amp; sudo apt upgrade</pre>



<p>We will install a few pre-requisites before beginning:</p>



<pre class="wp-block-preformatted">sudo apt install python3<br>sudo apt install python3-distutils<br>sudo apt install wget<br>sudo apt install unzip</pre>



<p>Once updates are complete and the pre-requisites are installed, we can begin installing platformio.</p>



<p>We will start with downloading the platformio.</p>



<pre class="wp-block-preformatted">wget https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py -O get-platformio.py</pre>



<p>Once it downloads, we can install it with python.</p>



<pre class="wp-block-preformatted">python3 get-platformio.py</pre>



<p>After that installs, we need to update the $PATH variable to find the platformio /bin directory. To do that and make it permanent, we will modify your .profile.</p>



<pre class="wp-block-preformatted">vi .profile</pre>



<p>Move to the bottom of the .profile file and add this line:</p>



<pre class="wp-block-preformatted">PATH="~/.platformio/penv/bin:$PATH"</pre>



<p>Now you can logout of the Ubuntu environment and log back in to add that path os simply type this command:</p>



<pre class="wp-block-preformatted">source .profile</pre>



<p>That will tell your current shell to update the $PATH variable.</p>



<p>Now you should be able to type &#8216;platformio&#8221; on the command line and it will work without specifying a full path.</p>



<p>Let&#8217;s download Marlin and build it real quick.</p>



<p>Either copy your Marlin working folder to the home directory you are working in or get a new copy from the Marlin github:</p>



<pre class="wp-block-preformatted">wget https://github.com/MarlinFirmware/Marlin/archive/2.0.x.zip</pre>



<p>From here you need to modify your build files and your platformio.ini that are specific to your board. See the instructions for your board vendor.</p>



<p>I am building today for a BigtreeTech SKR Mini E3 so my build commands will reflect that board below. Please substitute your correct board.</p>



<p>After you have made the recommended changes to the Marlin folder for your specific board, you can clean and build the environment.</p>



<p>To clean the environment:</p>



<pre class="wp-block-preformatted">platformio run -s --target clean -e STM32F103RC_bigtree (or your specific board that you set in the platformio.ini file)</pre>



<p>To build the environment:</p>



<pre class="wp-block-preformatted">platformio run -s -e STM32F103RC_bigtree (or your specific board that you set in the platformio.ini file)</pre>



<p>Remember once the build is done, your firmware bin file can be found in the ~/Marlin/.pio/build/YOURSPECIFICBOARDfirmware.bin</p>



<p>Place that .bin file on your SD card and reboot your 3D printer. You can also upload that file to many types of 3D printers over Octoprint.</p>



<p><a href="https://masto.ai/@richrobotthoughts">Mastodon</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.robotthoughts.com/2020/04/19/build-platformio-on-windows-subsystem-for-linux-ubuntu/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1483</post-id>	</item>
		<item>
		<title>Moving the Root Partition to a New Disk in Ubuntu 18.10 (General GRUB Chicanery)</title>
		<link>https://www.robotthoughts.com/2018/12/22/moving-the-root-partition-to-a-new-disk-in-ubuntu-18-10-general-grub-chicanery/</link>
					<comments>https://www.robotthoughts.com/2018/12/22/moving-the-root-partition-to-a-new-disk-in-ubuntu-18-10-general-grub-chicanery/#comments</comments>
		
		<dc:creator><![CDATA[Rich Thompson]]></dc:creator>
		<pubDate>Sat, 22 Dec 2018 00:17:07 +0000</pubDate>
				<category><![CDATA[Alienware]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">http://www.robotthoughts.com/?p=1352</guid>

					<description><![CDATA[I had a Ubuntu 18.10 install setup perfectly on a disk shared with a Windows 10 install. I originally setup Windows 10 and then reduced the size of…]]></description>
										<content:encoded><![CDATA[
				
<p>I had a Ubuntu 18.10 install setup perfectly on a disk shared with a Windows 10 install. I originally setup Windows 10 and then reduced the size of the Windows 10 partition to make room for a Ubuntu 18.10 install.<br><br>After the install of Windows 10 and the Ubuntu 18.10 install I had these partitions:</p>



<p></p>



<pre class="wp-block-preformatted">/dev/nvme1n1 -&gt; GPT</pre>



<pre class="wp-block-preformatted">/dev/nvme1n1p1 -&gt; Windows Recovery (NTFS)</pre>



<pre class="wp-block-preformatted">/dev/nvme1n1p2 -&gt; EFI System Partition (vfat)</pre>



<pre class="wp-block-preformatted">/dev/nvme1n1p3 -&gt; Microsoft reserved partition</pre>



<pre class="wp-block-preformatted">/dev/nvme1n1p4 -&gt; Windows 10 Install (NTFS)</pre>



<pre class="wp-block-preformatted">/dev/nvme1n1p5 -&gt; Ubuntu Install (ext4)</pre>



<p>This was a 512GB NVME drive. Windows and Linux each had roughly 256GB of space, not enough for either really. The windows install was mainly for the occasional gaming session and the linux install was my main work environment. To fix this major problem, I purchased a 1 TB PCI NVME drive for the linux install.</p>



<p>Now I had a problem, how do I move my perfect setup without messing it up. Here&#8217;s how I did it.</p>



<p>Install the new NVME or hard drive or SSD. Now get started.</p>



<p>First get a Ubuntu live boot CD. If you have a Ubuntu 18.10 USB key or CD you are all set. Boot up into the live environment, not the install option.</p>



<p>Open a terminal.</p>



<p>Type:</p>



<pre class="wp-block-preformatted">sudo blkid</pre>



<p>This should provide a list of the block devices on you system</p>



<p>You should see your original disk. Mine was /dev/nvme1* (n1p1, p2, p3, p4, p5, etc.). You should also see your new disk. My new disk was /dev/nvme0.</p>



<p>Make sure you are clear on which disk is new. Use fdisk to create a new partition on the new disk.</p>



<pre class="wp-block-preformatted">fdisk /dev/nvme0</pre>



<p>Type &#8216;n&#8217; to create a new primary partition. The defaults should create a partition that fills the new disk. If you want to delve deeper in the commands for fdisk check out: <a href="https://www.tldp.org/HOWTO/Partition/fdisk_partitioning.html">https://www.tldp.org/HOWTO/Partition/fdisk_partitioning.html</a></p>



<p>Once you have the partition created type &#8216;w&#8217; to write it to disk. If you issue the &#8216;sudo blkid&#8217; command again you should see your new partition. In my case the new partition was &#8216;/dev/nvme0n1p1&#8217;.</p>



<p>Now mount the old partition and the new partition.</p>



<p>To do this type</p>



<pre class="wp-block-preformatted">sudo mkdir /mnt/old</pre>



<pre class="wp-block-preformatted">sudo mkdir /mnt/new</pre>



<pre class="wp-block-preformatted">sudo mount /dev/nvme1n1p5 /mnt/old</pre>



<pre class="wp-block-preformatted">sudo mount /dev/nvme0n1p1 /mnt/new</pre>



<p>Now we need to copy the data from the old disk to the new disk. Keep in mind that in my case I had a single partition that kept &#8216;/&#8217;, &#8216;/boot&#8217;, and &#8216;/home&#8217;. If you have separate partitions for those directories then you will need to wither create the same format on your new drive or collapse them onto the single partition during the copy process.</p>



<p>To copy the data do this (preserving permission and owners):</p>



<pre class="wp-block-preformatted">cp -av /mnt/old/.* /mnt/new/</pre>



<p>I use the &#8216;-v&#8217; option so I can check the stream of what is being copied. It may slow down the copy since you are waiting on terminal character buffers in some cases.</p>



<p>Now, you can reboot into the old environment and it is time to update &#8216;grub&#8217; so your system will boot into the new environment.</p>



<p>Once you are logged into your old environment lets update &#8216;grub&#8217;.</p>



<p>Remember, in my scenario /dev/nvme0 is the new disk, /dev/nvme0n1p1 is the new environment, and /dev/nvme1n1p5 is the old environment.</p>



<p>First let mount the new partition:</p>



<pre class="wp-block-preformatted">sudo mkdir /mnt/new</pre>



<pre class="wp-block-preformatted">sudo mount /dev/nvme0n1p1 /mnt/new</pre>



<p>Now we need to mount the efi partition that we identified back in the first steps.</p>



<pre class="wp-block-preformatted">sudo mount /dev/nvme1n1p2 /mnt/new/boot/efi</pre>



<p>The efi partition will be important later. </p>



<p>Now mount using the &#8216;-B&#8217; option to bind the following filesystem into the new environment &#8216;/proc&#8217;, &#8216;/dev&#8217;, &#8216;/dev/pts&#8217;, and &#8216;/sys&#8217;.</p>



<pre class="wp-block-preformatted">mount -B /proc /mnt/new/proc</pre>



<pre class="wp-block-preformatted">mount -B /dev /mnt/new/dev</pre>



<pre class="wp-block-preformatted">mount -B /dev/pts /mnt/new/dev/pts</pre>



<pre class="wp-block-preformatted">mount -B /sys /mnt/new/sys</pre>



<p>Ok, time for the magic. Chroot into the new environment.</p>



<pre class="wp-block-preformatted">sudo chroot /mnt/new</pre>



<p>In the new environment you will run this command to update and install grub on your original volume since you want to keep that grub install.</p>



<pre class="wp-block-preformatted">sudo update-grub</pre>



<pre class="wp-block-preformatted">sudo grub-install /dev/nvme1</pre>



<p>Remember /dev/nvme1 was my original disk and I did not want to change the grub location.</p>



<p>Now you can reboot into the new environment.</p>



<p>After you validate the update you can delete the old install. I did this by booting into my windows environment and deleting the old install and expanding the window partition back to it&#8217;s full 512GB glory.</p>



<p></p>
		]]></content:encoded>
					
					<wfw:commentRss>https://www.robotthoughts.com/2018/12/22/moving-the-root-partition-to-a-new-disk-in-ubuntu-18-10-general-grub-chicanery/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1352</post-id>	</item>
		<item>
		<title>Installation Notes for Kubuntu 18.10 on the Alienware 17 R5 Laptop</title>
		<link>https://www.robotthoughts.com/2018/11/18/installation-notes-for-kubuntu-18-10-on-the-alienware-17-r5-laptop/</link>
					<comments>https://www.robotthoughts.com/2018/11/18/installation-notes-for-kubuntu-18-10-on-the-alienware-17-r5-laptop/#comments</comments>
		
		<dc:creator><![CDATA[Rich Thompson]]></dc:creator>
		<pubDate>Sun, 18 Nov 2018 04:45:45 +0000</pubDate>
				<category><![CDATA[Alienware]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">http://www.robotthoughts.com/?p=1279</guid>

					<description><![CDATA[Before Installation Installing Kubuntu / Ubuntu on the Alienware 17 R5 Laptop NVME Drive To get the NVME drive or M.2 drive to show up as an installation…]]></description>
										<content:encoded><![CDATA[<h3>Before Installation</h3>
<h5>Installing Kubuntu / Ubuntu on the Alienware 17 R5 Laptop NVME Drive</h5>
<p>To get the NVME drive or M.2 drive to show up as an installation candidate for the installer, you need to make a small BIOS change and modify two kernel arguments at boot time.</p>
<p>First, boot into the BIOS on the AW 17 R5. To do this, press F2 when booting up.</p>
<p>Change the SATA setting in the BIOS from RAID to AHCI. Save and exit.</p>
<p>Reboot and press F12 to select the boot disk image. I used a spare USB key as the boot image.</p>
<p>Based on the information from the link below, I needed to load the NVME driver to recognize my M2 drive. To do this I need to follow two steps.</p>
<ol type="1">
<li class="gap">Wait until the UEFI/BIOS has finished loading, or has almost finished. (During this time you will probably see a logo of your computer manufacturer.) Note: UEFI fast boot may be to fast to give time to press any key.<span id="line-8" class="anchor"></span></li>
<li>With BIOS, quickly press and hold the Shift key, which will bring up the GNU GRUB menu. (If you see the Kbuntu logo, you&#8217;ve missed the point where you can enter the GRUB menu.) With UEFI press (perhaps several times) the Escape key to get grub menu.</li>
</ol>
<p>Now that you are in the grub menu, you can edit the kernel parameters. Press &#8216;e&#8217; to edit the kernel parameters.</p>
<p>At the end of the line containing the &#8220;quiet splash &#8212;&#8221; option, add &#8220;nvme_load=YES&#8221; and remove &#8220;quiet splash &#8212;&#8220;.</p>
<p>Press ctrl-X to accept the change and boot into the installer as normal. You should see the NVME drive as an option for installation.</p>
<p>Link information:</p>
<p><a href="https://www.dell.com/support/article/us/en/04/sln299303/loading-ubuntu-on-systems-using-pcie-m2-drives?lang=en">https://www.dell.com/support/article/us/en/04/sln299303/loading-ubuntu-on-systems-using-pcie-m2-drives?lang=en</a></p>
<h3>Installation Notes</h3>
<h5>Do not encrypt, or at least know how to proceed</h5>
<p>During the install, do not choose to encrypt the filesystem. For some reason I cannot fix yet, the password screen is loaded but not visible after a reboot. I can type the password to decrypt the file system as normal, but the process is not visible. After I type the password and press enter, the reboot proceeds and I load into SDDM to select my user and enter my account password.</p>
<h5>Use a USB Mouse</h5>
<p>Also, during the install you will need to use a USB mouse. The trackpad will not work reliably until we make a few changes post install.</p>
<h3>Post Installation</h3>
<h5>Fix the trackpad</h5>
<p>We can fix the trackpad drivers after the install by following the instructions below.</p>
<p>Open a terminal window and type the commands below:</p>
<pre>sudo su
echo 'blacklist i2c_hid' &gt;&gt; /etc/modprobe.d/blacklist.conf
depmod -a
update-initramfs -u</pre>
<p>More detail is available from this link:</p>
<p><a href="https://fzheng.me/2017/05/11/fix-touchpad-ubuntu-1604/">https://fzheng.me/2017/05/11/fix-touchpad-ubuntu-1604/</a></p>
<h5>Fix the Media Keys (X-5 on the left hand side of your keyboard)</h5>
<pre>sudo vi /etc/init.d/keyremap</pre>
<p>Put this text in that file:</p>
<pre>sudo setkeycodes e011 146
sudo setkeycodes e012 148
sudo setkeycodes e013 204
sudo setkeycodes e014 203
sudo setkeycodes e015 149
sudo setkeycodes e016 184</pre>
<p>Save and quit that file.</p>
<p>Then make it executable.</p>
<pre>sudo chmod a+x /etc/init.d/keyremap</pre>
<p>Next step.</p>
<pre>sudo vi ~/.Xmodmap</pre>
<p>Put this text in that file:</p>
<pre>keycode 154 = XF86Launch0
keycode 156 = XF86Launch1
keycode 157 = XF86Launch2
keycode 211 = XF86Launch3
keycode 212 = XF86Launch4
keycode 172 = XF86Launch5</pre>
<p>Save and quit that file.</p>
<p>No create a script you can run on startup. I have a long startup script that sets several items. How you run the startup script is up to you, but put these lines of text in there:</p>
<pre># Run the remap key commands for the Alienware Macro keys
/etc/init.d/keyremap
sudo xmodmap ~/.Xmodmap</pre>
<p>Save and exit the startup scripts</p>
<p>chmod a+x your startup script and ./yourstartupscriptname</p>
<h5>Install NVIDIA Drivers</h5>
<p>Installation of the NVIDIA drivers work like normal on Kubuntu/Ubuntu.</p>
<p>Open a terminal window and type the commands below:</p>
<pre>ubuntu-drivers devices
sudo ubuntu-drivers autoinstall</pre>
<p>The output should look similar to the information below, except I did not need to install the drivers:</p>
<pre>rich@PortableServer:~$ ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00001BE1sv00001028sd0000088Cbc03sc00i00
vendor   : NVIDIA Corporation
model    : GP104M [GeForce GTX 1070 Mobile]
driver   : nvidia-driver-390 - distro non-free recommended
driver   : xserver-xorg-video-nouveau - distro free builtin

rich@PortableServer:~$ sudo ubuntu-drivers autoinstall
[sudo] password for rich: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.</pre>
<p>That should install the correct NVIDIA drivers and they will be active after a reboot.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.robotthoughts.com/2018/11/18/installation-notes-for-kubuntu-18-10-on-the-alienware-17-r5-laptop/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1279</post-id>	</item>
		<item>
		<title>Build a 3D Printed Ukulele</title>
		<link>https://www.robotthoughts.com/2018/10/06/build-a-3d-printed-ukulele/</link>
					<comments>https://www.robotthoughts.com/2018/10/06/build-a-3d-printed-ukulele/#comments</comments>
		
		<dc:creator><![CDATA[Rich Thompson]]></dc:creator>
		<pubDate>Sat, 06 Oct 2018 03:03:31 +0000</pubDate>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[6]]></category>
		<guid isPermaLink="false">http://www.robotthoughts.com/?p=1260</guid>

					<description><![CDATA[I’ve recently been looking at building instruments using a 3D printer. I’ve been playing the guitar for over 40 years but most of the builds for 3D printed…]]></description>
										<content:encoded><![CDATA[<p><a href="https://i0.wp.com/3.18.111.69/wp-content/uploads/2018/10/IMG_0068.jpeg"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter size-large wp-image-1262" src="https://i0.wp.com/3.18.111.69/wp-content/uploads/2018/10/IMG_0068-569x1024.jpeg?resize=569%2C1024" alt="" width="569" height="1024" /></a></p>
<p>I’ve recently been looking at building instruments using a 3D printer. I’ve been playing the guitar for over 40 years but most of the builds for 3D printed guitars seemed a little daunting as a place to start.</p>
<p>I found a couple of 3D printed ukuleles that looked like quicker one day builds. I finally settled on chuckbobuck’s soprano ukulele found on Thingiverse.</p>
<p>I built a few to get started and found that instead of the friction tuning pegs used for his design, I wanted geared tuners. I originally used a drill to widen the mount points for the geared tuners, but that weakened the mount points. Once I had decided on the size of the new holes, I modified the left and right ukulele halves with larger, reinforced mounting holes. I have liked the original design, download those STLS, and then I linked my modified parts.</p>
<p>The parts list and STLs are linked below.</p>
<p>Parts List:</p>
<p>Ukulele Tuning Pegs: <a href="https://amzn.to/2zTJpqI">https://amzn.to/2zTJpqI </a>or <a href="https://amzn.to/2Oz734f">https://amzn.to/2Oz734f</a></p>
<p>Soprano Ukulele Strings: <a href="https://amzn.to/2pD2kAd">https://amzn.to/2pD2kAd</a></p>
<p>M6 x 1MM Hex Lock Nuts: <a href="https://amzn.to/2C1PsLE">https://amzn.to/2C1PsLE</a></p>
<p>M6 x 35MM Bolts: <a href="https://amzn.to/2BWrXU5">https://amzn.to/2BWrXU5</a></p>
<p><a rel="tag" class="hashtag u-tag u-category" href="https://www.robotthoughts.com/tag/6/">#6</a> x 1/2&#8243; Flat Head Wood Screw: <a href="https://amzn.to/2pBSMWa">https://amzn.to/2pBSMWa</a></p>
<p>M6 x 75MM Bolt (Acts as a Truss): <a href="https://amzn.to/2BX1IN8">https://amzn.to/2BX1IN8</a></p>
<p>Ukulele Strap: <a href="https://amzn.to/2Pd2qtt">https://amzn.to/2Pd2qtt</a></p>
<p>Download the STLs:</p>
<p>Original design: <a href="https://www.thingiverse.com/thing:1367923">https://www.thingiverse.com/thing:1367923</a></p>
<p>Modified for geared tuning pegs: <a href="https://www.printables.com/model/19731-modified-ukulele">https://www.printables.com/model/19731-modified-ukulele</a></p>


<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.robotthoughts.com/2018/10/06/build-a-3d-printed-ukulele/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1368</post-id>	</item>
		<item>
		<title>Install Arduino IDE on Ubuntu 18.04</title>
		<link>https://www.robotthoughts.com/2018/09/01/install-arduino-ide-on-ubuntu-18-04/</link>
					<comments>https://www.robotthoughts.com/2018/09/01/install-arduino-ide-on-ubuntu-18-04/#comments</comments>
		
		<dc:creator><![CDATA[Rich Thompson]]></dc:creator>
		<pubDate>Sat, 01 Sep 2018 01:21:09 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Technology]]></category>
		<guid isPermaLink="false">http://robotthoughts.com/?p=1252</guid>

					<description><![CDATA[I had to get an Arduino IDE up and compiling on a Kubuntu 18.04 install. In order to not forget what I did, I made this little post.…]]></description>
										<content:encoded><![CDATA[<p>I had to get an Arduino IDE up and compiling on a Kubuntu 18.04 install. In order to not forget what I did, I made this little post.</p>
<p>This is not super detailed but it should get the job done.</p>
<p>Grad the <a href="https://www.arduino.cc/download_handler.php?f=/arduino-1.8.6-linux64.tar.xz">64-bit version</a> of the Arduino IDE (or the <a href="https://www.arduino.cc/download_handler.php?f=/arduino-1.8.6-linux32.tar.xz">32-bit version</a> if you absolutely need it).</p>
<p>Open a terminal and let&#8217;s do a few things.</p>
<p>Uncompress the software (cd to your Downloads directory) using ark:</p>
<pre>ark arduino-*-linux64.tar.xz</pre>
<p>I moved the resulting folder to /opt so it would not litter up my home directory. You will likely need to use sudo.</p>
<pre>sudo mv arduino-*/ /opt/</pre>
<p>Since we will be working out of that directory now, let&#8217;s move into it.</p>
<pre>cd /opt/arduino*/</pre>
<p>Again, we will leverage sudo to get this installed. Run the install.sh script.</p>
<pre>sudo ./install.sh</pre>
<p>Once the script completes you should have a new electronics category in your Applications menu with the Arduino IDE.</p>
<p>Open the IDE and make sure it opens appropriately. You are not ready to compile and upload to your board yet. We have a few more steps.</p>
<p>Open the preferences in the Arduino IDE (File -&gt; Preferences). Here you can modify the interface scale to make sure you easily read the screen and code.</p>
<p>Now close the IDE and let&#8217;s make sure you can write out across the USB serial line.</p>
<p>Open a terminal again and let&#8217;s look at a few things. First notice that your home directory now has an Arduino directory. Inside that directory is the libraries directory. That is where you put your downloaded arduino libraries if you need to download any. That is outside the scope of this document, but now you know where they go.</p>
<p>You should connect via /dev/ttyUSB0 (or 1 or 2, etc.). To make the Arduino IDE work, we will need to add your user to the dialout group and make sure you can read and write to /dev/ttyUSB0. Here are the commands to do accomplish those tasks.</p>
<pre>sudo usermod -a -G dialout $USER

sudo chmod a+rw /dev/ttyUSB0</pre>
<p>Now reopen your Arduino IDE and compile a sketch. Yuu should be able to write it to your board.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.robotthoughts.com/2018/09/01/install-arduino-ide-on-ubuntu-18-04/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1252</post-id>	</item>
	</channel>
</rss>
