2020年7月27日月曜日

EagleでV-cutを指定してJLCPCBに注文する

*2020年07月29日 コピー手順を加筆しました。

V-cutは、端から端まで横断するV字の溝です。小さな基板を複数まとめて作り、実装が終わったところでポキンと折ります。スキージング回数は減るしpick&placeもまとめてできるし基板費用も安く済むので大変ありがたいです。

今までわたしは、Panel by JLCPCB、つまり1枚分の基板データを渡して、「あとは縦x枚、横y枚に割り付けてください」ってお願いするだけでした。

が、これだと同じ基板を複数作ることはできますが、異なった種類のものを同じ基板に割り付けるのは自分でやらないといけません。

ってことで、やってみました。

■コピー元のデータを用意する■

当然、Eagleを使って基板を設計します。今回は、秋月で売ってるGaN MOSFETブレイクアウト基板を2種類作りました。

■パネライズする■

出来上がったボードデータをそのままコピーしようとしても、部品番号が自動的にインクリメントされたりでうまくいきません。そこで、パネライズします。なお、パネライズしたあと、Saveしてはいけません。

パネライズはツールバーのオレンジ色の「Run ULPボタン」をクリックし、


検索欄にpaneと入力すると絞り込まれてpanelizeが残ります。panelizeをダブルクリックします。


これでtNames, bNamesが部品番号と切り離れた_tNames, _bNamesにコピーされます。

基板全体をGoup Copyし、SaveせずにWindowを閉じます(Panelizeした状態で上書きするとこの後の修正時などに掃除が大変)。

【追記07/29】全体のGroup Copyの際には 、以下の手順がオススメです。

  1. 表示LayerでShow Layersボタンを押して全レイヤーを選択
  2. 20 Dimensionだけを除外してOKボタン
  3. cmd+Aで全選択
  4. カーソル位置を原点にあわせて座標表示が0,0になるのを確かめてcmd+C
特に4番大事。これやるとペースト先で座標がずれません。え?知ってました? 私知らなかったです……。Windowsの方は適宜キーを読み替えてください。【追記終わり】


■新しいボードを作りペースト■

File->New->Boardで新しいbrdを作ります。回路schは不要です。

JLCPCBの場合、パネライズの最低サイズは70x70mmなのでこれ以上になるようにします。あまった部分に詰め込んでもいいですし、さくっとカットしてもいいです。

カーソルを原点に合わせてからcmd+Vでさっきコピーしたボード図をペーストし、正しい位置に置きます。同じものが複数必要ならば、正しい位置に必要な回数コピーします。saveします。複数の回路を組み込む場合は、パネライズとペーストを繰り返します。

基板の配置は、かならず碁盤の目のように縦横が並んでいないといけません。冒頭に書いたように、V-cutラインは端から端まで一直線に横切らないといけないからです。

■V-cutのラインを入れる■

アイコンからLineを選び、レイヤーとしてVscore、太さ0.5mmを指定します。太さは0でもいいですが、カットする幅が必要なのでカット幅がパターンやシルクをケズらないか確認する意味でも太さを指定した方が良いと思います。

端から端まで縦縦縦縦横横横……と線を入れていきます。なお、下の図で、下の方にやたらスキマが開いているのは、70x70mmというルールに後から気づいた(指摘された)からです……。 もともとの設計は60x50mmだったのですが、今回の基板、四隅の固定ネジの間隔は決まっているので、もったいないですが左右と下に余白を追加しました。なお、V-cutを依頼する場合、JLCPCBでは70x70mm、ALLPCBは80x80mmが最低外形寸法です。


■Gerber出力■

いつものCam processerを使ってGerberを出力しますが、いつもと違う点が2つ。processorによって違うかもしれないので、私がいつも使っているSystem Example -> Third Party -> OSH Park -> OSHPark_2_Layer.camを例に説明します。


まず、Gerber下のBoard Outlineには、Edit Layersのボタンから「Vscore」を追加します。これをしないとV-cut用に書いた線がgerberに出力されません。


Vscoreを追加すると、右の窓にgerber線が追加されます。


次に、Top Silkscreenでは、同様にEdit LayersボタンからもともとのtNamesを除外し、_tNamesを選びます。裏面にもシルクがある場合も同様にbNamesを除外して_bNamesを選びます。

あとは、Process Jobをクリックすれば、.zipが出来上がります。

■発注時の注意■

JLCPCBに注文を入力する際に、何種類のデザインが混在しているか、を忘れずに選びます。Different Designを2以上にすると自動的にDelivery Formatが「panel by Customer」に切り替わります。


あとは、いつものように発注しましょう。

あ、パネライズ初体験の場合は、チェックアウトの3.Submit Orderのところで「Review Before Payment」を選んだほうが良いと思います。私もやらかしてキャンセル→再注文になってしまいましたので……。

