Upgrade to Pro — share decks privately, control downloads, hide ads and more …

生成AIとPythonで
ラズパイカーを動かそう! 〜GradioとLangChainで作るプ...

Avatar for komo_fr komo_fr
February 19, 2026
100

生成AIとPythonで
ラズパイカーを動かそう! 〜GradioとLangChainで作るプロトタイプ〜

2026/2/19開催の「みんなのPython勉強会#120」での発表資料です。
個人で気軽に試せる趣味プロジェクトの例として、生成AIを使った、音声や画像で操作できるRaspberry Pi Pico搭載の小さな車を紹介。実際のコードを交えて、仕組みや利用しているライブラリ(LangChain、Gradio、Microdot など)を説明しました。

イベントページ:
https://startpython.connpass.com/event/382895/

GitHub:
https://github.com/komo-fr/llm-pico-car

X(Twitter):
https://x.com/komo_fr

Avatar for komo_fr

komo_fr

February 19, 2026
Tweet

More Decks by komo_fr

Transcript

  1. 9!LPNP@GS w ੜ੒"*Λ࢖͑͹ɺࣗવݴޠˠߏ଄Խ͞Εͨࢦࣔσʔλʹ؆୯ʹม׵Ͱ͖ͦ͏ w ϓϩϯϓτͷΠϝʔδ ʮࣗવݴޠʹΑΔࢦࣔΛɺࣙॻͷϦετܗࣜͰίϚϯυʹม׵͠ͳ͍͞ʯ ·͙ͬ͢ߦͬͯ ӈʹۂ͕ͬͯʂ [ {

    "action": { "type": "forward", "distance_cm": 20,}}, { "action": { "type": "turn", "direction": "right", "angle": 90,}}, ...] ࣗવݴޠ ߏ଄Խ͞ΕͨࢦࣔσʔλʢࣙॻͷϦετʣ લʹDNਐΉ ӈʹ౓ճస ੜ੒"* ΞΠσΞ ԿΛ࡞ͬͨͷ͔
  2. 9!LPNP@GS 8FCΞϓϦ͔Β Ի੠Λೖྗ ίϚϯυΛड৴  ࣮ߦ Ի੠Λจࣈى͜͠  ੜ੒"*Ͱࢦࣔσʔλʹม׵ Ի੠σʔλ

    ߏ଄Խ͞Εͨ ࢦࣔσʔλ 4UFQ 4UFQ 4UFQ શମͷߏ੒ Ͳ͏࡞ͬͨͷ͔ εϚϗͳͲͷ 8FCϒϥ΢β 1JDP$POUSPMMFS4FSWFS ʢ.BDʣ 1JDP$BS4FSWFS ʢ3BTQCFSSZ1J1*DP$BSʣ
  3. 9!LPNP@GS εϚϗͳͲͷ 8FCϒϥ΢β 1JDP$POUSPMMFS4FSWFS ʢ.BDʣ 1JDP$BS4FSWFS ʢ3BTQCFSSZ1J1*DP$BSʣ 8FCΞϓϦ͔Β Ի੠Λೖྗ ίϚϯυΛड৴

     ࣮ߦ Ի੠Λจࣈى͜͠  ੜ੒"*Ͱࢦࣔσʔλʹม׵ Ի੠σʔλ ߏ଄Խ͞Εͨ ࢦࣔσʔλ 4UFQ 4UFQ 4UFQ 4UFQ8FCΞϓϦ͔ΒԻ੠Λೖྗ
  4. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Audio Instructions"): # ίϯϙʔωϯτΛ഑ஔ audio_input = gr.Audio( sources=["microphone"], type="filepath", format="wav") with gr.Row(): audio_send_button = gr.Button("Submit", variant="primary") audio_reset_button = gr.Button("Reset", variant="secondary") ... # ΠϕϯτΛઃఆ audio_send_button.click(handler_audio_input, inputs=audio_input, outputs=[audio_transcript_output, audio_commands_output, audio_status_output, progress_lamps,],) ... # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) HS"VEJP HS#VUUPO HS#VUUPO HS5FYUCPY HS5FYUCPY HS+40/ TUSVDUVSFEBDUJPOT ίʔυ(SBEJP#MPDLT HS)5.-  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ
  5. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ audio_input = gr.Audio( sources=["microphone"], type="filepath", format="wav") with gr.Row(): audio_send_button = gr.Button("Submit", variant="primary") audio_reset_button = gr.Button("Reset", variant="secondary") audio_transcript_output = gr.Textbox(label="Transcription Result") audio_status_output = gr.Textbox(label="Processing Status") audio_commands_output = gr.JSON(label=“Generated Commandas") # ΠϕϯτΛઃఆ ... # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυը໘ϨΠΞ΢τ HS"VEJP HS#VUUPO HS#VUUPO HS5FYUCPY HS5FYUCPY HS+40/ TUSVDUVSFEBDUJPOT HS)5.-  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ Ի੠ೖྗ༻ ίϯϙʔωϯτ Ϙλϯ ݁Ռग़ྗ༻ͷ ίϯϙʔωϯτ
  6. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ audio_input = gr.Audio( sources=["microphone"], type="filepath", format="wav") with gr.Row(): audio_send_button = gr.Button("Submit", variant="primary") audio_reset_button = gr.Button("Reset", variant="secondary") audio_transcript_output = gr.Textbox(label="Transcription Result") audio_status_output = gr.Textbox(label="Processing Status") audio_commands_output = gr.JSON(label=“Generated Commandas") # ΠϕϯτΛઃఆ ... # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυը໘ϨΠΞ΢τ HS"VEJP HS#VUUPO HS#VUUPO HS5FYUCPY HS5FYUCPY HS+40/ TUSVDUVSFEBDUJPOT HS)5.-  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ Ի੠ೖྗ༻ ίϯϙʔωϯτ Ϙλϯ ݁Ռग़ྗ༻ͷ ίϯϙʔωϯτ
  7. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ audio_input = gr.Audio( sources=["microphone"], type="filepath", format="wav") with gr.Row(): audio_send_button = gr.Button("Submit", variant="primary") audio_reset_button = gr.Button("Reset", variant="secondary") audio_transcript_output = gr.Textbox(label="Transcription Result") audio_status_output = gr.Textbox(label="Processing Status") audio_commands_output = gr.JSON(label=“Generated Commandas") # ΠϕϯτΛઃఆ ... # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυը໘ϨΠΞ΢τ HS"VEJP HS#VUUPO HS#VUUPO HS5FYUCPY HS5FYUCPY HS+40/ TUSVDUVSFEBDUJPOT HS)5.-  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ Ի੠ೖྗ༻ ίϯϙʔωϯτ Ϙλϯ ݁Ռग़ྗ༻ͷ ίϯϙʔωϯτ
  8. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ … # ΠϕϯτΛઃఆ audio_send_button.click(handler_audio_input, inputs=audio_input, outputs=[audio_transcript_output, audio_commands_output, audio_status_output, progress_lamps,],) audio_reset_button.click(...) audio_input.start_recording(...) audio_input.stop_recording(...) # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυΠϕϯτϋϯυϥ $MJDL  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ
  9. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ ... # ΠϕϯτΛઃఆ audio_send_button.click(handler_audio_input, inputs=audio_input, outputs=[audio_transcript_output, audio_commands_output, audio_status_output, progress_lamps,],) audio_reset_button.click(...) audio_input.start_recording(...) audio_input.stop_recording(...) # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυΠϕϯτϋϯυϥ ೖྗ ग़ྗ ΫϦοΫ  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ
  10. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ ... # Πϕϯτͷઃఆ audio_send_button.click(handler_audio_input, inputs=audio_input, outputs=[audio_transcript_output, audio_commands_output, audio_status_output, progress_lamps,],) audio_reset_button.click(...) audio_input.start_recording(...) audio_input.stop_recording(...) # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυΠϕϯτϋϯυϥ .click(handler, inputs=..., outputs=...) audio_transcript_output ΫϦοΫ࣌ʹ࣮ߦ͞ΕΔؔ਺ w Ի੠ࢦࣔͷจࣈى͜͠ w ੜ੒"*ʹΑΔίϚϯυม׵ॲཧ w 1JDPΧʔʹίϚϯυૹ৴ w ʜ audio_status_output audio_commands_output audio_input  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ
  11. 9!LPNP@GS import gradio as gr ... with gr.Blocks() as demo:

    ... with gr.Tab("Voice Input"): # ίϯϙʔωϯτΛ഑ஔ ... # ΠϕϯτΛઃఆ audio_send_button.click(handler_audio_input, inputs=audio_input, outputs=[audio_transcript_output, audio_commands_output, audio_status_output, progress_lamps,],) audio_reset_button.click(...) audio_input.start_recording(...) audio_input.stop_recording(...) # αʔόΛىಈ demo.launch(server_name="0.0.0.0", share=True) ίʔυαʔόͷىಈ  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ
  12. 9!LPNP@GS audio_send_button.click(handler_audio_input, inputs=audio_input, outputs=[audio_transcript_output, audio_commands_output, audio_status_output, progress_lamps]) def handler_audio_input(audio_file): success,

    text = transcribe(audio_file) if success: yield text, None, "จࣈى͜͠׬ྃ", render_lamps(["s", "u", "u"]) commands = text_to_command(text) commands = convert_commands(commands) yield text, commands, "ίϚϯυੜ੒׬ྃ", render_lamps(["s", "s", "u"]) response = send_commands(commands) status = response.get("status") yield text, commands, status, render_lamps(["s"] * 3) else: yield text, None, "จࣈى͜͠ʹࣦഊ͠·ͨ͠ɻऴྃ͠·͢", render_lamps(["e", "u", "u"]) w (SBEJPͰ͸ʮஈ֊తʹ݁ՌΛฦ͢ʯ6*΋؆୯ʹ࡞ΕΔ w ΠϕϯτϋϯυϥͷதͰyieldΛ࢖ͬͯ݁ՌΛฦ͢ ᶈ͢΂ͯͷ݁ՌΛฦ͢ Πϕϯτϋϯυϥ ग़ྗઌͷίϯϙʔωϯτ ᶃจࣈى͜͠Λ࣮ߦ ᶅੜ੒"*Λ࢖ͬͯɺจࣈྻΛߏ଄Խ͞ΕͨίϚϯυʹม׵͢Δ ᶇ1JDPΧʔʹίϚϯυΛૹ৴ ZJMFEΛ࢖ͬͯஈ֊తʹ݁ՌΛฦ͢ ᶆੜ੒"*͕ม׵ͨ͠ίϚϯυΛฦ͢ ᶄจࣈى͜͠ͷ݁ՌΛฦ͢  4UFQ8FCΞϓϦ͔ΒԻ੠ೖྗ
  13. 9!LPNP@GS 1JDP$BS4FSWFS ʢ3BTQCFSSZ1J1*DP$BSʣ εϚϗͳͲͷ 8FCϒϥ΢β 8FCΞϓϦ͔Β Ի੠Λೖྗ ίϚϯυΛड৴  ࣮ߦ

    Ի੠Λจࣈى͜͠  ੜ੒"*Ͱࢦࣔσʔλʹม׵ 4UFQ 4UFQ 4UFQ ߏ଄Խ͞Εͨ ࢦࣔσʔλ Ի੠σʔλ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵ 1JDP$POUSPMMFS4FSWFS ʢ.BDʣ
  14. 9!LPNP@GS w Ի੠ͷ··ੜ੒"*ʹೖྗ͢Δͱ"1*ྉۚͷίετ͕͔͔Γͦ͏ 👉ϩʔΧϧͰGBTUFSXIJTQFSΛ࢖ͬͯจࣈى͜͠Λ͢Δ from faster_whisper import WhisperModel model_size =

    "tiny" model = WhisperModel(model_size, device="cpu", compute_type="float32") …ུ… segments, _ = model.transcribe(tmp_audio_path, language="ja") text = "".join([segment.text for segment in segments]) ᶃϞσϧͷಡΈࠐΈ ᶄϞσϧͷ࣮ߦʢจࣈى͜͠ʣ Ի੠ˠςΩετʢจࣈى͜͠ʣ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  15. 9!LPNP@GS w Ի੠ͷ··ੜ੒"*ʹೖྗ͢Δͱ"1*ྉۚͷίετ͕͔͔Γͦ͏ 👉ϩʔΧϧͰGBTUFSXIJTQFSΛ࢖ͬͯจࣈى͜͠Λ͢Δ from faster_whisper import WhisperModel model_size =

    "tiny" model = WhisperModel(model_size, device="cpu", compute_type="float32") …ུ… segments, _ = model.transcribe(tmp_audio_path, language="ja") text = "".join([segment.text for segment in segments]) ᶃϞσϧͷಡΈࠐΈ ᶄϞσϧͷ࣮ߦʢจࣈى͜͠ʣ Ի੠ˠςΩετʢจࣈى͜͠ʣ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  16. 9!LPNP@GS w -BOH$IBJO w ೥ʹൃද͞Εͨɺ--.ΞϓϦ։ൃͷͨΊͷ1ZUIPOϑϨʔϜϫʔΫ w -BOH$IBJOܦ༝Ͱ0QFO"*ͷ"1*ʢHQUʣΛݺͼग़͠ɺ ࣗવݴޠͷࢦࣔΛɺߏ଄Խ͞ΕͨࢦࣔσʔλʢࣙॻͷϦετʣʹม׵͢Δ ·͙ͬ͢ߦͬͯ ӈʹۂ͕ͬͯʂ

    [{ "action": { "type": "forward", "distance_cm": 20,}}, { "action": { "type": "turn", "direction": "right", "angle": 90,}}, ...] ࣗવݴޠ ߏ଄Խ͞ΕͨࢦࣔσʔλʢࣙॻͷϦετʣ લʹDNਐΉ ӈʹ౓ճస ੜ੒"* ςΩετˠߏ଄Խ͞Εͨࢦࣔσʔλ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  17. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # Add RGB color info based on the LED color name (CSS color name) in the generated data instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ᶃϓϩϯϓτςϯϓϨʔτͷߏங ᶄϞσϧͷॳظԽ ᶅϓϩϯϓτͱϞσϧΛܨ͙ ᶆJOWPLFϝιουͰ࣮ߦ  ίʔυ-BOH$IBJOͷجຊ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  18. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # CSS৭໊ΛRGBʹม׵ͯ͠௥Ճ instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ᶃϓϩϯϓτςϯϓϨʔτͷߏங ᶄϞσϧͷॳظԽ ᶅϓϩϯϓτͱϞσϧΛܨ͙ ᶆJOWPLFϝιουͰ࣮ߦ  ίʔυ-BOH$IBJOͷجຊ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  19. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # CSS৭໊ΛRGBʹม׵ͯ͠௥Ճ instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ᶃϓϩϯϓτςϯϓϨʔτͷߏங ᶄϞσϧͷॳظԽ ᶅϓϩϯϓτͱϞσϧΛܨ͙ ᶆJOWPLFϝιουͰ࣮ߦ  ίʔυ-BOH$IBJOͷجຊ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  20. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # CSS৭໊ΛRGBʹม׵ͯ͠௥Ճ instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ᶃϓϩϯϓτςϯϓϨʔτͷߏங ᶄϞσϧͷॳظԽ ᶅϓϩϯϓτͱϞσϧΛܨ͙ ᶆJOWPLFϝιουͰ࣮ߦ  ίʔυ-BOH$IBJOͷجຊ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  21. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # CSS৭໊ΛRGBʹม׵ͯ͠௥Ճ instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ᶃϓϩϯϓτςϯϓϨʔτͷߏங ᶄϞσϧͷॳظԽ ᶅϓϩϯϓτͱϞσϧΛܨ͙ ᶆJOWPLFϝιουͰ࣮ߦ  ίʔυ-BOH$IBJOͷجຊ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  22. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # CSS৭໊ΛRGBʹม׵ͯ͠௥Ճ instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ༩͑ΒΕͨ೔ຊޠͷࢦࣔจΛɺpicoΧʔ༻ͷJSONܗࣜͷಈ࡞ίϚ ϯυ഑ྻʹม׵͍ͯͩ͘͠͞ɻ ࢦࣔͰ͸ͳ͍ݴ༿ΛݴΘΕͨ৔߹ʢʮ͓͸Α͏ʂʯʮ͹͔ʂʯͳͲʣ ͸ɺݴΘΕͨݴ༿ʹର͢Δײ৘Λද͢ಈ࡞ͷίϚϯυ഑ྻʹม׵͠ ͍ͯͩ͘͞ɻ ίϚϯυ഑ྻ͚ͩΛग़ྗ͠ɺͦΕҎ֎ͷઆ໌จͳͲ͸ؚΊͳ͍Ͱ͘ ͍ͩ͞ɻ ֤ίϚϯυ͸ҎԼͷܗࣜΛ࢖༻͍ͯͩ͘͠͞: … ϓϩϯϓτ 1SPNQU  4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  23. 9!LPNP@GS from langchain.chat_models import init_chat_model from langchain_core.prompts import ChatPromptTemplate ...

    prompt = ChatPromptTemplate( [ ("system", TEXT_TO_COMMAND_PROMPT), ("human", "ࢦࣔ: {text}"), ] ) llm = init_chat_model(model="gpt-4.1", temperature=0) chain = prompt | llm result = chain.invoke({"text": text}) instructions = result.content # CSS৭໊ΛRGBʹม׵ͯ͠௥Ճ instructions = _add_led_rgb(instructions) instructions = json.loads(instructions) ༩͑ΒΕͨ೔ຊޠͷࢦࣔจΛɺpicoΧʔ༻ͷJSONܗࣜͷಈ࡞ίϚ ϯυ഑ྻʹม׵͍ͯͩ͘͠͞ɻ ࢦࣔͰ͸ͳ͍ݴ༿ΛݴΘΕͨ৔߹ʢʮ͓͸Α͏ʂʯʮ͹͔ʂʯͳͲʣ ͸ɺݴΘΕͨݴ༿ʹର͢Δײ৘Λද͢ಈ࡞ͷίϚϯυ഑ྻʹม׵͠ ͍ͯͩ͘͞ɻ ίϚϯυ഑ྻ͚ͩΛग़ྗ͠ɺͦΕҎ֎ͷઆ໌จͳͲ͸ؚΊͳ͍Ͱ͘ ͍ͩ͞ɻ ֤ίϚϯυ͸ҎԼͷܗࣜΛ࢖༻͍ͯͩ͘͠͞: … 1SPNQU  ϓϩϯϓτ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  24. 9!LPNP@GS ͋ͳͨՄѪ͍ΘͶʙ w ᐆດͳݴ༿ΛݴΘΕͨͱ͖͸ɺͦͷݴ༿ʹର͢Δײ৘Λද͢ಈ࡞ɾ৭ʹ ม׵͢ΔΑ͏ϓϩϯϓτͰࢦࣔ 👉ᐆດͳݴ༿ΛݴΘΕͨ࣌΋ɺԿΒ͔ͷʮੜ͖෺Β͍͠൓ԠʯΛͯ͘͠ΕΔ ͹͔͹͔ʂ ஥௚Γ͠Α͏ ϐϯΫͰલਐͯ͠ࠨӈʹ;Γ;Γ ʢتͼʁʣ

    ੨৭Ͱޙୀʢ൵͠Έʁʣ ྘Ͱલਐʢߠఆʁʣ ϓϩϯϓτͷ޻෉ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵ ϐϯΫͰલਐͯ͠ࠨӈʹ;Γ;Γʢتͼʁʣ ϓϩϯϓτͰ͸ɺʮ൵͠Έ͸੨Ͱද͢ʯ ͱ͍ͬͨࢦࣔ͸༩͍͑ͯͳ͍ ੜ੒"*͕ࣗ෼Ͱࣗવͳ৭ΛબͿͷͰ ෯޿͍ݴ༿ʹॊೈʹ൓ԠͰ͖Δ
  25. 9!LPNP@GS [ { "action": {"type": "forward", "distance_cm": 20}, "led": {"color":

    "green"}}, { "action": {"type": "turn", "direction": "right", "angle": 90}, "led": {"color": "green"}}, ...] BDUJPOӈճస ›  MFE྘ BDUJPOલਐ DN  MFE྘ ͭ໨ͷίϚϯυ ͭ໨ͷίϚϯυ  ੜ੒͞ΕΔࢦࣔσʔλ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  26. 9!LPNP@GS [ { "action": {"type": "forward", "distance_cm": 20}, "led": {"color":

    "green", "rgb": (0, 255, 0) }}, { "action": {"type": "turn", "direction": "right", "angle": 90}, "led": {"color": "green", "rgb": (0, 255, 0)}}, ...] $44৭໊Λ3(#஋ʹม׵ w ੜ੒"*͸$44ͷ৭໊͚ͩΛग़ྗɻޙॲཧͰ1ZUIPOͰ3(#஋ʹม׵͢Δ w ৭໊ͷํ͕ײ৘Λදͤͦ͏ ਓ͕ؒݟͯཧղ͠΍͍͢ͷͰɺ "*ʹ͸৭໊Λग़ྗͤͨ͞ w $44৭໊͔Β3(#΁ͷม׵͸ɺγϯϓϧͰ࣮֬ʹ΍ΒͤΔͨΊ1ZUIPOʹ೚ͤͨ  ੜ੒͞ΕΔࢦࣔσʔλ 4UFQԻ੠Λจࣈى͜͠ ੜ੒"*Ͱࢦࣔσʔλʹม׵
  27. 9!LPNP@GS 1JDP$POUSPMMFS4FSWFS ʢ.BDʣ εϚϗͳͲͷ 8FCϒϥ΢β 8FCΞϓϦ͔Β Ի੠Λೖྗ ίϚϯυΛड৴  ࣮ߦ

    Ի੠Λจࣈى͜͠  ੜ੒"*Ͱࢦࣔσʔλʹม׵ 4UFQ 4UFQ 4UFQ ߏ଄Խ͞Εͨ ࢦࣔσʔλ Ի੠σʔλ 4UFQίϚϯυΛड৴ ࣮ߦ 1JDP$BS4FSWFS ʢ3BTQCFSSZ1J1*DP$BSʣ
  28. 9!LPNP@GS from microdot import Microdot from pico_car import Car, RealCar

    car = Car() if settings.USE_MOCK else RealCar() app = Microdot() ... @app.route("/command", methods=["POST"]) async def handle_command(request): try: car.sound_freq(1000, 0.1) car.sound_freq(1200, 0.1) command_list = request.json car.run_commands(command_list) return {"status": "ok"} except Exception as e: handle_buggy_error() print_exception(e) return {"status": "error", "message": str(e)}, 500 ... app.run(port=5001) ᶃड৴ԻΛ໐Β͢ ᶄίϚϯυΛ࣮ߦ Τϥʔൃੜ࣌ͷॲཧʢΤϥʔԻΛ໐Β͢ɺϞʔλఀࢭͳͲʣ αʔόΛىಈ ίʔυ1JDP্ͷ.JDSPEPUαʔό ίϚϯυΛड৴࣮ͯ͠ߦ͢Δ"1*ͷఆٛ  4UFQίϚϯυΛड৴ ࣮ߦ ࣗ࡞ͷ1JDPΧʔΫϥεͷΠϯελϯεΛੜ੒ .JDSPEPUΞϓϦΛ࡞੒
  29. 9!LPNP@GS from microdot import Microdot from pico_car import Car, RealCar

    car = Car() if settings.USE_MOCK else RealCar() app = Microdot() ... @app.route("/command", methods=["POST"]) async def handle_command(request): try: car.sound_freq(1000, 0.1) car.sound_freq(1200, 0.1) command_list = request.json car.run_commands(command_list) return {"status": "ok"} except Exception as e: handle_buggy_error() print_exception(e) return {"status": "error", "message": str(e)}, 500 ... app.run(port=5001) ᶃड৴ԻΛ໐Β͢ ࣗ࡞ͷ1JDPΧʔΫϥεͷΠϯελϯεΛੜ੒ ᶄίϚϯυΛ࣮ߦ Τϥʔൃੜ࣌ͷॲཧʢΤϥʔԻΛ໐Β͢ɺϞʔλఀࢭͳͲʣ αʔόΛىಈ ίʔυ1JDP্ͷ.JDSPEPUαʔό ίϚϯυΛड৴࣮ͯ͠ߦ͢Δ"1*ͷఆٛ  4UFQίϚϯυΛड৴ ࣮ߦ ಈ࡞֬ೝ͠΍͍͢Α͏ ઃఆͰϞοΫͱ࣮ػΛ੾Γସ͑ .JDSPEPUΞϓϦΛ࡞੒
  30. 9!LPNP@GS from microdot import Microdot from pico_car import Car, RealCar

    car = Car() if settings.USE_MOCK else RealCar() app = Microdot() ... @app.route("/command", methods=["POST"]) async def handle_command(request): try: car.sound_freq(1000, 0.1) car.sound_freq(1200, 0.1) command_list = request.json car.run_commands(command_list) return {"status": "ok"} except Exception as e: handle_buggy_error() print_exception(e) return {"status": "error", "message": str(e)}, 500 ... app.run(port=5001) ᶃड৴ԻΛ໐Β͢ ࣗ࡞ͷ1JDPΧʔΫϥεͷΠϯελϯεΛੜ੒ ᶄίϚϯυΛ࣮ߦ Τϥʔൃੜ࣌ͷॲཧʢΤϥʔԻΛ໐Β͢ɺϞʔλఀࢭͳͲʣ αʔόΛىಈ ίʔυ1JDP্ͷ.JDSPEPUαʔό ίϚϯυΛड৴࣮ͯ͠ߦ͢Δ"1*ͷఆٛ .JDSPEPUΞϓϦΛ࡞੒  4UFQίϚϯυΛड৴ ࣮ߦ ಈ࡞֬ೝ͠΍͍͢Α͏ ઃఆͰϞοΫͱ࣮ػΛ੾Γସ͑
  31. 9!LPNP@GS from microdot import Microdot from pico_car import Car, RealCar

    car = Car() if settings.USE_MOCK else RealCar() app = Microdot() ... @app.route("/command", methods=["POST"]) async def handle_command(request): try: car.sound_freq(1000, 0.1) car.sound_freq(1200, 0.1) command_list = request.json car.run_commands(command_list) return {"status": "ok"} except Exception as e: handle_buggy_error() print_exception(e) return {"status": "error", "message": str(e)}, 500 ... app.run(port=5001) ᶃड৴ԻΛ໐Β͢ ࣗ࡞ͷ1JDPΧʔΫϥεͷΠϯελϯεΛੜ੒ ᶄίϚϯυΛ࣮ߦ Τϥʔൃੜ࣌ͷॲཧʢΤϥʔԻΛ໐Β͢ɺϞʔλఀࢭͳͲʣ αʔόΛىಈ ίʔυ1JDP্ͷ.JDSPEPUαʔό ίϚϯυΛड৴࣮ͯ͠ߦ͢Δ"1*ͷఆٛ .JDSPEPUΞϓϦΛ࡞੒  4UFQίϚϯυΛड৴ ࣮ߦ 'MBTLͬΆ͍ߏจ
  32. 9!LPNP@GS from microdot import Microdot from pico_car import Car, RealCar

    car = Car() if settings.USE_MOCK else RealCar() app = Microdot() ... @app.route("/command", methods=["POST"]) async def handle_command(request): try: car.sound_freq(1000, 0.1) car.sound_freq(1200, 0.1) command_list = request.json car.run_commands(command_list) return {"status": "ok"} except Exception as e: handle_buggy_error() print_exception(e) return {"status": "error", "message": str(e)}, 500 ... app.run(port=5001) ᶃड৴ԻΛ໐Β͢ ࣗ࡞ͷ1JDPΧʔΫϥεͷΠϯελϯεΛੜ੒ ᶄίϚϯυΛ࣮ߦ Τϥʔൃੜ࣌ͷॲཧʢΤϥʔԻΛ໐Β͢ɺϞʔλఀࢭͳͲʣ αʔόΛىಈ ίʔυ1JDP্ͷ.JDSPEPUαʔό ίϚϯυΛड৴࣮ͯ͠ߦ͢Δ"1*ͷఆٛ .JDSPEPUΞϓϦΛ࡞੒  4UFQίϚϯυΛड৴ ࣮ߦ 'MBTLͬΆ͍ߏจ
  33. 9!LPNP@GS from microdot import Microdot from pico_car import Car, RealCar

    car = Car() if settings.USE_MOCK else RealCar() app = Microdot() ... @app.route("/command", methods=["POST"]) async def handle_command(request): try: car.sound_freq(1000, 0.1) car.sound_freq(1200, 0.1) command_list = request.json car.run_commands(command_list) return {"status": "ok"} except Exception as e: handle_buggy_error() print_exception(e) return {"status": "error", "message": str(e)}, 500 ... app.run(port=5001) ᶃड৴ԻΛ໐Β͢ ࣗ࡞ͷ1JDPΧʔΫϥεͷΠϯελϯεΛੜ੒ ᶄίϚϯυΛ࣮ߦ Τϥʔൃੜ࣌ͷॲཧʢΤϥʔԻΛ໐Β͢ɺϞʔλఀࢭͳͲʣ αʔόΛىಈ ίʔυ1JDP্ͷ.JDSPEPUαʔό ίϚϯυΛड৴࣮ͯ͠ߦ͢Δ"1*ͷఆٛ .JDSPEPUΞϓϦΛ࡞੒  4UFQίϚϯυΛड৴ ࣮ߦ
  34. 9!LPNP@GS w ୯७ʹforϧʔϓͰίϚϯυΛॱʹ࣮ߦ w ίϚϯυʹԠͯ͡Ϟʔλ΍-&%Λ੍ޚ͢Δ w Ϟʔλʔ΍-&%ͷ੍ޚʹ͸ɺ1JDPΧʔͷΩοτ༻ͷϥΠϒϥϦΛ࢖༻ w IUUQTHJUIVCDPN,JUSPOJL-UE,JUSPOJL1JDP"VUPOPNPVT3PCPUJDT1MBUGPSN.JDSP1ZUIPO ίϚϯυΛॱ൪ʹॲཧ

    4UFQίϚϯυΛड৴ ࣮ߦ  from PicoAutonomousRobotics import KitronikPicoRobotBuggy buggy = KitronikPicoRobotBuggy() ... buggy.motorOn("l", "f", SPEED) # ࠨंྠ: લਐ buggy.motorOn("r", "f", SPEED) # ӈंྠ: લਐ buggy.motorOn("l", "f", SPEED) # ࠨंྠ: લਐ buggy.motorOn("r", "r", SPEED) # ӈंྠ: ޙਐ લਐ ӈճస Ϟʔλͷ੍ޚྫ
  35. 9!LPNP@GS w (SBEJPͰ࡞ͬͨ6*͔Βɺखඳ͖Ͱϧʔτը૾Λೖྗ w 4ελʔτ஍఺ɺ(ΰʔϧ஍఺ w ϓϩϯϓτͱҰॹʹը૾Λੜ੒"*ʹ౉͢ Ωϟϯόε্ʹϧʔτΛඳ͍ͯ ೖྗ ʢgr.ImageEditorʣ

    ༩͑ΒΕͨը૾ʹϧʔτ͕ඳ͔Ε͍ͯ·͢ɻ S͕ελʔτ஍఺ͰɺG͕ΰʔϧ஍఺Ͱ͢ɻ ͜ͷϧʔτը૾ΛɺpicoΧʔ༻ͷJSONܗࣜͷ ಈ࡞ίϚϯυ഑ྻʹม׵͍ͯͩ͘͠͞ɻ …ུ… ϓϩϯϓτ ϧʔτը૾Λ༩͑ͯ1JDPΧʔΛಈ͔͢ Ԡ༻ը૾ʹΑΔࢦࣔ
  36. 

  37. 

  38. 9!LPNP@GS NJDSPCJUΛ࢖͏৔߹ͷ੍໿ Ԡ༻ྫNJDSPCJUͱͷ࿈ܞ Ի੠σʔλ ߏ଄Խσʔλ εϚϗͳͲͷ 8FCϒϥ΢β $POUSPMMFS4FSWFS ʢ.BDʣ $BS4FSWFS

    w ͜͜·Ͱઆ໌ͨ͠3BTQCFSSZ1J1JDP༻ͷ࢓૊Έ͸ͦͷ··Ͱ͸࢖͑ͳ͍ w NJDSPCJU୯ମʹ͸8J'J௨৴ͷػೳ͕ͳ͍ w ͦͷͨΊɺNJDSPCJU্ʹ8FC"1*αʔόΛཱͯΔͷ͸ݱ࣮తͰ͸ͳ͍ NJDSPCJU 
  39. 9!LPNP@GS NJDSPCJU༻ͷߏ੒ Ԡ༻ྫNJDSPCJUͱͷ࿈ܞ Ի੠σʔλ ߏ଄Խ σʔλ εϚϗͳͲͷ 8FCϒϥ΢β $POUSPMMFS4FSWFS w

    .BDͱNJDSPCJU͸༗ઢͩͱγϦΞϧ௨৴Ͱ؆୯ʹσʔλަ׵Ͱ͖Δ w NJDSPCJUಉ࢜͸ແઢͰ؆୯ʹ௨৴Ͱ͖Δ w 👉ͦͷͨΊɺ.BDʹதܧ༻ͷNJDSPCJUΛ64#Ͱܨ͗ ͦͷதܧ༻NJDSPCJUͱϩϘοτ্ͷNJDSPCJUΛ௨৴͢Δ $BS4FSWFS .BD NJDSPCJUᶃ NJDSPCJUᶄ จࣈྻσʔλ จࣈྻσʔλ 64# .BD γϦΞϧ௨৴ ແઢ