特别感谢文章作者:周工,辛苦制作的教程,非常适合新人及树莓派爱好者学习使用!
一、项目简介
本项目实现了在 Raspberry Pi Compute Module 0 (CM0) 上调用 火山引擎豆包大模型(Ark 平台) 的文本生成功能,并将生成的诗句显示到 0.96 英寸 SSD1306 OLED 屏幕(I²C 接口) 上。
该项目涵盖:
云端 AI 调用;
虚拟环境搭建;
I²C 屏幕驱动;
错误调试;
远程开发部署。
二、硬件环境
⚠️ 注意:部分系统或 Adafruit_Blinka 库会自动识别为 CM1,这是正常现象,不影响功能。我们仍在代码中声明实际板型为 CM0 以保持一致。
export BLINKA_FORCEBOARD=RASPBERRY_PI_CM1
三、软件环境
四、环境搭建步骤
1. 创建 Python 虚拟环境
cd ~/Desktop/workspacepython3 -m venv venvsource venv/bin/activate
2. 安装依赖(使用国内镜像)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade "volcengine-python-sdk[ark]"pip install -i https://pypi.tuna.tsinghua.edu.cn/simple adafruit-circuitpython-ssd1306 pillow adafruit-blinka
3. 配置 API Key
export ARK_API_KEY="你的火山引擎API密钥"
建议把这行加入 ~/.bashrc,让系统开机自动加载。
五、开发与远程调试
1. 通过 VS Code Remote-SSH 连接
安装插件:Remote - SSH
连接开发板:ssh xiaozhou@<树莓派IP>
进入工作目录:~/Desktop/workspace
激活虚拟环境后执行:python3 oled_test.py
🧠 技巧:可在 /etc/ssh/ssh_config 或 Windows ~/.ssh/config 中保存密码实现自动登录。
六、AI 调用与 OLED 显示代码
# -*- coding: utf-8 -*-import osimport timeimport boardimport busiofrom PIL import Image, ImageDraw, ImageFontimport adafruit_ssd1306from volcenginesdkarkruntime import Ark# ==============================# OLED初始化(适配CM0的I2C总线)# ==============================def init_oled():WIDTH = 128HEIGHT = 64I2C_ADDR = 0x3C # 你的OLED地址I2C_BUS = 1 # 树莓派CM1的I2C默认总线为1(与物理引脚SDA=2, SCL=3对应)try:# 初始化CM0的I2C总线i2c = busio.I2C(board.SCL, board.SDA) # 自动映射到CM1的I2C引脚oled = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=I2C_ADDR)oled.fill(0)oled.show()image = Image.new("1", (WIDTH, HEIGHT))draw = ImageDraw.Draw(image)font = ImageFont.load_default(size=12) # 英文默认字体return oled, image, draw, fontexcept Exception as e:print(f"OLED初始化失败:{e}")return None, None, None, None# ==============================# OLED显示函数(英文适配)# ==============================def display_on_oled(oled, image, draw, font, text):if not all([oled, image, draw, font]):returnoled.fill(0)draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)line_height = 14max_width = oled.width - 4lines = []words = text.split()current_line = ""for word in words:if draw.textlength(f"{current_line} {word}", font=font) < max_width:current_line = f"{current_line} {word}".strip()else:lines.append(current_line)current_line = wordif current_line:lines.append(current_line)y = 0for line in lines[:4]: # 0.96寸最多显示4行draw.text((2, y), line, font=font, fill=255)y += line_heightoled.image(image)oled.show()# ==============================# AI客户端与回复处理# ==============================def init_ai_client():try:return Ark(base_url="https://ark.cn-beijing.volces.com/api/v3",api_key=os.environ.get("ARK_API_KEY"))except Exception as e:print(f"AI客户端初始化失败:{e}")return Nonedef get_ai_reply(ai_client, model_id, user_input):try:prompt = f"User's question: {user_input}nReply ONLY in English, concise (max 4 lines)."completion = ai_client.chat.completions.create(model=model_id,messages=[{"role": "user", "content": [{"type": "text", "text": prompt}]}])content = completion.choices[0].message.contentreturn content[0]["text"].strip() if (isinstance(content, list) and len(content) > 0 and "text" in content[0]) else str(content).strip()except Exception as e:return f"Error: {str(e)[:15]}"# ==============================# 主逻辑# ==============================if __name__ == "__main__":# 打印板型声明信息(验证是否生效)print(f"当前声明的板型:{os.environ.get('BLINKA_BOARD')}")oled, image, draw, font = init_oled()ai_client = init_ai_client()model_id = "doubao-seed-1-6-251015" # 替换为你的模型IDif not ai_client:print("AI客户端初始化失败,程序退出")exit(1)if not oled:print("OLED初始化失败,仅命令行模式运行")print("===== CM0 AI-OLED 助手 =====")print("提示:输入内容按回车发送,输入'q'或'退出'结束")if oled:display_on_oled(oled, image, draw, font, "RPi CM0 Ready")time.sleep(2)try:while True:user_input = input("n请输入问题:").strip()if user_input.lower() in ["q", "退出"]:print("对话结束")if oled:display_on_oled(oled, image, draw, font, "Bye!")time.sleep(2)oled.fill(0)oled.show()breakif not user_input:print("输入不能为空")if oled:display_on_oled(oled, image, draw, font, "No empty input")time.sleep(1.5)continueprint("AI replying...")if oled:display_on_oled(oled, image, draw, font, "Thinking...")time.sleep(0.5)ai_reply = get_ai_reply(ai_client, model_id, user_input)print(f"AI Reply: {ai_reply}")if oled:display_on_oled(oled, image, draw, font, ai_reply)time.sleep(5)except KeyboardInterrupt:print("n程序中断")if oled:oled.fill(0)oled.show()except Exception as e:print(f"错误:{e}")if oled:display_on_oled(oled, image, draw, font, "Error")time.sleep(3)oled.fill(0)oled.show()
七、运行项目
source venv/bin/activatepython3 oled_ai_display.py
屏幕显示示例:
星落满肩时,夜便有了重量。
八、调试与问题记录
1️⃣ 模块缺失错误,报错:
ModuleNotFoundError: No module named 'httpx'
解决:
pip install httpx
2️⃣ IndentationError(缩进错误)
原因: Python 中 for 循环后未缩进。
解决: 检查所有 for / if / try 语句后的缩进对齐。
3️⃣ InternalServerError (500),报错:
volcenginesdkarkruntime._exceptions.ArkInternalServerError: Error code: 500
原因: 火山引擎模型端短时异常。
解决: 稍后重试,或更换模型 ID。
4️⃣ OLED 无显示
排查步骤:
检查 I²C 地址是否为 0x3C;
执行 i2cdetect -y 1 确认屏幕是否被识别;
确认电源与地线连接正确。
5️⃣ Remote-SSH 登录繁琐
解决方案:在 Windows/Linux 的 SSH 配置中保存:
Host cm0HostName 192.168.x.xUser xiaozhouIdentityFile ~/.ssh/id_rsa
然后直接执行:
ssh cm0
6️⃣ pip 下载缓慢
解决: 使用清华镜像:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名
7️⃣ API Key 读取为空,现象:
api_key=os.environ.get("ARK_API_KEY") 返回 None
解决:手动导出或添加到 .bashrc:
export ARK_API_KEY="xxxxxxxx"source ~/.bashrc
九、运行效果与扩展方向
| 功能 | 状态 |
| AI 文本生成 | ✅ 正常 |
| OLED 显示 | ✅ 正常 |
| 网络访问 | ✅ Ping 通 |
| Remote-SSH 调试 | ✅ 支持 |
| 文生图 / 图生文 | 可扩展 |
扩展建议:
定时刷新新诗句;
加入语音输入模块;
在 OLED 上滚动长文本;
增加按键交互触发 AI 对话。
十、总结
本项目成功实现了在 树莓派 CM0 上使用 火山引擎豆包 AI 进行自然语言生成,并通过 OLED 屏幕 实时显示结果。
官方网站:https://edatec.cn/zh/cm0
淘宝店铺:https://edatec.taobao.com/
1026