VSCode开发K230,实现代码补全、烧录运行
环境需求
- CanMV IDE(非必须,但是基本都有吧)
- K230 开发板
- vscode(没安装可以参考2024 在 Windows 安装 VSCode_将”通过 code 打开”操作添加到 windows 资源管理器文件上下文菜单-CSDN 博客)
- conda(非必须,但推荐。没安装可以参考2024 在 Windows/Linux 使用 AnaConda/MiniConda 安装 Pytorch_windows conda pytorch-CSDN 博客)
引言
众所周知,CanMV IDE 中没有对代码的自动补全,以及编码体验还有待提高,而 Vscode 中编码因为缺少 micropython 库的支持导致频繁报红线错误影响体验。所以本文将带你从 0 开始配置一个 vscode 编写 K230 代码的环境。

获取官方 API
要在 vscode 中实现代码补全,首先需要把 K230 中的 MicroPython API 获取出来,这里使用的是 UP 主的代码并根据官方 API 手册尽量添加了所有 API
import gc
import os
import sys
# --- 1. 配置 ---
SAVE_ROOT = "/sdcard/k230_full_stubs"
# 普通单文件模块列表
SINGLE_MODULES = [
"_thread",
"aidemo",
"array",
"audio",
"binascii",
"camera",
"cmath",
"collections",
"cv_lite",
"display",
"errno",
"fpioa_manager",
"fft",
"gc",
"hashlib",
"heapq",
"image",
"io",
"i2c",
"i2c_salve",
"json",
"kpu",
"machine",
"maix",
"math",
"multimedia",
"neopixel",
"network",
"nncase_runtime",
"nonai2d",
"np",
"os",
"pin",
"pwm",
"random",
"re",
"rtc",
"rtt_interface",
"select",
"sensor",
"socket",
"spi",
"spi_lcd",
"ssl",
"struct",
"sys",
"time",
"touch",
"uart",
"ujson",
"ubinascii",
"ucollections",
"uctypes",
"uerrno",
"uhashlib",
"uheapq",
"uio",
"ure",
"urandom",
"ustruct",
"utime",
"uzlib",
"video",
"wdt",
"zlib",
"Ucryptolib",
"uos",
"usb",
"mpp",
]
# 包结构模块:key 为包名(小写),value 为子模块名(小写)
PACKAGE_MODULES = {
"libs": ["AI2D", "AIBase", "PipeLine", "utils", "YOLO"],
"ulab": ["numpy"],
"mpp": ["payload_struct"],
# media 也作为包处理
"media": [
"audio",
"camera",
"display",
"image",
"maix",
"media",
"sensor",
"vencoder",
"video",
"wave",
"player",
"mp4format",
"pyaudio",
"vdecoder",
"uvc",
],
}
# --- 2. 初始化环境 ---
def ensure_dir(path):
try:
os.mkdir(path)
except:
pass
print(f"Target Directory: {SAVE_ROOT}")
ensure_dir(SAVE_ROOT)
# --- 3. 核心写入函数 (通用) ---
def write_item(f, name, obj, indent_lvl=0):
indent = " " * indent_lvl
if name.startswith("__"):
return
try:
obj_type = str(type(obj))
# 函数/方法
if "function" in obj_type or "method" in obj_type:
f.write(
f"{indent}def {name}(*args, **kwargs):\n{indent} pass\n\n"
)
# 类 (递归写入类成员)
elif "class" in obj_type or "type" in obj_type:
f.write(f"{indent}class {name}:\n")
members = dir(obj)
has_member = False
for m in members:
if not m.startswith("__"):
try:
has_member = True
# 递归调用自己来写类里面的方法/属性
val = getattr(obj, m)
write_item(f, m, val, indent_lvl + 1)
except:
pass
if not has_member:
f.write(f"{indent} pass\n")
f.write("\n")
# 模块 (作为类处理,用于单文件生成模式)
elif "module" in obj_type:
# 只有在非包模式下才把模块写成类
f.write(f"{indent}class {name}:\n")
for m in dir(obj):
if not m.startswith("__"):
try:
write_item(f, m, getattr(obj, m), indent_lvl + 1)
except:
pass
f.write(f"{indent} pass\n\n")
# 变量/常量
elif "int" in obj_type:
f.write(f"{indent}{name} = {obj}\n")
elif "str" in obj_type:
f.write(f"{indent}{name} = '{obj}'\n")
elif "list" in obj_type:
f.write(f"{indent}{name} = []\n")
elif "dict" in obj_type:
f.write(f"{indent}{name} = {{}}\n")
else:
f.write(f"{indent}{name} = None\n")
except:
pass
# --- 4. 生成普通单文件模块 (os.py, sys.py 等) ---
def generate_single_file_stubs():
print("--- Phase 1: Generating Standard Libraries ---")
for mod_name in SINGLE_MODULES:
# 跳过 media 相关,由 Phase 2 处理
if mod_name.startswith("media"):
continue
print(f"--> Processing: {mod_name}")
try:
mod = __import__(mod_name)
path = f"{SAVE_ROOT}/{mod_name}.py"
with open(path, "w") as f:
f.write(f'"""Stub file for {mod_name}"""\n\n')
for attr in dir(mod):
write_item(f, attr, getattr(mod, attr), 0)
except ImportError:
print(f" Skipped (Not found)")
except Exception as e:
print(f" Error: {e}")
gc.collect()
# --- 5. 生成 包结构 ---
def generate_package_stubs():
print("\n=== Phase 2: Generating Package Structures ===")
for pkg_name, sub_list in PACKAGE_MODULES.items():
print(f"\n--- Generating package: {pkg_name} ---")
pkg_dir = f"{SAVE_ROOT}/{pkg_name}"
ensure_dir(pkg_dir)
# 1) 生成 __init__.py
init_path = f"{pkg_dir}/__init__.py"
print(f"--> Writing {init_path}")
try:
pkg = __import__(pkg_name)
with open(init_path, "w") as f:
f.write(f'"""Stub for top-level {pkg_name} package"""\n\n')
for attr in dir(pkg):
write_item(f, attr, getattr(pkg, attr), 0)
except ImportError:
print(" Error: media module not found!")
return
# 5.2 生成子模块文件
for sub in sub_list:
module_name = f"{pkg_name}.{sub}"
file_path = f"{pkg_dir}/{sub}.py"
print(f"--> Generating {module_name}")
try:
exec(f"import {module_name} as m_sub")
m_sub = locals()["m_sub"]
with open(file_path, "w") as f:
f.write(f'"""Stub for {module_name}"""\n\n')
for attr in dir(m_sub):
write_item(f, attr, getattr(m_sub, attr), 0)
print(f" Saved: {file_path}")
except ImportError:
print(f" Skipped (Not found): media.{sub}")
except Exception as e:
print(f" Error: {e}")
gc.collect()
# --- 主程序入口 ---
if __name__ == "__main__":
print("Pre-loading key modules...")
generate_single_file_stubs()
generate_package_stubs()
print("\n================ DONE ================")
print(f"Stubs saved to: {SAVE_ROOT}")
print("Please download this folder to your PC.")
将代码拷贝到一个文件,在 CanMV IDE 中打开文件,连接上 K230 运行

