1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MaixCAMにPicoClawをインストール

1
Posted at

最近話題の PicoClawを、数年前にAliexpressで買って積んでいた MaixCAMにセットアップしてみました。
その際のTipsです。

項目 内容
デバイス Sipeed MaixCAM
OS maixcam 2026-01-24-maixpy-v4.12.5
(BusyBox v1.36.1)
init システム init.d (SysVinit スタイル)
メモリ 128MB RAM

1. PicoClaw のセットアップ

  1. https://github.com/sipeed/picoclaw/releases から最新RISC-V向けビルド済みバイナリファイル(例:picoclaw_Linux_riscv64.tar.gz)をダウンロード

  2. 上記.tar.gzファイルを解凍して picoclaw ファイルを入手し、 MaixCAM の/ROOT/ディレクトリに転送
    (MaixVision を使うと簡単)

  3. SSH接続した MaixCAM のターミナルで以下を実行

bash
# バイナリファイルに実行権限を与える
chmod +x picoclaw

# 初期化
./picoclaw onboard

あとは https://github.com/sipeed/picoclaw/blob/main/README.ja.md#-クイックスタートネイティブ を参考にする。

自分の場合は

と連携できるようにした。

2. PicoClaw Discord Gateway 自動起動設定

いちいちコマンドを打ち込んでPicoClawを立ち上げるのが面倒になったら、自動起動用の init.d スクリプトを作成して自動起動化する。
watchdogにより自動でPicoClawを再起動させるシェルスクリプトも併用する。

2.1. PicoClawを再起動させるシェルスクリプトの作成

cat > /root/picoclaw-watchdog.sh << 'EOF'
#!/bin/sh

PICOCLAW=/root/picoclaw
LOG=/var/log/picoclaw-watchdog.log
HEARTBEAT_LOG=/root/.picoclaw/workspace/heartbeat.log
CONFIG=/root/.picoclaw/config.json
HEARTBEAT_TIMEOUT=3600
CHECK_INTERVAL=60

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG"
}

# Extract Discord bot token from config.json (look inside "discord" section)
get_discord_token() {
    grep -A10 '"discord"' "$CONFIG" | grep '"token"' | head -1 | sed 's/.*"token": *"\([^"]*\)".*/\1/'
}

# Extract last known Discord channel ID from heartbeat.log
get_discord_channel() {
    grep -o 'discord:[0-9]*' "$HEARTBEAT_LOG" 2>/dev/null | tail -1 | cut -d: -f2
}

# Send Discord notification via Bot API
notify_discord() {
    MSG="$1"
    TOKEN=$(get_discord_token)
    CHANNEL=$(get_discord_channel)

    if [ -z "$TOKEN" ] || [ -z "$CHANNEL" ]; then
        log "WARN: Discord token or channel not found, skip notification."
        return 1
    fi

    PAYLOAD="{\"content\":\"$MSG\"}"

    if which curl > /dev/null 2>&1; then
        curl -s -o /dev/null \
            -X POST \
            -H "Authorization: Bot $TOKEN" \
            -H "Content-Type: application/json" \
            -d "$PAYLOAD" \
            "https://discord.com/api/v10/channels/$CHANNEL/messages" \
            && log "Discord notification sent (curl)." \
            || log "WARN: Discord notification failed (curl)."
    elif which wget > /dev/null 2>&1; then
        wget -q -O /dev/null \
            --header="Authorization: Bot $TOKEN" \
            --header="Content-Type: application/json" \
            --post-data="$PAYLOAD" \
            "https://discord.com/api/v10/channels/$CHANNEL/messages" \
            && log "Discord notification sent (wget)." \
            || log "WARN: Discord notification failed (wget)."
    else
        log "WARN: Neither curl nor wget available, skip notification."
    fi
}

stop_picoclaw() {
    killall picoclaw 2>/dev/null
    # Clean up orphaned udevadm processes spawned by picoclaw device monitor
    killall udevadm 2>/dev/null
    sleep 2
}

start_picoclaw() {
    log "Starting PicoClaw gateway..."
    HOME=/root nohup $PICOCLAW gateway >> /var/log/picoclaw.log 2>&1 &
    PICOCLAW_PID=$!
    log "PicoClaw gateway started. PID=$PICOCLAW_PID"
    echo "$PICOCLAW_PID" > /var/run/picoclaw.pid
    PICOCLAW_STARTED=$(date +%s)
}

