Luapico
A programming environment for Lua for the Raspberry Pi Pico microcontroller
Install / Use
/learn @kevinboone/LuapicoREADME
picolua
A programming environment for Lua for the Raspberry Pi Pico microcontroller.
Version 0.3, April 2021
What is this?
picolua is a proof-of-concept Lua programming environment for the Pi
Pico. As well as the Lua run-time, it includes a rudimentary
shell that accepts Linux-like commands, a full-screen editor,
and basic file management facilities. picolua is designed to be
operated by connecting the Pico's USB to a terminal emulator.
Lua functions have been added for controlling the Pico's GPIO
and other peripherals.
As a result, it is possible to enter and run simple programs that
manipulate connected devices, without the need for any particular
development tools. There is support for general digital input/output,
analog input, PWM output, and I2C.
picolua has some conceptual similarities with MicroPython on the
Pico. However, picolua is designed to be completely self-contained,
in that no addition tools (other than a terminal) are required to
create, edit, and test programs. It's possible (to some extent) to
create and test Lua code on a workstation, and then upload it to the
Pico. However, this isn't necessary -- picolua is capable of
being self-contained.
picolua maintains a filesystem in the Pico's flash ROM, that can store
multiple files, perhaps organized into directories.
There is a rudimentary command-line shell that provides a few Unix-like commands, for copying, viewing, and deleting files; and, of course, for running Lua code.
Most of the standard Lua features are available, except those that
interact with an operating system. The Lua file handling routines
have been replaced by alternatives specific to the picolua
filesystem.
The shell
On startup, you will see the shell prompt $. I've used the dollar sign
here to distinguish it from the Lua > prompt, and because the shell
is a little like a Unix shell. There is a basic line editor
for entering shell commands; these commands are similar to Unix shell commands
-- cp, rm, mv, etc. The shell supports wilcard expansion ("globbing"),
with the ? character matching any single character, and * matching any number
of characters. So it's possible, and sometimes useful, to run
commands like cp *.lua /backup. There is a full list of shell
commands below.
As in Unix shells, any line that starts with a # is taken to be a
comment. This is only useful in scripts (see below).
Running Lua on picolua
There are various ways to run Lua in picolua.
-
Create the Lua file using the built-in editor, or upload it from a terminal using the YModem protocol (described below). Then run it using the shell command
lua {filename}. -
Run the Lua file directly from the editor, by hitting the Ctrl+
key combination. -
Start an interactive Lua session by running
luaat the shell prompt. You can enter Lua code directly at the Lua prompt. From this prompt you can also invoke the editor, usingpico.edit "filename". -
Run
lua -e "lua code..."at the shell prompt. -
If the Lua file is in a directory which is in the search path (see "Search path" below), then you can just type the name at the prompt, without the
.luaextension. So you can run '/bin/blink.lua' just be enteringblink. -
Lua files can be grouped into modules, and executed using the
require()function -- see "Lua modules" below.
Notes about the Lua implementation
picolua is based on Lua 5.4, and this will probably not change,
given the number of changes that I had to make to it.
On start-up, picolua enters interactive mode. You can enter expressions,
which are evaluated and displayed, or run a program using dofile or
require. At the Lua prompt, you can invoke the (rudimentary)
screen editor using
edit "file.lua". One change from the conventional Lua interactive mode
is that if the result is a table, the contents are displayed. This makes
it possible to provide "commands" like ls "/dir" and df() -- these return
a table, which gets displayed.
Standard Lua has only one numeric data type (at least, one only one
that is accessible outside the Lua runtime). It can be set at compile
time, but then it's fixed. At present, it is set to double
-- double-precision
floating-point. Many functions in the Pico interface of necessity take
integer arguments. A GPIO pin number, for example, can only be an
integer. Care needs to be take if using the results of calculations
as arguments to these functions. At the time of writing, the Pico
SDK includes double-precision floating-point support more-or-less
as a matter of course, so there's little to be gained by trying to
use lower precision.
The implementation uses one Lua context for the whole runtime.
So any functions defined, or variables set, by executing a Lua file
(e.g, by using dofile "file.lua") remain in effect. This is nearly
always the expected behaviour.
As in regular Lua, a file can be loaded using
dofile "file.lua" and require "file". There are subtle differences
between these methods, that are described in the Lua documentation,
and apply here too. Here, though, there's little need to use
require, because there isn't a file search path.
Like all Lua functions, the Pico functions can be used without brackets
when there is a single string argument. So it's correct to write
edit "test.lua" as well as edit ("test.lua"). Although these
functions are defined in a library called pico, and should probably
be written pico.edit, pico.ls, etc., they are also defined in the
global namespace as well, just for convenience.
Since there is no underlying shell, some of the Pico-specific functions provide shell-like functionality. There are functions for editing and copying files, for example, and querying system status.
Interrupts
Sending Ctrl+C should interrupt a running program. The same key is used to abandon a line in the line editor. Ctrl+C is not used to exit the screen editor; in fact, it has no function there -- not even "copy". See the Screen editor section for more information.
The filesystem
picolua maintains a filesystem in the PICO's flash memory. Filesystem
storage starts a little after the program code, and extends, more-or-less
to the end of the flash memory.
When you flash a .uf2 file on the Pico, only the flash areas specified
in the file are re-written. Consequently, and intentionally,
the picolua filesystem will survive re-flashing the program itself.
The filesystem supports files and directories, with names up to 255 characters. It has no notion of file permissions, ownership, timestamps, or links. This is to reduce the amount of storage used per file to a minimum.
Line editor
The line editor responds to cursor movement and backspace (delete on some keyboards) keys. Ctrl+Left and Ctrl+Right move the cursor by whole words. Ctrl+Home and Ctrl+End move the cursor to the start and end of the line respectively
Up-arrow and down-arrow scroll through a history of previous lines. By default, the history is limited to the last four lines. The line editor is nowhere near as sophisticated as that found in most Linux shells -- but it's a lot smaller.
Screen editor
The screen editor is fairly rudimentary, and designed specifically to operate from a serial terminal. Some of the key bindings are not very conventional, because I've tried to avoid key combinations that are taken over by terminal emulators and window managers.
The editor is invoked initially by running edit "filename".
Thereafter, further files can be opened by sending Ctrl+O and
entering a filename. If multiple files are open, you can
switch between them using Ctrl+E.
To get a list of key bindings, send Ctrl+@. It would have been nice use Ctrl+H (for "help") but Ctrl+H usually generates a "backspace" keycode.
There are a few oddities that might be worth mentioning.
-
The key combination Ctrl+\ executes the file in the editor as a Lua program.
-
The usual Ctrl+C for "copy" has been replaced by Ctrl-Y, because I wanted to reserve the Ctrl+C combination for an interrupt throughout the environment.
-
If text is selected, the tab key indents the text two spaces. Shift-tab unindents by the same amount. If nothing is selected, the tab key simple enters a tab character.
-
The editor auto-indents using spaces. At present, this behaviour can't be turned off
Shell scripts
picolua does not have well-developed shell script support, because it's
unnecessary -- you can run shell commands, should there be a need to,
from a Lua script.
However, picolua does have a rudimentary notion of a shell script. A
script if a file containing shell commands, one to each line. The shell
will process the script line by line to the end, or until some command
raises an error.
This facility is mostly intended for initialization.
Command-line arguments
When you run a Lua program from the shell prompt, you can pass command-line arguments if necessary. This mechanism works in Lua the same in regular Lua.
So we can execute a LUa program like this:
$ lua bin/myprog.lua hello world
or
$ myprog hello world
and in both cases the arguments "hello" and "world" are available in
the Lua program as arg[1] and arg[2]. By convention,
arg[0] is the name of the program.
Search path
The picolua shell has a rudimentary knowledge of search path. At start-up,
the path consists (only) of the directory /bin. Any Lua file placed
in that directory, with a name ending in .lua, can be executed at the
shell prompt simply by entering the name, without the extension. So
instead of entering lua /bin/blink.lua, we can enter blink.
The same principle applies to shell scripts. A shell script can be
executed by entering only its name, if it is in the /bin directory,
and has a name endring in .sh.
Lua modules
picolua supports Lua modules, as ordinary Lua does. However, the module
search path contains
Related Skills
node-connect
336.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
336.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
82.9kCommit, push, and open a PR