完成后,可以在资源管理器中打开 K230 的 SD 卡,找到 mtp://CanMV/sdcard/k230_full_stubs 文件夹,随便点击一个 py 文件查看是有函数生成如图所示即代表成功。

如果想要增加某个模块的 API,自行加入到 SINGLE_MODULES 或 PACKAGE_MODULES 里,打开 CanMV IDE 再运行即可。
创建虚拟环境
因为 K230 使用的是 micropython,且 API 大部分供 K230 使用就可以了,所以这里先使用 miniconda 创建一个 K230 的虚拟环境,防止破坏其他环境。
创建完虚拟环境后,会输出环境的路径,在资源管理器中打开这个路径,打开其下面的 Lib\site-packages 文件夹,我这里是(E:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages)。

把 K230SD 卡中的 k230_full_stubs 文件夹里面整个复制到 site-packages 里面去。文件结构如下图
E:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\
libs/
media/
os.py
machine.py
...
放置完后,可以在环境中输入下面的指令测试是否有异常
python -c "import machine; print(machine)"
python -c "import media.display; print(media.display)"
python -c "import libs.ai2d; print(libs.ai2d)"
像下图中所示,说明正确导入了每个模块。

打开 vscode,安装上 python 必要插件后,选择安装的 K230 虚拟环境。创建一个新 py 文件。

此时再输入一些 MicroPython 的 API,就可以自动补全了。

烧录运行
在vscode中烧录运行K230的程序,作者已更新,现在直接在插件中搜索"CanMV Flasher"下载并安装即可。我们只需要将扩展拖入安装即可。安装后点击左下角选择python编译器,也就是刚才创建的虚拟环境的编译器,可以在环境中输入 where python ,正常情况下第一行的路径就是虚拟环境的编译器路径。然后打开 设备管理器 ,找到K230的端口号,输入到左下角就行。

报错
当点击运行或者烧录的时候出现下面错误,在 CanMV IDE 中断开连接。
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "e:\ProgramFiles\Miniconda\envs\K230\Scripts\ampy.exe\__main__.py", line 6, in <module>
sys.exit(cli())
~~~^^
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\click\core.py", line 1485, in __call__
return self.main(*args, **kwargs)
~~~~~~~~~^^^^^^^^^^^^^^^^^
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\click\core.py", line 1406, in main
rv = self.invoke(ctx)
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\click\core.py", line 1870, in invoke
super().invoke(ctx)
~~~~~~~~~~~~~~^^^^^
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\click\core.py", line 1269, in invoke
return ctx.invoke(self.callback, **ctx.params)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\click\core.py", line 824, in invoke
return callback(*args, **kwargs)
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\ampy\cli.py", line 99, in cli
_board = pyboard.Pyboard(port, baudrate=baud, rawdelay=delay)
File "e:\ProgramFiles\Miniconda\envs\K230\Lib\site-packages\ampy\pyboard.py", line 147, in __init__
raise PyboardError('failed to access ' + device)
ampy.pyboard.PyboardError: failed to access \\.\COM12

浙公网安备 33010602011771号