log "Watchdog started."
start_picoclaw

# Wait for PicoClaw to fully initialize, then send startup notification
sleep 15
notify_discord "PicoClaw started on MaixCAM at $(date '+%Y-%m-%d %H:%M:%S')"

while true; do
    sleep "$CHECK_INTERVAL"

    PID=$(cat /var/run/picoclaw.pid 2>/dev/null)

    # Check 1: Is the process alive?
    if [ -z "$PID" ] || ! kill -0 "$PID" 2>/dev/null; then
        log "WARN: PicoClaw process not found. PID=$PID Restarting..."
        stop_picoclaw
        start_picoclaw
        sleep 15
        notify_discord "PicoClaw restarted on MaixCAM (crash recovery) at $(date '+%Y-%m-%d %H:%M:%S')"
        continue
    fi

    # Check 2: Is heartbeat log stale? (process hung)
    # Only check after running at least HEARTBEAT_TIMEOUT to avoid false positives on startup
    NOW=$(date +%s)
    UPTIME=$(expr $NOW - $PICOCLAW_STARTED)
    if [ "$UPTIME" -gt "$HEARTBEAT_TIMEOUT" ] && [ -f "$HEARTBEAT_LOG" ]; then
        LAST_BEAT=$(stat -c %Y "$HEARTBEAT_LOG" 2>/dev/null || echo 0)
        ELAPSED=$(expr $NOW - $LAST_BEAT)
        if [ "$ELAPSED" -gt "$HEARTBEAT_TIMEOUT" ]; then
            log "WARN: Heartbeat stale for ${ELAPSED}s. Killing and restarting..."
            stop_picoclaw
            start_picoclaw
            sleep 15
            notify_discord "PicoClaw restarted on MaixCAM (heartbeat timeout) at $(date '+%Y-%m-%d %H:%M:%S')"
        fi
    fi
done
EOF

2.2. init.d スクリプト作成

bash
cat > /etc/init.d/S99picoclaw << 'EOF'
#!/bin/sh

PICOCLAW=/root/picoclaw
WATCHDOG=/root/picoclaw-watchdog.sh
LOG=/var/log/picoclaw.log
WATCHDOG_LOG=/var/log/picoclaw-watchdog.log

start() {
    echo "Starting PicoClaw watchdog..."
    HOME=/root nohup $WATCHDOG >> $WATCHDOG_LOG 2>&1 &
    echo "PicoClaw watchdog started."
}

stop() {
    echo "Stopping PicoClaw and watchdog..."
    killall picoclaw-watchdog.sh 2>/dev/null
    killall picoclaw 2>/dev/null
    rm -f /var/run/picoclaw.pid
    echo "PicoClaw stopped."
}

case "$1" in
    start)   start ;;
    stop)    stop ;;
    restart) stop; sleep 2; start ;;
    *) echo "Usage: $0 {start|stop|restart}" ;;
esac
EOF

HOME=/root の明示が必須。これがないと ~/.picoclaw/config.json が見つからず起動失敗する。

2.3. 実行権限を与える

bash
ssh root@<MaixCAMのIP> "chmod +x /root/picoclaw-watchdog.sh && chmod +x /etc/init.d/S99picoclaw && sed -i 's/\r//' /root/picoclaw-watchdog.sh"

2.4. 動作確認

bash
# 手動起動テスト
/etc/init.d/S99picoclaw start

# ログ確認
tail -f /var/log/picoclaw.log

# プロセス確認
ps | grep picoclaw

正常起動時のログ例:

bash
[INFO] channels: Starting channel {channel=discord}
[INFO] discord: Starting Discord bot
[INFO] discord: Discord bot connected {username=MaixCAM-PicoClaw}
[INFO] channels: All channels started
✓ Health endpoints available at http://0.0.0.0:18790/health and /ready

2.3. 再起動後の確認

bash
reboot

# 再起動後
ps | grep picoclaw
tail /var/log/picoclaw.log

3. tailscale のセットアップ・自動起動

ローカルネットワーク外からもアクセスできるように、tailscale をセットアップして自動起動できるようにする。