2020年7月15日水曜日

インターフォンからSMSを送りXiaomi mi bandへ通知



耳が聞こえないとインターフォンが聞こえないのでsmart bandに通知を送りたい。

ずっと考えていましたが、小雨降るお散歩中に簡単な方法を思いついたので、作ってみました。構想半年、アイデア30分、実装1時間、ブログ2時間ってやつです。

なお、タイトルは途中経過を大幅に端折ってます。

実際には
  1. 呼び鈴を押す
  2. インターフォンの画面が明るくなる
  3. APDS9930で明るさを検知
  4. ESP32でIFTTTを叩く
  5. IFTTTが私のiPhoneにSMSを送る
  6. iPhoneが着信
  7. Xiaomi mi bandに着信通知
という流れです。

■SMSは有償です■

ところでSMSの送信は有償です。今回使うclicksend.comだと1回約5円です。clicksend.comのアカウントを取得すると100円分のチャージが7日間使えます。実験であればそれで試せます。それでイケるとなったらカード番号など登録しましょう。

なんで自分ちのインターフォンが有償なんじゃい?!という気持ちがないではないですが、まぁ聴覚障害者として生まれちゃったのでしょうがないですね。

我が家の場合、比較的単価の安い荷物はみんな宅配ボックス、そうでない荷物や書留などについては電話で呼び出してもらってます。残りは生協ぐらいですが、生協は対面で受け取ると保冷ボックスが不要で手間がかからないというメリットがあって、それはまぁ5円に見合うのではないかと思っています。

■必要資材■


■IFTTTの設定■

アカウントのとり方などは他の方のブログを参考にしてください。以下の手順でIFTTTにサービスを追加します……「サービス」であってます?呼び方がわからん。
  1. ブラウザでHOME画面の右上、Createをクリック
  2. 「If」の後の「+」をクリック
  3. Search Servicesで「Webhook」と入力し「Webhooks」をクリック
    WebhooksはIFTTTの特定のURLを叩くと起動します。ESP32からのアクセスにうってつけですね。
  4. 「Receive a web request」をクリック
  5. 「Event Name」を入力します。今回は画面の明かりが点灯したことをトリガーにするので「light_up」と入力し、create triggerボタンをクリックします。
  6. If Thenのあとの「+」をクリック
  7. ClickSend SMSを選びます。
  8. 青い「Send SMS」をクリックします。
  9. Toにスマフォの電話番号を入力してCreate actionをクリックします。
  10. Finishをクリックします。
と、すみません。6-10のどこかでclicksend.comのアカウント取得画面に飛ぶのですが、スクショ取りそこねてしまいました。特に難しいことはないと思います。

ともあれ、これで特定のURLを叩くとSMSに通知が飛ぶ、というサービスができました。試すには
  1. ブラウザ上でIFTTTのHomeに戻る。
  2. Webhooksをクリック
  3. 右上のDocumentationをクリック
  4. 「Make a POST or GET web request to:」下の{event}にlight_upと入力
  5. value1, value2, value3には適当な文字列などを入れてみる。
    入力するとそれにつれてcurlのパラメータが変わっていきます。
  6. Test itのボタンをクリック
数秒後にさっきToで登録した電話番号にSMSが届きます。

ここでcurlの-d以降の部分をhttp postすれば中身がメッセージとして送られますが、 今回の用途ではSMSだけ送ればいいのでhttps以降だけを叩くのが簡単です。今回もそれで済ませてます。ごめんなさい。

■ハードウェアの接続■

私は以下のブログを参考にしました。ってわしのブログや。どんなつまらないことでもブログに残しておくべきだなぁとしみじみ思う今日このごろです。

CJMCU-9930ESP32
VL3.3v
GNDGND
VCC3.3v
SCL22
SDA21

ブログと異なり、INT - 2の配線は不要です。

■ESP32の実装■

APDS9930のサンプルプログラムを元に、http secureのサンプルを切り貼りしました。コピペエンジニアリングです。ごめんなさい。
//
//  WiFi Secure, IFTTT
//

#include <WiFiClientSecure.h>

#define ssid     "....ssid...."
#define password "....password...."

const char*  server = "maker.ifttt.com";  // Server URL

const char* test_root_ca = \
 "-----BEGIN CERTIFICATE-----\n" \
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" \
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" \
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" \
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" \
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" \
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" \
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" \
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" \
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" \
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" \
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" \
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" \
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" \
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" \
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" \
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" \
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" \
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" \
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" \
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" \
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \
"-----END CERTIFICATE-----\n";

WiFiClientSecure client;

