JavaScript SyntaxError: The requested module ‘./notes.mjs’ does not provide an export named ‘default’から考える適切なimport/exportの使い方

まずは該当コードを確認しよう。自作モジュール notes.mjsからいくつかの関数をインポートしたかった。

import chalk from "chalk";
import yargs from "yargs";
import notes from "./notes.mjs"

yargs(process.argv.slice(2))
    .usage('Usage: $0 <command> [options]')
    .command('add', 'add note', 
    function (yargs) {
        return yargs
        .option('title', {
            alias: 't',
            default: '',
            demandOption: true})
        .option('body', {
            alias: 'b',
            default: '',
            demandOption: true})
        }, 
    function(argv){
            notes.addNotes(argv.title, argv.body)
            // console.log(`Title: ${argv.title} Body: ${argv.title}`)
        }
    )
    .example('$0 add --title hoge', 'add title "hoge"')
    .help('h')
    .alias('h', 'help')
    .argv;

しかしながらこのコードを実行しようとすると以下エラーが発生。

node app.mjs add --title hoge --body huga
file:///Users/user/node-js-basics/notes-app/app.mjs:3
import notes from "./notes.mjs"
       ^^^^^
SyntaxError: The requested module './notes.mjs' does not provide an export named 'default'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:127:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:193:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:341:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

Node.js v17.6.0

正直このシンタックスエラーの意味がよくわからなかった。「default」ってなんぞや・・・。

ちなみに自作モジュールがこちら。

import * as fs from 'fs'
import { add } from './utils.mjs'

const getNotes = function() {
    return 'Your notes...'
}

export const addNotes = function(title, body) {
    const notes = loadNotes()
    console.log(notes)
}

const loadNotes = function() {
    try {
        const dataBuffer = fs.readFileSync('notes.json')
        const dataJSON = JSON.toString(dataBuffer)
        return JSON.parse(dataJSON)
    } catch(e) {
        return []
    }
}

そこで我らがMDNドキュメントを見ると目から鱗。importの構文を全く理解できていなかったことが発覚。

import defaultExport from "module-name";
import * as name from "module-name";

先述のコードは上記の1行目と同じ表現になるがこちらは以下のように説明されている。

defaultExport:モジュールからのデフォルトのエクスポートを参照する名前。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import

つまりexport defaultで宣言したもののみがこの構文でimportできると理解(知らんけど)。

続いて2行目については以下のように説明されている。

name: インポートを参照するとき名前空間のように用いられるモジュールオブジェクトの名前。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import

つまり任意のモジュールに含まれる要素を任意のオブジェクト名でimportするときはこの表現を使え、と理解(知らんけど)。

答え

冒頭のimprot文の表記をちょこっと変えただけ。

import chalk from "chalk";
import yargs from "yargs";
import * as notes from "./notes.mjs"

併せて読んでおきたい

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export

Node.js yargsの使い方

yargs

https://www.npmjs.com/package/yargs

yargs-parser

https://www.npmjs.com/package/yargs-parser

yargsとyargs-parserの違い

yargsがyargs-parserを包括している感じでしょうか?実際の挙動を見てみます。

import yargsp from "yargs-parser";
import yargs from "yargs";
import process from "process";

console.log(yargs(process.argv.slice(2)));
console.log(yargs(process.argv.slice(2)).argv);
console.log(yargsp(process.argv.slice(2)));
$ node app.mjs add --title="Things to buy"
YargsInstance {
  customScriptName: false,
  parsed: false,
  '$0': 'app-chap16.mjs',
  argv: [Getter]
}
{ _: [ 'add' ], title: 'Things to buy', '$0': 'app-chap16.mjs' }
{ _: [ 'add' ], title: 'Things to buy' }
  • yargsは引数を与えることでYargInstanceというオブジェクトになります。
  • yargsの引数パース結果はyargs.argvで参照できます
  • yargs-parserはyargsのそれとは若干結果が異なります
    • yargsはパース結果に実行ファイルそのものを含むのに対してyargs-parserは明示的に与えた引数のみを結果に含みます

