Pythonロボティクスコース レッスン 39

テーマ.10-2 光を使った通信装置の制作

コンピュータ上での文字データの表し方を学ぼう

このレッスンで学ぶこと

このレッスンでは、コンピュータ上で扱うデータ量の表し方や、文字データをコンピュータ上で扱うための仕組みを学習します。

コンピュータで扱うデータ量の表し方

テーマ.10-1では、コンピュータ内部の計算は、簡単に言えば、電子回路のスイッチのオン/オフの切り替えによって行われていることを説明しました。

そして、スイッチのオン/オフによって、回路にかかる電圧は低い状態(LOW)と高い状態(HIGH)に変化し、それぞれをデジタルの「0(LOW)」と「1(HIGH)」に置き換えることで、コンピュータは2進数で数を扱うことができました。

実は数だけでなく、文字や写真、動画などコンピュータが扱うすべてのデータが、「0」と「1」の2つの数字で表されています。

コンピュータ上では1桁の「0」と「1」で表される情報がデータの最小単位となり、この単位を「bit(ビット)」といいます。bitは「binary(2進数)」と「digit(桁)」を組み合わせた造語です。また、コンピュータ上でデータ量を表すときは、bitではなく「byte(バイト)」という単位が使用されます。一般的に、1byteは8bitで表されるデータ量を表しています。(bitは桁数)

パソコンやスマートフォンで使用するデータの通信量を表すときに使われる「G(ギガ)」という言葉は、「Gigabyte(ギガバイト)」の略称です。「Giga」という接頭辞が10億(109)を表しているため、「1G」は「10億byte」のデータ量を指しています。

*-*-*-*-

(注意:2進数の考え方)
1byte=8bit
1KiB(キビバイト)=1024byte(2^10)
1MiB(メビバイト)=1024*1024byte
1GiB(ギビバイト)=1024*1024*1024byte =1,073,741,824byte

実際には、コンピュータにおける1キロバイト (KB) は、1024バイトではなく、1000バイトで定義される場合が一般的です。この定義はSI接頭語の規定に基づいています。

具体的には、以下の通りです:

  • 1キロバイト (KB) = 1000バイト

これはSI接頭語の「キロ」が1000を意味するためです。この定義は国際標準化機構(ISO)や国際単位系(SI)によって規定されています。

ただし、コンピュータの技術用語としては、2進数の性質から「キロバイト」を1024バイトとする用語も使われてきました。これは、2^10 (1024) が近似的に1キロバイトに相当するためです。

しかし、近年では国際的な標準化の進展により、正確な意味での「キロバイト」は1000バイトとされることが多くなっています。したがって、正確な場面では1000バイトが用いられるべきですが、歴史的には1024バイトを指す場合も見られます。

このように、コンピュータ業界における用語の定義は時とともに変化しており、正確な文脈に応じてどちらの定義が適用されているかを理解する必要があります。