void submit() {
  Serial.println("\nStarting connection to server...");
  if (!client.connect(server, 443))
    Serial.println("Connection failed!");
  else {
    Serial.println("Connected to server!");
    // Make a HTTP request:
    client.println("POST https://maker.ifttt.com/trigger/light_up/with/key/....api key.... HTTP/1.0");
    client.println("Host: maker.ifttt.com");
    client.println("Connection: close");
    client.println();

    while (client.connected()) {
      String line = client.readStringUntil('\n');
      if (line == "\r") {
        Serial.println("headers received");
        break;
      }
    }
    while (client.available()) {
      char c = client.read();
      Serial.write(c);
    }

    client.stop();
  }
}


//
//  APDS9930
//

#include <Wire.h>
#include <APDS9930.h>

// Global Variables
APDS9930 apds = APDS9930();
float ambient_light = 0; // can also be an unsigned long
uint16_t ch0 = 0;
uint16_t ch1 = 1;



//
//  setup
//

void setup() {
  // Initialize Serial port
  Serial.begin(115200);

  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  // attempt to connect to Wifi network:
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    // wait 1 second for re-trying
    delay(1000);
  }

  Serial.print("Connected to ");
  Serial.println(ssid);

  // Initialize APDS-9930 (configure I2C and initial values)
  if ( apds.init() ) {
    Serial.println(F("APDS-9930 initialization complete"));
  } else {
    Serial.println(F("Something went wrong during APDS-9930 init!"));
  }

  // Start running the APDS-9930 light sensor (no interrupts)
  if ( apds.enableLightSensor(false) ) {
    Serial.println(F("Light sensor is now running"));
  } else {
    Serial.println(F("Something went wrong during light sensor init!"));
  }

  delay(500);
}


//
//  loop
//
uint32_t prevMillis = 0;

void loop() {

  // Read the light levels (ambient)
  if (  !apds.readAmbientLightLux(ambient_light)) {
    Serial.println(F("Error reading light values"));
  } else {
    Serial.print(F("Ambient: "));
    Serial.println(ambient_light);

    uint32_t thisMillis = millis();
    if ((prevMillis == 0 || thisMillis - prevMillis > 180 * 1000) && ambient_light > 50) {

      submit();

      prevMillis = thisMillis;
    }

    //    char fstr[16];
    //    dtostrf(ambient_light, 5, 1, fstr);
    //    M5.Lcd.drawString(fstr, 80,  70);
  }

  delay(100);
}

2020年7月9日木曜日

Arduino IDE + DRV8835 + ステッピングモーター



Seeed Xiaoと秋月のDRV8835基板を使って、さくっと動かします。

モーターはオリジナルマインドから中古で買ったオリエントモーターの42mmサイズバイポーラー。定格17V。

XIAOとDRV8835の結線は以下の通り。

XIAODRV8835その他の接続相手
GNDGND外部電源のGND, Volumeのmin側
5V出力Vcc, MODE
3.3V出力Volumeのmax側
3AIN1
4AIN2
5BIN1
6BIN2
7Volumeの中間
AOUT1モーターの黒
AOUT2モーターの緑
BOUT1モーターの青
BOUT2モーターの赤
VM外部電源の+側(5-17V)


DRV8835をステッピングモーター用に使う場合には、MODEをHIGHにします。こうすると、AIN2, BIN2 = HIGHのときだけ出力が有効になり、LOWにすると出力の電流がカットされます。AIN1に1個パルス(LOW->HIGH->LOW)を入れると正転、BIN1だと逆転します(モーターの配線や仕様によって変わりますので注意)。

今回、両手が塞がる用途でモーターを使うので、ミシン用のフットペダルを用意しました。3.5mmφのモノラル用ミニプラグ出力で踏まないと0Ω、踏むと約10kΩになります。GND - ペダルの片方 - XIAOの7ピン - 10kΩの抵抗 - 3.3V出力、という風につなぎました。こうするとXIAOへの電圧は0-約1.65Vの間で変化します。これをアナログポートで読み取ります。

ところで、リファレンスやググると出てくるサンプルコードを見るとスピード指定関数setSpeedの引数が rpm になっているけど、試したところではpps(1秒あたりのパルス数)みたいです。本家ArduinoでStepperクラスを使ったことないけど(あるいは忘れている)、少なくともXIAOでは。

ということで、ソースコードはこんな感じ。


#include <Stepper.h>

Stepper myStepper(200, 3, 5);

bool running = false;

void setup() {
  Serial.begin(115200);
  pinMode(4, OUTPUT);
  pinMode(6, OUTPUT);
}

void loop() {
  int value = analogRead(7) / 2 - 5;
  if (value < 0) {
    if (running) {
      digitalWrite(4, LOW);
      digitalWrite(6, LOW);
      running = false;    
    }
    delay(50);
  } else {
    if (!running) {
      digitalWrite(4, HIGH);
      digitalWrite(6, HIGH);
      running = true;    
    }

    Serial.println(value);
    
    myStepper.setSpeed(value) ;
    myStepper.step(value / 10);
  }
}


2020年7月2日木曜日