3.1. セットアップ

  1. https://pkgs.tailscale.com/stable/#static から、から最新RISC-V向けビルド済みバイナリファイル(例:tailscale_1.94.2_riscv64.tgz)をダウンロード

  2. 上記.tar.gzファイルを解凍して tailscale ファイルと tailscaled ファイルを入手し、 MaixCAM の/usr/bin/ディレクトリに転送
    (MaixVisionでは無理なので、scpコマンドを使う)

    bash
    $ scp tailscale_1.94.2_riscv64/tailscale root@192.168.x.x:/usr/bin/
    $ scp tailscale_1.94.2_riscv64/tailscaled root@192.168.x.x:/usr/bin/
    
  3. SSH接続した MaixCAM のターミナルで以下を実行

    bash
    tailscaled --state=/var/lib/tailscale/tailscaled.state
    tailscale up
    

    認証URLが表示されるので、ブラウザで開いて tailscale アカウントで認証。

3.2 自動起動化

以下で自動起動用の init.d スクリプトを作成

bash
cat > /etc/init.d/S98tailscale << 'EOF'
#!/bin/sh

TAILSCALED=/usr/bin/tailscaled
TAILSCALE=/usr/bin/tailscale
STATE_DIR=/var/lib/tailscale

start() {
    echo "Starting tailscaled..."
    mkdir -p $STATE_DIR
    $TAILSCALED --state=$STATE_DIR/tailscaled.state &
    sleep 2
    $TAILSCALE up
    echo "tailscaled started."
}

stop() {
    echo "Stopping tailscaled..."
    killall tailscaled 2>/dev/null
    echo "tailscaled stopped."
}

case "$1" in
    start) start ;;
    stop)  stop ;;
    restart) stop; sleep 1; start ;;
    *) echo "Usage: $0 {start|stop|restart}" ;;
esac
EOF

# 実行権限を与える
chmod +x /etc/init.d/S98tailscale

3.3. (備考)起動シーケンスまとめ

init.d のスクリプトはファイル名の番号順に実行される。

スクリプト 内容
S98tailscale Tailscale VPN デーモン起動
S99picoclaw PicoClaw Discord Gateway 起動

4. メモリ対策

4.1. 事前確認

(PicoClawを立ち上げていない状態で)実機でメモリ使用量を確認した結果、既に空き容量が4MBしかなかったので、Swap ファイルを作成してメモリを空ける。

bash
# メモリ使用量確認
free -h
              total        used        free      shared  buff/cache   available
Mem:         127.8M       63.2M        5.7M      316.0K       58.9M       57.1M
Swap:             0           0           0

# プロセスごとのメモリ使用量確認
ps -o pid,comm,vsz,rss | sort -k4 -rn | head -20

主なメモリ使用プロセス(実測値)

プロセス RSS
tailscaled 37MB
launcher 13MB
sshd 5MB
wpa_supplicant 4MB
bluetoothd 2.6MB
vsftpd 1.9MB

4.2. Swap ファイル作成

tailscaled が 37MB 使用するため、Swap ファイルを作って逃がす

bash
# 128MB の Swap ファイル作成
dd if=/dev/zero of=/swapfile bs=1M count=128
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# 確認
free -h

# 再起動後も有効化(fstab に追記)
echo "/swapfile swap swap defaults 0 0" >> /etc/fstab

4.3. 結果

bash
free -h
              total        used        free      shared  buff/cache   available
Mem:         127.8M       64.0M        4.5M      320.0K       59.2M       57.9M
Swap:        128.0M           0      128.0M

5. スキルの開発

スキルを実装することで、ある特定のワードをトリガーにPythonやシェルスクリプトを発動させることができる。

フォーマットは https://github.com/sipeed/picoclaw/blob/main/workspace/skills/skill-creator/SKILL.md を参考

6. その他もろもろ

記事にするのめんどくさくなったのでGitHubのリポジトリを見て。
Discodeと連携して、MaixCamで撮った画像をDiscodeのチャンネルに送ったりする方法を実装してる。

ちなみに自分がやった作業はClaude.mdに方針を示してClaudeCodeに指示を与えただけ。
ssh接続してMaixCAM内のファイル操作は基本的にClaudeCodeにやってもらってる。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?