【 データ量を表すときに使われる接頭辞 】
接頭辞意味
K(キロ)1000(103
M(メガ)100万(106
G(ギガ)10億(109
T(テラ)1兆(1012
P(ペタ)1000兆(1015

コンピュータ上での文字データの表し方

上では、コンピュータが扱う文字データも「0」と「1」で表されていることを紹介しました。例えば、英語のアルファベット1文字は、Pythonの標準的な設定では、1byte(8bit)のデータ量で表されています。

↓2進数は「01000001」です。(画像は間違い)

この1byteが表す数値(番号)は、「文字コード」または、「コードポイント」と呼ばれています。つまり、コンピュータ上では直接文字データを扱うことができないため、代わりに固有の番号に置き換えているということです。

そして、どの文字に対してどの文字コードを割り当てるのかを定めているのが「文字集合」です。元々は言語によって異なる文字集合が利用されていましたが、現在ではインターネットが普及し、世界中の様々な人々が共通のWebサイトやWebサービスを利用するようになったため、多言語に対応した「Unicode(ユニコード)」という文字集合が広く使われるようになりました。UnicodeはPythonでも標準の文字集合として採用されています。

下の表は、Unicodeで英語のアルファベットや記号に割り振られている文字コードの一例です。

【 Unicodeの文字コードの一例 】
アルファベット・記号文字コード(16進数)
!33(0x21)
?63(0x3F)
A65(0x41)
B66(0x42)
C67(0x43)
a97(0x61)
b98(0x62)
c99(0x63)

文字コードは、ord()関数を使って確認することもできます。

Pythonのord()関数のordは、「ordinal」(序数)を略したものです。この関数は、文字のUnicodeコードポイント(整数値)を返します。例えば、ord('A')は65を返します。

【 サンプルコード 3-1-1 】
(実行結果)

また、反対にchr()関数を使うと、文字コードから文字に変換することもできます。

Pythonのchr()関数のchrは、「character」(文字)を略したものです。この関数は、整数値を対応するUnicode文字に変換します。例えば、chr(65)は文字「A」を返します。

【 サンプルコード 3-1-2 】
(実行結果)

このように、特定の文字をUnicodeのような文字集合で定義された文字コードへ変換することを「エンコーディング」といいます。反対に文字コードから文字へ変換することを「デコーディング」といいます。

unicodeでは、代表的なエンコーディング方式として「utf-8」と「utf-16」があります。これら2つの違いは、主に文字コードのデータ量、つまり、何byteで1文字を表すかという点にあります。

「utf-8」は、1文字を1~6byteで表す方式で、英語のアルファベットは1byteに変換されますが、日本語で使う漢字や平仮名、片仮名は3byteで表されます。

一方で、「utf-16」は2byte単位で表す方式で、英語のアルファベットも、日本語の漢字や平仮名、片仮名も、どちらも2byteで表されます。そのため、文章内に英語が多い場合は「utf-8」の方がデータ効率が良く、日本語が多い場合は「utf-16」の方がデータ効率が良いと言えます。

Pythonでは、「utf-8」が標準のエンコーディング方式として設定されています。

そして、エンコーディングを行うときは、文字列のencode()メソッドを使います。エンコーディング後は「バイト列」というデータ型に変換されます。バイト列についての詳しい説明は次のチャプターで行います。反対にデコーディングのときは、バイト列のdecode()メソッドを使います。

【 サンプルコード 3-1-3 】
(実行結果)

実行結果を確認すると、バイト列に変換された証しとして、先頭にbが付いています。

バイト列

バイト列は1バイトのデータが並んだ集合です。文字列や数値の場合は、同じ1バイト単位のデータであっても、文字や数であるという意味が与えられています。一方でバイト列には、特定の形式や意味が与えられていません。つまり、ただの「0」と「1」の並びという扱いになります。

さきほどは文字のエンコーディングを英語のアルファベットで行ったため、print文で出力した結果を見てもバイト列であることが分かりづらくなっていましたが、日本語をエンコーディングして、出力すると、3byteのバイト列に変換されていることが確認できます。

※ 日本語が入力できない場合は、以下のサンプルコードをそのままコピー&ペーストして実行してください。
【 サンプルコード 4-1-1 】
(実行結果)

バックスラッシュ(\)で区切られた一画が1byte分のデータです。「x」は16進数であることを表しているため、その後ろの2文字で1byteとなっています。

具体的には、b'\xe3\x81\x82' の各バイトは以下のように解釈されます:

  1. \xe3 (227)
  2. \x81 (129)
  3. \x82 (130)

これらのバイトが組み合わさって、UTF-8 でエンコードされた日本語の文字「\あ\」を表現しています。UTF-8 は、1バイトから4バイトの可変長エンコーディングであり、各文字をユニコードに対応するバイト列にエンコードします。

※ 1桁の16進数は4bitで表せるため、2桁の16進数で1byteになります。

*-*-*-*-*-*-*-*-*-

16進数とビット

16進数(hexadecimal)は、1桁で0から15(0-F)までの値を表現します。1桁の16進数は4ビットで表現できます。

  • 0 (0000)
  • 1 (0001)
  • 2 (0010)
  • 3 (0011)
  • 4 (0100)
  • 5 (0101)
  • 6 (0110)
  • 7 (0111)
  • 8 (1000)
  • 9 (1001)
  • A (1010)
  • B (1011)
  • C (1100)
  • D (1101)
  • E (1110)
  • F (1111)

2桁の16進数で1バイト

8ビット(1バイト)は、4ビットの2倍で、2桁の16進数で表現されます。

例:

  • 0xE3(16進数) = 11100011(2進数)

0xE3 は2桁の16進数で、これは8ビット(1バイト)になります。

例として b'\xe3\x81\x82'

b'\xe3\x81\x82' の各バイトは次のように解釈されます:

  1. \xe3(16進数) = 227(10進数) = 11100011(2進数)
  2. \x81(16進数) = 129(10進数) = 10000001(2進数)
  3. \x82(16進数) = 130(10進数) = 10000010(2進数)

各バイトは8ビットで構成されており、3バイト(24ビット)で1文字の「\あ\」を表現しています。これは、UTF-8エンコーディングの特徴です。UTF-8は、1バイトから4バイトの可変長エンコーディングであり、各文字をユニコードに対応するバイト列にエンコードします。

このように、2桁の16進数は1バイト(8ビット)を表現し、文字列をバイト列として扱う際には非常に重要です。

*-*-*-*-*-*-*-*-*-*-

また、文字列だけでなく、数値とバイト列も相互に変換することができます。それには、整数型のto_bytes()メソッドとintfrom_bytes()メソッドを使います。

【 サンプルコード 4-1-2 】
(実行結果)

to_bytes()メソッドの第1引数で、変換後のbyte数を指定します。「15777200」という数値は、ちょうど3byteで表すことができるため、「3」を渡しています。第2引数に渡した「"big"」は、バイト列化するときのデータの並び順を表していて、「ビックエンディアン("big")」と「リトルエンディアン("little")」の2つの方式があります。

【 ビックエンディアンとリトルエンディアンの違い 】

実際にさきほどのサンプルコードをリトルエンディアンに変更してみましょう。

【 サンプルコード 4-1-3 】
変更【3行目、6行目】
(実行結果)

実行結果からもバイト列の並び順が入れ替わっていることが分かります。ビッグエンディアンでバイト列化してリトルエンディアンで数値へ戻すと、内容が変わってしまうため、どちらの方式でバイト列化されたものなのかを必ず確認するようにしましょう。

ビット演算

ここまでで、様々なデータがbitやbyteという情報量の単位で表されていることを確認してきました。実はPythonも含めて多くのプログラミング言語では、1bit単位での演算処理をサポートしています。

5. 1 1bit単位での論理演算(AND、OR、XOR)

2つのデータを1bit単位で論理演算するときは、次の演算子を使います。

演算子内容 
&論理積(AND) 
|論理和(OR) 
^排他的論理和(XOR) 

それぞれ、同じ桁のbitの組み合わせで得られる結果は次のようになります。

  • 論理積(AND)
ABA AND B
000
100
010
111
  • 論理和(OR)
ABA OR B
000
101
011
111
  • 排他的論理和(XOR)
ABA XOR B
000
101
011
110

実際に8bitの2進数で表したデータを用意してこれらの演算子を使ってみましょう。

前のレッスンでは、"0b101""0x1f"のように2進数や16進数を文字列として定義して扱いましたが、ここでは""で囲まずに数値として定義します。

では、上のAとBの2つの数値に対して、1bit単位での論理積(AND)と論理和(OR)、排他的論理和(XOR)をそれぞれ行い、結果を表示してみましょう。

【 サンプルコード 5-1-1 】
追加【4行目~6行目】
(実行結果)

AとBは1bit単位で論理演算が行われていますが、結果が数値として扱われているので、print文で表示すると10進数に書き換えられてしまいます。そこで、数値を2進数の文字列に変換するbin()関数を使います。上のサンプルコードを以下のように書き直して、もう一度実行してみましょう。

【 サンプルコード 5-1-2 】
変更【4行目~6行目】
(実行結果)

今度は2進数で結果を確認することができました。

5. 2 1bit単位での反転(NOT)

論理演算には反転の「NOT」もあります。1bit単位で反転を行うときは、演算子「~」を使います。まずは、以下のサンプルコードを実行して結果を確認してみましょう。

【 サンプルコード 5-2-1 】
(実行結果)

もしかすると、ただ各桁の「0」と「1」が反転するだけという結果を予想していたのではないでしょうか。しかし実際はそのような結果とはなりません。

今度は、bin()関数を使わずに結果を表示してみましょう。

【 サンプルコード 5-2-2 】
変更【3行目】
(実行結果)

~」で反転を行うと、「x」を元の数値として「-(x+1)」が返ってきます。そのため、2進数の文字列で表すと先頭に-の符号が付き、最下位のビットに「1」が加算されることになります。

5. 3 ビットシフト

Pythonには論理演算以外にも、1bit単位で左や右にデータをシフトするための演算子が用意されています。

左にシフトするときは「<<」の演算子を使い、右にシフトするときは「>>」の演算子を使います。また、何桁分シフトするのかをこれらの演算子の後に続けて数値で指定します。実際に以下のサンプルコードを実行して、結果を確認してみましょう。

【 サンプルコード 5-3-1 】
(実行結果)

普段はあまり1bit単位で演算をする機会は少ないかもしれませんが、情報のデータ量を削減したり、計算に必要な処理コストを下げたりするときに、これらの演算が役立ちます。

光通信用の装置の組立て

レッスンの前半では、コンピュータ上で扱う数値や文字、画像などのデータが「0」と「1」の2進数で表されていることや、「bit」や「byte」という情報量の単位があることを確認してきました。このようなデータの表し方は、コンピュータどうしで情報をやり取りするときにもメリットがあります。

コンピュータ間では、データを電気的な信号に変換してお互いに伝達しています。例えば、パソコンで作成したプログラムをStuduino:bitへ転送するときは、USBケーブルを介して、電圧が高い状態(HIGH)と電圧が低い状態(LOW)の変化を電気的な信号として送っています。例えばこの信号で、電圧の高い状態を「1」、電圧の低い状態を「0」としてルールを決めると、1bitずつ情報を送ることができます。

また、インターネット通信では、より多くのデータを高速で送るために、電気的な信号をさらに光の信号に変えて情報を伝達しています。

情報伝達に使うケーブルには、「光ファイバー」という素材が利用されています。光ファイバーは、一定の入射角を超えて入った光をすべて反射する性質(全反射)があり、光を外に漏らさずに内部で反射を繰り返しながら、遠く離れたところまで信号を届けることができます。

【 光ファイバーの構造 】

そして、光を利用した通信では、電圧の高低の代わりに光の点滅によって2進数の情報を送る仕組みになっています。

そこでレッスンの後半では、この光を利用した通信の仕組みを参考にして、「明るさの変化で1byte(8bit)の文字情報を送る光通信システム」を作成します。まずは、このシステムで使用する装置を組み立てましょう。

【 組み立てる装置 】

6. 1 組み立てに必要なパーツ

【 パーツ一覧 】
  • Studuino:bit×1
  • ブロック基本四角(黒)×4
  • ブロック基本四角(赤)×1
  • ブロックハーフB(黒)×2
  • ブロックハーフC(白)×6
  • ブロックハーフD(白)×4
【 アーテックブロックの形状 】

6. 2 組立説明書

以下のリンク先から組立説明書を確認しましょう。

光通信用装置の組立説明書

光の信号で文字情報を送受信するプログラムの作成

まずは、組み立てた装置を使って、どのように1byte(8bit)の文字情報の送信や受信を行うのかを確認していきましょう。

7. 1 組み立てた装置を使った通信方法

組み立てた装置は、手動で光の信号を作る仕組みになっています。黒色のブロックを左に押すと、光センサーが露出し、反対に右に引くと隠れます。つまり、この操作で光センサーに光を通す(明るい)/通さない(暗い)を切り替えることができ、疑似的に光の点滅を再現できます。

また、コンピュータ同士で通信を行う場合は、1秒あたりに送受信できる情報量(転送速度)を互いに合わせることで、情報を欠損することなく相手まで届けています。

【 転送速度の設定が異なる場合 】
【 転送速度の設定が同じ場合 】

ですが、今回は信号を手動で送るため、コンピュータどうしのように、転送速度を正確に合わせて通信することはできません。そこで、転送速度は落ちますが、おおまかな点灯状態の時間の長さで2進数の「0」と「1」を表すようにします。1秒以上の点灯状態(光センサーに光を通す)が続いた場合は「1」とし、それよりも短い場合は「0」としましょう。

また、情報の送信を始める前には、必ず相手に対して受信開始を要求しなければいけません。ここでは、2秒以上の点灯状態を続けることで受信開始を要求し、上位の桁から情報を送るようにします。

ここまでに説明した方法で、1byteで表現可能な1文字の情報を送ることができます。しかし、通信においては、何らかの影響によって送受信中に情報が欠落したり、別の情報に置き換えられたりしてしまうケースがあります。そのため、受信した情報に誤りがないかを検出するための技術が開発されています。

その中でも仕組みが簡単でよく知られているのが「パリティチェック」という手法です。パリティチェックは情報の最後に「パリティビット」と呼ばれる1bitの情報を加えることで誤りを検出します。このパリティビットの加え方には、「偶数パリティ」と「奇数パリティ」の2つがあります。

  • 偶数パリティ
    送信データの各ビットから「1」の個数を数え、その個数が奇数の場合は末尾に「1」のビットを追加し、偶数の場合は「0」のビットを追加することで、「1」のビット数が偶数になるように調整します。これによって、受信データの「1」のビット数の合計が奇数だった場合に誤りを検出できます。
  • 奇数パリティ
    送信データの各ビットから「1」の個数を数え、その個数が偶数の場合は「1」のビットを追加し、奇数の場合は「0」のビットを追加することで、「1」のビット数が奇数になるように調整します。これによって、受信データの「1」のビット数の合計が偶数だった場合に誤りを検出できます。

パリティチェックのプログラムは簡単に追加できるので、これから作成する光通信のプログラムにも取り入れてみましょう。

7. 2 プログラムの作成手順

では、上で確認した通信方法を実現するためのプログラムを作ります。このプログラムでは、以下の2つの機能を用意します。

  • ターミナルに入力された文字情報から送信用の2進数データを作成する機能
  • 光の信号を受信してターミナルにその信号が表す文字情報を表示する機能

信号は手動で送りますが、送る信号を自分で計算して用意するのは大変です。1つめの機能は、その手間を省くためのものです。

では、それぞれの機能を以下の関数にまとめていきましょう。

関数名機能
convert_letter_to_signal()関数ターミナルに入力された文字情報から、送信用の2進数のデータを作成する機能
receiver()関数光の信号を受信して、ターミナルにその信号が表す文字情報を表示する機能

■ convert_word_to_signal関数の作成

光の信号は、以下の手順で文字から変換した2進数の文字列を参考にして送ります。convert_letter_to_signal()関数ではこの変換を行い、パリティビットを追加したデータを作成します。

【 文字からパリティビットを付加した2進数文字列への変換手順 】

では、コードを書きながら順を追ってこの変換を行うコードを書いていきましょう。

まず、ord()関数で、ターミナルから入力された文字の文字コード(10進数の数値)を取得します。

次に、bin()関数で2進数の文字列に変換します。bin()関数で変換すると、先頭に2進数の表記であることを示す0bが追加されます。今回これは不要なため、文字列のスライス操作で0bの後に続く部分だけを取り出しましょう。

追加【3行目】

送信する文字情報はすべて1byte(8bit)に長さに固定します。しかし、bin()関数では数値が8bit未満で表せる場合、上位ビットの「0」は省略されてしまいます。そこで、文字列のformat()メソッドの書式変換で、8bitになるまで上位を「"0"」で埋め、どの文字が入力されても必ず8bitで表されるように調整しましょう。

追加【4行目】

最後にパリティビット(偶数パリティ)を末尾に加えて、結果を返します。

追加【6行目~11行目】
※ 数を2で割った余り(余剰の%演算子で求められる)が「1」であれば奇数と判断できます。

上のコードを実行して、ターミナルから関数を呼び出してみましょう。送信用の2進数データに変換できていることを確認してください。

■ receiver関数の作成

次に、受信側の処理をreceiver()関数にまとめます。

まずは、光センサーが隠れているときと、露出しているときに返す値をそれぞれ確認しておきましょう。新しく別のファイルを作成して、以下のサンプルコードを実行してください。

【 光センサーの値を習得するコード 】

それぞれの状態で光センサーの値が確認できたら、2つの状態を判別するためのしきい値を決めます。今回はより正確な判断が求められるため、2つのしきい値を設定しましょう。

では、元のプログラムに戻り、先頭にtimeモジュールとlightsensorオブジェクトをインポートするコードと、決めた2つのしきい値を定義するコードを追加しましょう。

追加【1行目~5行目】

2つのしきい値を使って受信処理のコードを書いていきます。

始めは、受信開始の要求を受けるまで待機します。待機中は一定時間(10ミリ秒)おきに光センサーの値を取得し、threshold_highより値が大きい場合は、点灯状態が継続しているものと判断します。そして、この継続回数を記録することで、2000ミリ秒以上の点灯状態が続いたかどうかを確認します。もし、途中で消灯状態に変わった場合は、この回数をリセットします。

追加【20行目~30行目】

継続回数が200回続いた後、消灯状態に切り替わると、24行目のwhile文のループを抜けて、データの受信を開始します。

追加【32行目~36行目】

受信開始後は、送られてきた信号を順番に受け取り、2進数に変換します。点灯状態の時間の長さを計測して、1秒以上続いた場合は「"1"」を、1秒未満の場合は「"0"」を文字列の末尾に追加しましょう。これをパリティビットを含む9bitのデータを受け取るまで繰り返します。

追加【38行目~52行目】

これで9bitのデータが受信できたので、最後にパリティチェックを行います。もし、誤りが検出された場合は、エラーメッセージを表示します。誤りが検出されなかった場合は、受信データ(2進数の文字列)を文字に変換してターミナルに表示します。

【 パリティチェック後の受信データから文字への変換手順 】
追加【54行目~58行目】

■ main関数の作成

ここまでで、convert_letter_to_signal()関数とreceiver()関数が用意できました。最後は、このシステムが使いやすくなるように、ボタンAを押すとターミナルから文字の入力を受け付けて、入力された文字をconvert_letter__to_signal()関数へ渡し、返ってきた結果を表示する処理と、receiver()関数をスレッドを立てて実行する処理をmain()関数にまとめてプログラムの完成です。

追加【2・3行目、64行目~74行目】

7. 3 プログラムの動作確認

完成したプログラムを実行して、ターミナルからmain()関数を呼び出します。練習として以下の文字情報を送信し、正しく受信できるかどうか確かめてみましょう。

文字convert_word_to_signal()関数の返り値
“A”“010000010”
“a”“011000011”
”?”“001111110”

(実行例)

もし、どうしてもエラーが修正できない場合は、自分の書いたコードに誤りがないか、下のプログラムの完成例と1行ずつ見比べてみましょう。

【 サンプルコード 7-3-1 】

課題:光の信号で色の情報を送信する

前のチャプターでは、1文字の情報をパリティビットを含めて9bitのデータとして送信しました。実際の通信では、データ量を増やすことで画像や動画など複雑な情報も送信しています。

そこで、この課題では【 サンプルコード 7-3-1 】を改造して、文字よりも多くのデータ量を必要とする「LEDの点灯色」の情報を送受信するシステムを制作してみましょう。

8. 1 色の情報の表し方

LEDの点灯色は、光の3原色から(R, G, B)のタプルで表現することができました。Studuino:bitでは、RGBの各色の光の強さを「0~31」の数値で設定します。最大値の「31」は、2進数に変換すると「11111」です。そのため、各色の光の強さは5bitで表すことができ、パリティビットも含めて16bit(R, G, B)を表すときのデータ量になります。

以上のことを踏まえた上で、RGBで表された色の情報を受信すると、ディスプレイの左上のLEDがその色で点灯するように、【 サンプルコード 7-3-1 】を改造してみましょう。

8. 2 プログラムの改造手順

基本的な処理の流れは【 サンプルコード 7-3-1 】と同じですが、以下の点を変更します。(

【 プログラムの変更点 】
  • convert_letter_to_signal()関数は、受け取るデータをRGBを表すタプルに変更。また、関数名もconvert_rgb_to_signalへ変更。
  • receiver()関数は、受け取ったデータが表す色でLEDを点灯するように変更。
  • main()関数は、ボタンAが押されたときに実行する関数名をconvert_rgb_to_signalに変更。

では、順番にコードを書き換えていきましょう。

■ convert_letter_to_signal関数の変更

まず、機能が変わるので関数名をconvert_rgb_to_signalに変更します。そして、引数に渡されるデータが文字ではなく、(R, G, B)のタプルに変わります。そのため、for文で要素を1つずつ取り出し、順番に2進数の文字列へ変換します。RGBの1色の情報は長さは5bitで固定することにして、長さが足りない場合は「”0”」で埋めましょう。

変更【8行目~18行目】

■ receiver関数の変更

データを受信する処理は、全長が9bitから16bitに変更になるだけです。パリティチェックを行い、受信したデータに誤りがなければ、先頭から5bitずつスライスで取り出して、10進数に変換します。そして、その値を使って(R, G, B)のタプルを用意してディスプレイの左上((0, 0))のLEDを点灯します。

変更【3行目、42行目、59行目~64行目】

■ main関数の変更

ターミナルから入力される情報が文字からタプルに変わります。しかし、input()関数で取得したデータは文字列として扱われるため、ターミナルに以下のように入力しても、文字列のデータになります。

この文字列から順番に数字を切り取って、int()関数で整数に変換して、そしてタプルとしてまとめるということもできますが、少し回りくどい感じがします。実は、Pythonには文字列の式をそのまま評価できる便利なeval()関数が用意されています。

例えば、eval()関数の引数に計算式を表す文字列を渡すと、その計算式を評価(演算)して、結果を返します。

タプルと同じ書き方をした文字列を渡すと、同じく評価してタプルを返します。

そこで、eval()関数を使って、次のコードでターミナルから入力された文字列をタプルに変換して、convert_rgb_to_signal()関数に渡すようにしてみましょう。

この変更を行ったコードが以下になります。入力で受け付けるタプルの要素の数は(R,G,B)の3つになるので、要素数が3でない場合は入力エラーとして扱いましょう。

変更【72行目~78行目】

8. 3 プログラムの動作の確認

以上ですべての変更が完了しました。完成したプログラムを実行して、動作を確認してみましょう。

【 サンプルコード 8-3-1 】

操作方法:

1. main()を入力
2. now waiting… と出るので、ボタンAを押す
3. Input rgb >>> とでるので(20,20,0)など、rgbコードを入力(入力を省いてもOK)
4.  数値変換される。その後スライダーを動かしてセンサーを露出し5秒くらい待ち、隠す。
5. Receiving starts. と出たら、スライダーで0と1を合わせていく(1秒以上明るい状態で1、未満で0)
6. 完成したら色が点灯(間違ってもカラーコードが合致すれば点灯する。なければエラー)

おわりに

9. 1 このレッスンのまとめ

今回は、コンピュータ上で扱うデータ量の表し方と、文字データの表し方について学習しました。

数値や文字、画像や動画コンピュータ上の情報は、すべて「bit」や「byte」という単位でそのデータ量を表すことができました。

また、データは&|^~の演算子を使うと、1bit単位で論理演算を行うことができました。

レッスンの後半では、実際の通信において、データが電気的な信号や光の信号に変換されて送信されていることを紹介し、光を利用して1byteの文字情報を送受信する簡単なシステムを作成しました。

テーマ.10-1と今回のレッスンを通して、コンピュータが内部でどのようにしてデータを取り扱っているのかを見てきました。難しい内容も多かったと思いますが、プログラミング言語を覚えるだけでなく、その根底にあるコンピュータの仕組みを理解することも、良いエンジニアになるためには必要です。

テーマ.10-3、テーマ.10-4とまた少し難しい話が続きますが、諦めずに取り組みましょう。

9. 2 次のレッスンについて

次回のレッスンでは、データを整理して保管する「データベース」の技術と、特定の文章のパターンを検索するときに使われる「正規表現とマッチング」の技術を学びます。

TOP