実装例1. yargsを使った基本的なパース

コマンドラインからコマンドをパースさせます。

yargs(process.argv.slice(2))
    .usage('Usage: $0 <command> [options]')
    .command('count', 'Count the files in a directory', function (yargs) {
        console.log('count items!')
    })
    .command('list', 'list files of a directory:', function (yargs) {
        console.log('list items!')
    })
    .example('$0 count', 'count the lines in the given file')
    .help('h')
    .alias('h', 'help')
    .argv;

以下のコマンドを実行します。想定通りの結果になっているでしょうか?

$ node app.mjs count
count items!

$ node app.mjs list 
list items!

$ node app.mjs --help
Usage: app.mjs <command> [options]

Commands:
  app.mjs count  Count the files in a directory
  app.mjs list   list files of a directory:

Options:
      --version  Show version number                                   [boolean]
  -h, --help     Show help                                             [boolean]

Examples:
  app.mjs count  count the lines in the given file

実装例2. コマンドオプションの設定

countやlistといったコマンドにオプションを追加してやります。以前はbuilderとしてオプションを与えていたみたいですが・・・。

yargs(process.argv.slice(2))
    .usage('Usage: $0 <command> [options]')
    .command('count', 'Count the files in a directory', function (yargs) {
        return yargs.option('directory', {
            alias: 'd',
            default: './'
        })
        console.log('count items!')
    })
    .command('list', 'list files of a directory:', function (yargs) {
        return yargs.option('directory', {
            alias: 'd',
            default: './'
        })
        console.log('list items!')
    })
    .example('$0 count', 'count the lines in the given file')
    .help('h')
    .alias('h', 'help')
    .argv;

以下コマンドを実行してみます。countのみ確認してますが無事オプションは追加されたようです。

$ node app.mjs count --help
app.mjs count

Count the files in a directory

Options:
      --version    Show version number                                 [boolean]
  -h, --help       Show help                                           [boolean]
  -d, --directory                                                [default: "./"]

しかしながらコマンド実行後の挙動が何もないのは寂しいのでコードを変更して実際の挙動を確認していきます。addコマンドのtitleオプションを指定してコンソール上にタイトルを表示させます。

yargs(process.argv.slice(2))
    .usage('Usage: $0 <command> [options]')
    .command('add', 'add note', 
    function (yargs) {
        return yargs.option('title', {
            alias: 't',
            default: '',
            demandOption: true})
        }, 
    function(argv){
        console.log(`Title: ${argv.title}`)
        }
    )
    .example('$0 add --title hoge', 'add title "hoge"')
    .help('h')
    .alias('h', 'help')
    .argv;

以下コマンドを実行していきます。

$ node app.mjs add --help      
app.mjs add

add note

Options:
      --version  Show version number                                   [boolean]
  -h, --help     Show help                                             [boolean]
  -t, --title                                           [required] [default: ""]

$ node app.mjs add --title hoge
Title: hoge

まとめ・所感

  • yargsは多機能パーサー、yargs-parserは単機能パーサーといった理解に落ち着くとします

M1 macでnode.jsの開発環境を整備する

パッケージのインストール

  • node.js

$ brew install node

  • nvm(node version manager)
    • node.jsのバージョンを管理・切り替え

$ brew install nvm

インストール完了後に以下を実施

$ mkdir ~/.nvm # nvmのワーキングディレクトリ
$ vim ~/.zshrc # nvmの環境変数を設定、以下の記述を構成ファイルに追加する

export NVM_DIR=”$HOME/.nvm”
[ -s “/opt/homebrew/opt/nvm/nvm.sh” ] && \. “/opt/homebrew/opt/nvm/nvm.sh” # This loads nvm
[ -s “/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm” ] && \. “/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm” # This loads nvm bash_completion

