Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
dRuby over BLE
Search
makicamel
June 08, 2026
Programming
390
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
dRuby over BLE
dRuby over BLE: Device-to-Device Remote Method Calls
2026.06.06. 松江Ruby会議12
makicamel
June 08, 2026
More Decks by makicamel
See All by makicamel
Road to RubyKaigi: Play Hard(ware)
makicamel
1
700
First step to PicoRuby
makicamel
2
570
PicoRuby on Rails
makicamel
4
290
Take a small step beyond the api
makicamel
2
210
Road to RubyKaigi: Making Tinny Chiptunes with Ruby
makicamel
4
1.8k
Road to RubyKaigi
makicamel
4
710
Rails アプリ地図考 Flush Cut
makicamel
1
230
ErdMap: Thinking about a map for Rails applications
makicamel
2
4.2k
dRuby 入門者によるあなたの身近にあるdRuby 入門
makicamel
4
1.8k
Other Decks in Programming
See All in Programming
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
290
Performance Engineering for Everyone
elenatanasoiu
0
230
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
350k
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
790
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.8k
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
130
さぁV100、メモリをお食べ・・・
nilpe
0
160
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
0
170
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
560
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.1k
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.3k
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
230
Featured
See All Featured
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
160
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
Google's AI Overviews - The New Search
badams
0
1.1k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
310
The Cult of Friendly URLs
andyhume
79
6.9k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.2k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
170
AI: The stuff that nobody shows you
jnunemaker
PRO
8
740
How to train your dragon (web standard)
notwaldorf
97
6.7k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.6k
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
450
Transcript
E3VCZPWFS#-& %FWJDFUP%FWJDF3FNPUF.FUIPE$BMMT !NBLJDBNFM দߐ3VCZձٞ 1 / 64
ࣗݾհ ! !NBLJDBNFMݪສق ! 3VCZ!ͱϏʔϧ"ͱ͓ञ͕͖ ! 1JDP1JDP3VCZͬͯ·͢ ! 3PBEUP3VCZ,BJHJͷ࡞ऀ 2
/ 64
3PBEUP3VCZ,BJHJ NBLJDBNFMSPBE@UP@SVCZLBJHJ IUUQTHJUIVCDPNNBLJDBNFMSPBE@UP@SVCZLBJHJ 3 / 64
3PBEUP3VCZ,BJHJ ! 3VCZJTUʹΑΔ3VCZJTUͷͨΊͷ3VCZͷήʔϜ ! λʔϛφϧ্Ͱ༡ͿԣεΫϩʔϧΞΫγϣϯήʔϜ ! όάΛ͠ʒ͔ΒಀΕͯ3VCZ,BJHJࢀՃΛࢦ͢ 4 / 64
3PBEUP3VCZ,BJHJ⭐ ! !3VCZ,BJHJ-5 ! 1JDP3VCZͱ ՃηϯαʔͰͭ͘Δ ήʔϜίϯτϩʔϥ 3PBEUP3VCZ,BJHJ1MBZ)BSE XBSF !NBLJDBNFM
IUUQTTQFBLFSEFDLDPNNBLJDBNFMSPBEUPSVCZLBJHJQMBZIBSEXBSF 5 / 64
ొਓ 1JDP3VCZ ΈࠐΈ͚3VCZ ηϯαʔͳͲͱଓͯ͠ ͖ͳσόΠεΛͭ͘ΕΔ QJDPSVCZQJDPSVCZ IUUQTHJUIVCDPNQJDPSVCZQJDPSVCZ 6 / 64
ొਓ 1JDP3VCZ ʢ3BTQCFSSZ1J1JDP8ʣ ΈࠐΈ͚3VCZ ηϯαʔͳͲͱଓͯ͠ ͖ͳσόΠεΛͭ͘ΕΔ QJDPSVCZQJDPSVCZ IUUQTHJUIVCDPNQJDPSVCZQJDPSVCZ 7 /
64
ొਓ ίϯτϩʔϥ 8 / 64
ొਓ Ճηϯα 9 / 64
ొਓ Ճηϯα ՃηϯαͷΛ 3PBEUP3VCZ,BJHJʹ͍ͨ͠ 3PBEUP3VCZ,BJHJ 10 / 64
ొਓ 1JDP3VCZ Ճηϯα 1JDP3VCZͰ ՃηϯαͷΛಡΈऔΓ 3PBEUP3VCZ,BJHJ 11 / 64
ొਓ 1JDP3VCZ #MVFUPPUIͰ 3PBEUP3VCZ,BJHJʹૹ৴ 3PBEUP3VCZ,BJHJ 12 / 64
ొਓ 1JDP3VCZ #MVFUPPUIͰ 3PBEUP3VCZ,BJHJʹૹ৴ Ͱ͖ͳ͍ 3PBEUP3VCZ,BJHJ 13 / 64
ొਓ 1JDP3VCZ #MVFUPPUIͷ ΫϩεϓϥοτϑΥʔϜͳ 3VCZΫϥΠΞϯτ͕ͳ͍ #MVFUPPUIͰ 3PBEUP3VCZ,BJHJʹૹ৴ Ͱ͖ͳ͍ 3PBEUP3VCZ,BJHJ 14
/ 64
ొਓ ϒϥβ 8FC#MVFUPPUI"1* 8FC#MVFUPPUI"1*8FC"1*c.%/ IUUQTEFWFMPQFSNP[JMMBPSHKBEPDT8FC"1*8FC@#MVFUPPUI@"1* 15 / 64
ొਓ ϒϥβ 8FC#MVFUPPUI"1* 8&#SJDLαʔό 3PBEUP3VCZ,BJHJ 16 / 64
ొਓ 1JDP3VCZ #MVFUPPUI ϒϥβ 8&#SJDLαʔό 3PBEUP3VCZ,BJHJ 17 / 64
ొਓ 1JDP3VCZ #MVFUPPUI ϒϥβ )551 8&#SJDLαʔό 3PBEUP3VCZ,BJHJʹ ૹ৴Ͱ͖ͨ 3PBEUP3VCZ,BJHJ 18
/ 64
#MVFUPPUI 19 / 64
#-& ! #MVFUPPUI-PX&OFSHZ ! লిྗ͚#MVFUPPUIن֨ ! 3BTQCFSSZ1J1JDP 8ʹແઢνοϓ͕͍ͬͯΔ !
1JDP3VCZ͔Βѻ͑Δ ֓೦ɾ͓࡞๏͕ Ή͔͍ͣ͠ 20 / 64
#-&6"35 ! 6"35 ! ػثΛཧઢͰͭͳ͍ͰํʹόΠτΛૹΔ௨ ৴ํࣜ ! #-&6"35 ! 6"35Λ#-&ͰԾతʹ࣮ݱ͢Δ1JDP3VCZͷ࣮
! *0ͷΑ͏ͳΠϯλʔϑΣʔεͰѻ͑Δ #-&6"35QJDPSVCZQJDPSVCZ IUUQTHJUIVCDPNQJDPSVCZQJDPSVCZUSFFNBTUFSNSCHFNTQJDPSVCZCMFVBSU 21 / 64
#-&6"35 # ૹ৴ଆ(PicoRuby) ble_uart = BLE::UART.new ble_uart.start do if ble_uart.connected?
ble_uart.puts('Hello, BLE::UART!') end end 3VCZͬΆ͍ʂ 22 / 64
#-&6"35 # ड৴ଆ(PicoRuby.WASM) # ηοτΞοϓ @buffer = '' server =
@device.connect service = server.service(@svc_uuid) @rx_char = service.characteristic(@rx_uuid) @rx_char.on_change { |data| @buffer << data } @rx_char.start_notify 23 / 64
#-&6"35 # ड৴ଆ(PicoRuby.WASM) # @bufferΛҰఆ࣌ؒຖʹνΣοΫ͢Δ while (idx = @buffer.index(SEPARATOR)) line
= @buffer.slice!(0..idx).strip line.split(SAMPLE_SEPARATOR) .each { |sample| send_data(sample) } end 3VCZͬΆ͍ʜʜʁ 24 / 64
#-&6"35 ! )551 ! ϦΫΤετϝοηʔδ ! #-&6"35 ! όΠτετϦʔϜ !
ड৴ϝοηʔδ ! FH ෳϝοηʔδɺϝοηʔδ్͕தͰ͖ΕΔ ! ηύϨʔλͰ۠Γͯࣗ͠ͰΈཱͯΔ 25 / 64
#-&6"35 3VCZͬΆ͘ॻ͖͍ͨʂ 26 / 64
E3VCZ 27 / 64
E3VCZ ! EJTUSJCVUJPO3VCZ ! ࢄ3VCZ ! ࢄΦϒδΣΫτγεςϜΛ࣮ݱ͢ΔϥΠϒϥϦ ! ؔকढ़͞Μ࡞ MJCSBSZESC
3VCZϦϑΝϨϯεϚχϡΞϧ IUUQTEPDTSVCZMBOHPSHKBMBUFTUMJCSBSZESCIUNM 28 / 64
E3VCZ ! ϓϩηεωοτϫʔΫΛ͑ͯϝοηʔδΛૹΔ ! ଞϓϩηεͷΦϒδΣΫτͷϝιουΛݺΔ 29 / 64
E3VCZ { greeting: 'Hello, Matsue!' } E3VCZೖऀʹΑΔ͋ͳͨͷۙʹ͋ΔE3VCZೖ!NBLJDBNFM IUUQTTQFBLFSEFDLDPNNBLJDBNFMESVCZBUUSBDUJPO 30 /
64
E3VCZ { greeting: 'Hello, Matsue!' object[:greeting] } E3VCZೖऀʹΑΔ͋ͳͨͷۙʹ͋ΔE3VCZೖ!NBLJDBNFM IUUQTTQFBLFSEFDLDPNNBLJDBNFMESVCZBUUSBDUJPO 31
/ 64
E3VCZ { greeting: 'Hello, Matsue!' object[:greeting] } # => 'Hello,
Matsue!' E3VCZೖऀʹΑΔ͋ͳͨͷۙʹ͋ΔE3VCZೖ!NBLJDBNFM IUUQTTQFBLFSEFDLDPNNBLJDBNFMESVCZBUUSBDUJPO 32 / 64
E3VCZ ! 3VCZͬΆ͍ʂ ! #-&͝͠ʹผϓϩηεͷΦϒδΣΫτΛ͞ΘΓ͍ͨ 33 / 64
E3VCZPWFS#-& 34 / 64
E3VCZPWFS#-& E3VCZϓϩτίϧ͕ࠩ͠ସ͑Մೳ ! ϏϧτΠϯ ! Ϣʔβʔ֦ு ! 5$1 ! 8FC4PDLFU
! 6/*9υϝΠϯιέοτ ! 44- 35 / 64
E3VCZPWFS#-& E3VCZϓϩτίϧ͕ࠩ͠ସ͑Մೳ ! ϏϧτΠϯ ! Ϣʔβʔ֦ு ! 5$1 ! 8FC4PDLFU
! 6/*9υϝΠϯιέοτ ! #-&! GPS1JDP3VCZ1JDP3VCZ8"4. ! 44- 36 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶃΦϒδΣΫτΛެ։ front = Calc.new DRb.start_service( "ble://picoruby", front)
37 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶄελϒΛ࡞Δ ᶃΦϒδΣΫτΛެ։ αʔόͷΞυϨεΛࢦఆ front = Calc.new obj
= DRbObject.new( DRb.start_service( "ble://picoruby") "ble://picoruby", front) 38 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶄελϒΛ࡞Δ ᶃΦϒδΣΫτΛެ։ αʔόͷΞυϨεΛࢦఆ front = Calc.new obj
= DRbObject.new( DRb.start_service( "ble://picoruby") "ble://picoruby", front) ᶅϝοηʔδૹ৴ obj.add(1, 2) όΠτྻมͯ͠ૹ৴ όΠτྻΛૹड৴ 39 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶄελϒΛ࡞Δ ᶃΦϒδΣΫτΛެ։ αʔόͷΞυϨεΛࢦఆ front = Calc.new obj
= DRbObject.new( DRb.start_service( "ble://picoruby") "ble://picoruby", front) ᶅϝοηʔδૹ৴ ᶆϝιουίʔϧ obj.add(1, 2) όΠτྻΛมͯ͠ϝιουίʔϧ όΠτྻมͯ͠ૹ৴ front.send(msg_id, *args) όΠτྻΛૹड৴ 40 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶄελϒΛ࡞Δ ᶃΦϒδΣΫτΛެ։ αʔόͷΞυϨεΛࢦఆ front = Calc.new obj
= DRbObject.new( DRb.start_service( "ble://picoruby") "ble://picoruby", front) ᶅϝοηʔδૹ৴ ᶆϝιουίʔϧ obj.add(1, 2) όΠτྻΛมͯ͠ϝιουίʔϧ όΠτྻมͯ͠ૹ৴ front.send(msg_id, *args) όΠτྻΛૹड৴ ᶇ݁ՌΛฦ͢ # => 3 41 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶄελϒΛ࡞Δ ᶃΦϒδΣΫτΛެ։ αʔόͷΞυϨεΛࢦఆ front = Calc.new obj
= DRbObject.new( DRb.start_service( "ble://picoruby") "ble://picoruby", front) ᶅϝοηʔδૹ৴ ᶆϝιουίʔϧ obj.add(1, 2) όΠτྻΛมͯ͠ϝιουίʔϧ όΠτྻมͯ͠ૹ৴ front.send(msg_id, *args) όΠτྻΛૹड৴ ᶈ݁ՌΛड͚औΔ ᶇ݁ՌΛฦ͢ # => 3 # => 3 42 / 64
όΠτྻͷૹड৴ ! DRbMessage ! ϝιουίʔϧɾΓˡˠόΠτྻͷมΛߦ͏ ! ௨৴࿏ʹͤΒΕΔͷόΠτྻ͚ͩ ! τϥϯεϙʔτͱૄ݁߹ 43
/ 64
όΠτྻͷૹड৴ ! τϥϯεϙʔτ ! FH ! 5$1 ! 8FC4PDLFU !
#-& ! 1JDP3VCZɾ4%,Ͱ࣮͞Ε͍ͯΔ 44 / 64
όΠτྻͷૹड৴ ! DRbMessage τϥϯεϙʔτ ! "1*ͷཁ݅ͱ࣮ଶʹ͕ࠩ͋Δ DRbMessage#recv_message | | |
BLE::UART#read_nonblock 45 / 64
όΠτྻͷૹड৴ ! DRbMessage ιέοττϥϯεϙʔτ ! "1*ͷཁ݅ͱ࣮ଶͷࠩΛٵऩ͢ΔιέοτΛ࣮͢Δ DRbMessage#recv_message | Adapter#read |
BLE::UART#read_nonblock 46 / 64
E3VCZGPS1JDP3VCZ ΫϥΠΞϯτ αʔό ᶄελϒΛ࡞Δ ᶃΦϒδΣΫτΛެ։ αʔόͷΞυϨεΛࢦఆ front = Calc.new obj
= DRbObject.new( DRb.start_service( "ble://picoruby") #-&༻ιέοτΛ "ble://picoruby", front) ࣮͢Δ͚ͩ ᶅϝοηʔδૹ৴ ᶆϝιουίʔϧ obj.add(1, 2) όΠτྻΛมͯ͠ϝιουίʔϧ όΠτྻมͯ͠ૹ৴ front.send(msg_id, *args) όΠτྻΛૹड৴ ᶈ݁ՌΛड͚औΔ ᶇ݁ՌΛฦ͢ # => 3 # => 3 47 / 64
%3C#-&"EBQUFS ! όΠτྻʹର͢Δૢ࡞छྨ ! read ! write DRb::BLE::Adapter#close࣮͠·͕͢ࠓճׂѪ 48 /
64
%3C#-&"EBQUFS ! DRbMessage ! BLE::UART #recv_message(n) #read_nonblock(n) ! ϒϩοΩϯάඞཁ !
ϒϩοΩϯά͠ͳ͍ ! ஸOόΠτ΄͍͠ ! ʙOόΠτΛฦ͢ ͜ͷࠩΛ DRb::BLE::Adapter#read Ͱٵऩ͢Δ 49 / 64
%3C#-&"EBQUFS def read(n) ड৴όοϑΝʹ until @uart.available >= n OόΠτ #
... ཷ·Δ·Ͱͭ ϒϩοΩϯά sleep_ms 10 end end 50 / 64
%3C#-&"EBQUFS def read(n) until @uart.available >= n # ... @uart.poll_once
ड৴ύέοτΛ sleep_ms 10 όοϑΝʹੵΉ end end 51 / 64
%3C#-&"EBQUFS def read(n) until @uart.available >= n # ... @uart.poll_once
sleep_ms 10 end OόΠτཷ·ͬͨΒ @uart.read_nonblock(n) औΓग़ͯ͠ฦ͢ end 52 / 64
%3C#-&"EBQUFS ! DRbMessage ! BLE::UART #send_request(data) #write(data) ࣗͷλΠϛϯάͰόΠτΛૹΕΑ͍ 53 /
64
%3C#-&"EBQUFS ͦͷ··సૹ͢Δ def write(data) @uart.write(data) end 54 / 64
%3C#-& ! ιέοτ͕Ͱ͖ͨ! ! αʔόͷ࣮ ! Πϯελϯε࡞ͬͨΓ ! ϝοηʔδΛड͚औͬͯϝιουίʔϧͯ͠ฦ͠ ͨΓ͢Δ͚ͩ
55 / 64
ΞϓϦଆίʔυ ! CFGPSF # ड৴ଆ(PicoRuby.WASM) # ηοτΞοϓ @buffer = ''
server = @device.connect service = server.service(@svc_uuid) @rx_char = service.characteristic(@rx_uuid) @rx_char.on_change { |data| @buffer << data } @rx_char.start_notify # @bufferΛҰఆ࣌ؒຖʹνΣοΫ͢Δ while (idx = @buffer.index(SEPARATOR)) line = @buffer.slice!(0..idx).strip line.split(SAMPLE_SEPARATOR) .each { |sample| send_data(sample) } end Ή͔͍ͣ͠ʜʜ 56 / 64
ΞϓϦଆίʔυ ! BGUFS # ड৴ଆ(PicoRuby.WASM) # ηοτΞοϓ @obj = DRb::DRbObject.new_with_uri(uri)
# @obj.readΛҰఆ࣌ؒຖʹίʔϧ͢Δ @obj.read.each { |sample| send_data(sample) } 3VCZͬΆ͍ʂ 57 / 64
σϞ 58 / 64
σϞ ! ಈ͍ͯͳ͍ʜʜʁ ! ඵؒαϯϓϧ͕Γ͍ͯͳ͍ 59 / 64
༨ஊ ! ϙʔϦϯάϨʔτԼ ! CFGPSF ! αϯϓϧඵ ! BGUFS !
αϯϓϧඵ ! 60 / 64
༨ஊ ! ϙʔϦϯάϨʔτԼ ʮήʔϜίϯτϩʔϥΈ͍ͨͳͷʹ ɹSFRVFTUSFQMZܕͷ௨৴͖·ͤΜʯ ʮ!ʯ 61 / 64
༨ஊ ! E3VCZ ! QVTI ! SFRVFTUSFQMZܕ ! ҰํͷετϦʔϜ !
ຖճ ! ߴසʹૹΕͯԆ ૹ৴ɾػɾड৴ ! ฦࣄෆཁ ! ௨৴ճ͕૿͑Δ ! ฦࣄΛͭ͘ͳΔ ༻్ʹ͋ͬͨํ๏ Λબ΅͏ ήʔϜίϯτϩʔϥQVTIܕ͖ 62 / 64
͓͠Βͤ 63 / 64
1JDP3VCZ,BJHJ "TTFNCMFΓ·͢ ! 1JDP3VCZΛͭ͘Δɺ1JDP3VCZͰͭ͘Δ ! ϓϩϙʔβϧืूࠓ݄։͖·͢ ! !
!ळ༿ݪ ! IUUQTQJDPSVCZLBJHJPSH 64 / 64