ちっこいGaNを動かしてみた

1号機も実は動いていた!
秋月でも入手可能なGaN N-ch FET。素晴らしい特性なのですが、4列の端子が0.4mmピッチで並ぶという極小パッケージ。ステンシル使ってリフローしてもちょっとシルクがズレたら失敗しかねないサイズです。

でも、とりあえず特性を調べてみたいんじゃよ。ということで、何とか配線してみました。ちょっとしたはんだ付けの腕試し、のつもりだったのですが……でも一打逆転の、ドラマです(プロジェクトXを見たので少し後遺症が……)。

■1回目:失敗(?)■

まず最初、両面テープに貼り付けてその上で作業しようとしました。


そしたら、熱伝導率があまりにも良くてハンダゴテをあてた瞬間に粘着剤が溶けてしまって作業にならず。逆作用ピンセットはバネが強すぎるので放熱クリップで挟んで作業しました。


この直後にピーン、と飛んでいってしまって諦めたのですが、ベッドのうえに着陸しているのを発見! 再作業して何とか3本配線できました。さっき3本目をつけようとして飛ばしてしまったので、失敗を繰り返さないよう予め2本をピンヘッダのうえにはんだ付けし、残り1本は先にピンヘッダの上にはんだ付けしておいて、そこからチップの上に曲げていき、ピンセットでおさえながらはんだ付けする、という方法を取りました。

ひん曲がりまくってますけども、チップになるべく負荷をかけまいと回り道していたらこんな形に……。強く引っ張ると電極が剥がれちゃうんですよね。


しかし。


デバイステスターで調べるとVgs65Vというとんでもない値が出てしまいます。失敗と判断しました(伏線)。

■2回目:失敗■

Twitterで「適当な0.4mmピッチの変換基板を使ったらいいのでは」とアドバイスをいただき、aitendoと秋月にQFPなどの変換基板を注文。先にaitendoから届いたので、さっそく作業します。


変換基板のパターンをカットするためには写真の超硬スクレーパーを使用しました。先端が三角錐になっていて、頂点で切り込みを入れて辺で削り取る、という使い方ができます。これを使うようになってからパターンカットで苦労することはなくなりました。おすすめです!


最初に左のカットをしたのですが、接着剤が柔らかくて加熱する前から曲がってしまったので捨てます。まぁ0.2x0.2mmぐらいしか面積がないので厳しい使い方だとは思いますが。


ペーストをのっけて、なるべくピン間に残らないように工業用綿棒のとんがったやつで掃除をします。これもとんがったところが意外と鋭くて細かい拭き取りができますし、円錐の直線部分は基板に密着して拭き取りが捗ります。通常の丸い綿棒だと点接触ですが、これは線接触なので吸い残しが出にくいのです。

何よりさすがは工業用綿棒、糸くずがほとんど出ません!綿棒なのに!!


この状態でリフロー路に入れて220度プロファイルで調理しました。うえは掃除後のやつですが、いい感じに止まっているじゃあないですか!(伏線としてのはんだボール残)


残りのソース端子も配線します。考えてみりゃ3番ピンがSなので別に配線しなくても良かったんですよね(伏線)。


結果です。見事に動作しません。この後、簡単なスイッチ回路を組み立てて試してみましたが、GS間が短絡しているようでダメでした(伏線回収)。

■3回目:成功!!■

3度目の正直は秋月のQFN基板、ハンダメッキ済です。GaNチップにはんだボールが乗っているので、ハンダクリームの載せない作戦です。


手を加える前の基板。結構ハンダ厚い。


削りました。今度はソースとゲートが短絡しないようにソース部分をまるごと削ってしまう作戦です。


サンハヤトの普通のフラックスを塗ります。黄色いのよね。


少し乾かしてからチップを載せました。松脂でベタベタの液に少し張り付いているだけなので、慎重にリフロー炉に入れます。が、うちのリフロー炉のドア、最後にガツン!ってイキオイがついてしまるんですよね……心配です(伏線)。


リフロー後です。ちょっとズレました。ソース電極がゲート電極側に寄ってしまったので短絡していないか心配です(伏線)。やる時には、カプトンテープなどでずれないようにしといた方が良いと思います。誰もやらないと思うけど。

結果。デバイステスターだと、1回めと同じ変な値が出てきます。だからVgs=65Vってなんすかああ! ……あれ、1回めと同じ不具合なんじゃなくて、1回めもこれも成功なんじゃね? GaNの特性が異次元過ぎて、デバイステスターが正常に判断できてないんじゃね??

ということで、LED駆動回路を組み立ててみました。


動きました(以外な結末)。


1回めのやつも動きました(冒頭の写真)。ゲート電圧をかけると点灯、GNDに落とすと消えます。バンザーイ!

ということで、微細なはんだ付けは楽しいな、ということでお送り致しました。