ただしNVM_DIR は任意の場所に設定できますが、/opt/homebrew/opt/nvm から変更しないままだと、アップグレード/再インストール時に nvm でインストールされた node はすべて壊れてしまう、という警告が出ています。これはどう対応したら良いのだろうか??#TODO

  • npm(node package manager)
    • node.jsのパッケージ管理

$ brew install npm

それぞれインストール完了後にコマンドライン上でnode/nvm/npmと叩いて正しく呼び出せるか確認すると良いでしょう。

ローカルサーバーを立てる

適当なリポジトリを作っておいて公式ドキュメントをもとにコードを写経してみます。

コードを書き終わったら以下コマンドを実行してサーバーを走らせます。

$ node app.js
Server running at http://127.0.0.1:3000/

localhost:3000にアクセスするとHellor Worldが返されます。

デバッグ

先ほどのコードを以下コマンドで実行することでデバッグクライアントが待機するようです。

$ node –inspect app.js
Debugger listening on ws://127.0.0.1:9229/21ab3436-839a-405f-8081-dd3dce1cf83a
For help, see: https://nodejs.org/en/docs/inspector
Server running at http://127.0.0.1:3000/

コマンドのレスポンス1行目がインスペクタクライアントのURLになります。ChromiumベースのWebブラウザでchrome://inspect/#devicesと入力してインスペクタクライアントを開いてサーバーの挙動を確認すると良いかもしれません。

ファイルシステムAPIを使う

htmlを使わない環境下でも使える様々なAPIがあるようです。たとえば以下。

const fs = require('fs');

fs.writeFileSync('notes.txt', 'Hi there!')
  • このrequireはcommonJSというサーバーサイドなどの環境下におけるJSの仕様らしい
    • Wikipedia見る限りそんな主流というわけでもないのか・・・?

ECMAScript形式だと以下のようになる

import * as fs from 'fs';

fs.writeFileSync('notes.txt', 'Hi there!')

ただし上記の形式の場合は以下のように拡張子に”m”をつけて実行する。

$ node app.mjs

外部モジュールの呼び出し

まずはメインファイル

import { name } from './utils.mjs'
console.log(name);

次にutilsファイル

console.log('utils.mjs')
export const name = 'Mike';

以下コマンドを実行するとutils内の関数呼び出しとexportされた変数を参照できていることがわかる。

$ node app.mjs

util.js
Mike

さらに関数のexportも確認する。

console.log('util.js')

export const name = 'Mike';

export const add = function(a, b) {
    return a + b;
};
import { name, add } from './utils.mjs'

console.log(name);

console.log(add(2, 1));

以下コマンドを実行すると関数addを呼び出せていることが確認できる。

$ app.mjs

util.js
Mike
3

気づき(なんでもあり)

  • シングルクォート「’」とバッククォート「`」は文字列の処理において使い分けられる
    • 後者は文字列の変数置換”${hoge}”で使われる
  • requireかimportか
    • commonJSかECMAScriptのどちらに従うかっぽいが後者のやり方がようわからんかった。

microマックイーンを使ってライントレース機能をプログラムする/第42回アソビワークショップ開催報告

何をやったか

小学3年生は

  • モーターの操作
  • ラインセンサーの使い方
  • 真偽値表を使ったライントレースの理論

小学1年生は

  • とりあえずライントレースできるプログラムを使ってみる
  • 自分なりにライントレースしてみる

振り返り

「どうやったらライントレースできるのか?」を整理して教えようとしたがそれが良くなかった気がする。というのも1年生のmayuchikuwaさんは理屈抜きで「自分の考える最強の動き方」をまず自力で考えていた。その失敗を経て初めて理屈を教えた方が食いつきが良かったのでは?と思った。

当日のPR資料

豆を投げつけたくなる鬼ロボットを作ろう/第41回アソビワークショップ開催報告

明けましておめでとうございます。2022年最初のイベントは報告記事を書き忘れました・・・。

表題のテーマで「鬼ロボット」を作りました。と言っても鬼限定にはせず、各々好きなものをロボットにかぶせてもらいました。発端はmayuchikuwaさんの「亀ロボットを作りたい」から始まりました。

簡単な作り方は以下の記事に書いてますのでよければご覧ください。

https://loochs.org/what-can-make-micro-maqueen-looks-better/

そういえば作品の写真をあまり撮れてなかった・・・。

What can make micro-maqueen looks better?マイクロマックイーンの見栄えをどうにかしたい

これの見た目どうにかならんのか?

https://www.dfrobot.com/product-1783.html

これを見たら閃いた

発砲どんぶり(お椀)で亀を作る:自由工作

上記リンク先の発泡どんぶりそのままだとデコレーションしづらい(油性ペン使えない)ので以下のアイテムを使うことにした。紙製かつ100円で環境にも優しいらしいので工作にはもってこい。

https://iyec.omni7.jp/detail/4973631533420

これだけだとマックイーンとの接着ができないので以下のアイテムを追加購入。

できたのがこちら

作ってみた感想

紙の土台だと工作もしやすいので良き。例えばサーボモータ乗っけて腕をつけるとかできそうかなと。

ArduinoでRFIDモジュール(MFRC522)を使ってタグに名前の書き込み・読み込みをする

今回使うもの

Aruduino UNO

MFRC522

使用する前のセッティング

以下の記事を参考にしてください。

非接触ICタグで遊ぼう!ArduinoでRFIDリーダRC522を使う方法

とりあえず私はこんなかんじ。無駄にマイクロビット繋げてますけど気にしないでください。

コード

ライブラリのサンプルをそのまま使います。

https://github.com/miguelbalboa/rfid/tree/master/examples

まずは書き込みから。

/*
 * Write personal data of a MIFARE RFID card using a RFID-RC522 reader
 * Uses MFRC522 - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 *
 * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout
 *
 * Hardware required:
 * Arduino
 * PCD (Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
 * PICC (Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203.
 * The reader can be found on eBay for around 5 dollars. Search for "mf-rc522" on ebay.com. 
 */

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

void setup() {
  Serial.begin(9600);        // Initialize serial communications with the PC
  SPI.begin();               // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card
  Serial.println(F("Write personal data on a MIFARE PICC "));
}

void loop() {

  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  Serial.print(F("Card UID:"));    //Dump UID
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
  }
  Serial.print(F(" PICC type: "));   // Dump PICC type
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));

  byte buffer[34];
  byte block;
  MFRC522::StatusCode status;
  byte len;

  Serial.setTimeout(20000L) ;     // wait until 20 seconds for input from serial
  // Ask personal data: Family name
  Serial.println(F("Type Family name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 30) ; // read family name from serial
  for (byte i = len; i < 30; i++) buffer[i] = ' ';     // pad with spaces

  block = 1;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("PCD_Authenticate() success: "));

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  block = 2;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, &buffer[16], 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  // Ask personal data: First name
  Serial.println(F("Type First name, ending with #"));
  len = Serial.readBytesUntil('#', (char *) buffer, 20) ; // read first name from serial
  for (byte i = len; i < 20; i++) buffer[i] = ' ';     // pad with spaces

  block = 4;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, buffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));

  block = 5;
  //Serial.println(F("Authenticating using key A..."));
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  // Write block
  status = mfrc522.MIFARE_Write(block, &buffer[16], 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
  else Serial.println(F("MIFARE_Write() success: "));


  Serial.println(" ");
  mfrc522.PICC_HaltA(); // Halt PICC
  mfrc522.PCD_StopCrypto1();  // Stop encryption on PCD

}

すると以下のような出力がシリアルモニターに表示されます。

Type Family name, ending with #

そしたら入力欄にファーストネーム「hoge#」を打ち込みましょう。入力の最後は#で終わらせる必要があります。すると以下の出力が続きます。

PCD_Authenticate() success:
MIFARE_Write() success:
MIFARE_Write() success:
Type First name, ending with #

最後に「taro#」と打ち込めば完了です。

次に読み込み。

/*
 * Initial Author: ryand1011 (https://github.com/ryand1011)
 *
 * Reads data written by a program such as "rfid_write_personal_data.ino"
 *
 * See: https://github.com/miguelbalboa/rfid/tree/master/examples/rfid_write_personal_data
 *
 * Uses MIFARE RFID card using RFID-RC522 reader
 * Uses MFRC522 - Library
 * -----------------------------------------------------------------------------------------
 *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
 *             Reader/PCD   Uno/101       Mega      Nano v3    Leonardo/Micro   Pro Micro
 * Signal      Pin          Pin           Pin       Pin        Pin              Pin
 * -----------------------------------------------------------------------------------------
 * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
 * SPI SS      SDA(SS)      10            53        D10        10               10
 * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
 * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
 * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
 *
 * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout
*/

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9           // Configurable, see typical pin layout above
#define SS_PIN          10          // Configurable, see typical pin layout above

MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance

//*****************************************************************************************//
void setup() {
  Serial.begin(9600);                                           // Initialize serial communications with the PC
  SPI.begin();                                                  // Init SPI bus
  mfrc522.PCD_Init();                                              // Init MFRC522 card
  Serial.println(F("Read personal data on a MIFARE PICC:"));    //shows in serial that it is ready to read
}

//*****************************************************************************************//
void loop() {

  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;

  //some variables we need
  byte block;
  byte len;
  MFRC522::StatusCode status;

  //-------------------------------------------

  // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    return;
  }

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }

  Serial.println(F("**Card Detected:**"));

  //-------------------------------------------

  mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //dump some details about the card

  //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));      //uncomment this to see all blocks in hex

  //-------------------------------------------

  Serial.print(F("Name: "));

  byte buffer1[18];

  block = 4;
  len = 18;

  //------------------------------------------- GET FIRST NAME
  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  status = mfrc522.MIFARE_Read(block, buffer1, &len);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //PRINT FIRST NAME
  for (uint8_t i = 0; i < 16; i++)
  {
    if (buffer1[i] != 32)
    {
      Serial.write(buffer1[i]);
    }
  }
  Serial.print(" ");

  //---------------------------------------- GET LAST NAME

  byte buffer2[18];
  block = 1;

  status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 1, &key, &(mfrc522.uid)); //line 834
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Authentication failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  status = mfrc522.MIFARE_Read(block, buffer2, &len);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("Reading failed: "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }

  //PRINT LAST NAME
  for (uint8_t i = 0; i < 16; i++) {
    Serial.write(buffer2[i] );
  }


  //----------------------------------------

  Serial.println(F("\n**End Reading**\n"));

  delay(1000); //change value if you want to read cards faster

  mfrc522.PICC_HaltA();
  mfrc522.PCD_StopCrypto1();
}
//*****************************************************************************************//

すると以下が出力されます。

**Card Detected:**
Card UID: xxxx
Card SAK: xxxx
PICC type: MIFARE 1KB
Name:
taro hoge
**End Reading**

注意点

一点はまったポイントがあるので記しておきます。書き込み時に以下のような出力が出る場合があります。

PCD_Authenticatie Failed…

MFRC522では各種操作の前に以下リンク先の205行目にあるPICC_CMD_MF_AUTH_KEY_Aを用いてタグの認証を行います。

https://github.com/miguelbalboa/rfid/blob/master/src/MFRC522.h

上記エラーはこの認証が通らなかったことを意味するのですが、事前の鍵情報の書き込みをしてない限りそれはあり得ません。

ではなぜ起こったのか?それは「書き込みが完了する前にタグをリーダから離してしまった」からです。書き込みが完了するまでは以下のようにしっかりとタグを読み込ませておかないと認証が失敗してしまうので気を付けてください。