昼間は昨日のお疲れで目覚めが1時間遅かった。
昼間はめちゃくちゃ蒸し暑いのでダラダラ
昨日購入したOfficeのインストールなどで時間が過ぎる。
夕方お散歩
フレスタのタージーパイ(大鶏排)がリースナブルでありがたい。
胸肉ではなくもも肉で298円
最筋肉怪我足りなく思ってたので速攻購入
夜型人間、夕方になると元気になってくる。
PlotClock工作に突入
ソースはこちらからゲット
RTCは先日実験したArduino標準ライブラリを組み込んだ。
先ずはソースコードをていねいに読んでみた。
rift(0),rift(1),rift(2) がちょっとわかりにくかったが、(0)が秒げ机上面、(1)が文字描画間のスキップ高、(2)がペンホルダを越す高さ
消すのも書くのも同じ机上面、その時にペンを装着してるかしてないかの違い。
0..9の文字はベクトルデータで仮想座標がプログラム内に記述されている。
フォントサイズも指定できる。
RTCユニットはゴミ箱から拾い上げて接続(電源と、Analog4,5ポートへ接続)
壊れていても、時間だけは刻むから。
これがないと起動マイクロセコンド起算で時計を自分で作らないといけないし、面倒くさい。
なにやらエアーモードで文字を書いては消しているが、少し位置がおかしい。
ここらあたりからの微調整が難しいようである。
ソースを提供しているGitHubユーザさんから全てをDLしてるなら比較的簡単かも知れないが、残念ながら違います。
なので、今晩はここで止める。
RTC壊れてるし、最後は吉凶占いおみくじロボットにしちゃろうか・・・
翌日、いよいよペンを載せようとあれこれやったがだめ。
そもそもペンの太さが全然合わない。
RTCが2065年なんて数字を表示する。2001年1/1になったり。どこか接触不良のようだ。
左右位置の調整が数値を変えても思ったように動かない。
最後はリフト担当のサーボが動かなくなった。
もう嫌になった。捨てたる!
------自作RTC版のPlotTime---------
// Plotclock
// https://github.com/9a/plotclock
// https://github.com/9a/plotclock/blob/master/plotclock.ino
// cc - by Johannes Heberlein 2014
// v 1.02
// thingiverse.com/joo wiki.fablab-nuernberg.de
// units: mm; microseconds; radians
// origin: bottom left of drawing surface
// time library see http://playground.arduino.cc/Code/time
// RTC library see http://playground.arduino.cc/Code/time
// or http://www.pjrc.com/teensy/td_libs_DS1307RTC.html
// Change log:
// 1.01 Release by joo at https://github.com/9a/plotclock
// 1.02 Additional features implemented by Dave:
// - added ability to calibrate servofaktor seperately for left and right servos
// - added code to support DS1307, DS1337 and DS3231 real time clock chips
// - see http://www.pjrc.com/teensy/td_libs_DS1307RTC.html for how to hook up the real time clock
// delete or mark the next line as comment if you don't need these
//#define CALIBRATION // キャリブレーション(調整)モード 適否
#define REALTIMECLOCK // リアルタイムクロック 適否
// パラメータ設定 調整時にこの値を正しく90度になるように調整すること
#define SERVOFAKTORLEFT 500 // 90どの値を入れろ? org 650
#define SERVOFAKTORRIGHT 500 // 他のサーボテストで得た値をとりあえず入れてみた org 650
// Zero-position of left and right servo
// When in calibration mode, adjust the NULL-values so that the servo arms are at all times parallel
// either to the X or Y axis
#define SERVOLEFTNULL 2000 // 左サーボ oeg: 2250
#define SERVORIGHTNULL 840 // 右サーボ oeg: 920
#define SERVOPINLIFT 2 // サーボ リフト(持ち上げ)ピン番号
#define SERVOPINLEFT 3 // サーボ 左 のピン番号
#define SERVOPINRIGHT 4 // サーボ 右 のピン番号
// リフトのパラメータ
// 水平が1400 数値が大きいほど下に下る
#define LIFT0 1400 // 1080 机の面高 on drawing surface
#define LIFT1 900 // 1350 文字描画のスキップ高 between numbers
#define LIFT2 600 // 1200 消去パッドへ入れる高さ going towards sweeper
// リフトの速度(高値ほど遅い)
#define LIFTSPEED 1500
// アームの長さ(mm)のはずだが??
#define L1 35
#define L2 55.1
#define L3 13.2
// 左右サーボの原点
#define O1X 22
#define O1Y -25
#define O2X 47
#define O2Y -25
#include "Time.h" // see http://playground.arduino.cc/Code/time
#include "Servo.h"
#ifdef REALTIMECLOCK
// RTC制御
// RTCを使う前に現在時刻を記録させること
// 以下2行はRTCを使う設定時に有効となる
#include "Wire.h"
//#include "DS1307RTC.h" // RTC制御
#include "RTClib.h"
RTC_DS1307 RTC; // オリジナルソースと違います
#endif
int servoLift = 1500; // リフト値
Servo servo1; // 1..3 サーボのオブジェクト生成
Servo servo2; //
Servo servo3; //
volatile double lastX = 75; // 最終位置 X
volatile double lastY = 47.5; // Y
int last_min = 0; // 最終動作 分
void setup()
{
Serial.begin(9600);
Wire.begin();
RTC.begin();
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running!");
// following line sets the RTC to the date & time this sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
}
drawTo(75.2, 47); // 初期位置へ移動
lift(0); // ペン着地
servo1.attach(SERVOPINLIFT); // リフトサーボ ピンアサイン有効化
servo2.attach(SERVOPINLEFT); // 左 servo
servo3.attach(SERVOPINRIGHT); // 右 servo
delay(1000);
lift(1);
delay(1000);
lift(2);
delay(1000);
lift(0);
delay(1000);
}
// 以下の主要な関数
// lift(0) ペンを下ろす
// lift(1) ペンを少し上げる(描画モードでの移動高さ)
// lift(2) ペンをホルダに入れる高さまで上げる?
// moveTo() そのまま指定先まで移動する:Lift(0)なら描画・消去
// number() 数字などを描く動作
// 0..9 11: 消去? 111:コロンは?
// 下請け関数
// set_XY() 指定した角度までサーボホーンを動かすパルスを出力する
// bogenXXX() なめらかな線を描く?
void time2serial(DateTime tnow ){ // シリアルへ時間を書き出す
Serial.print(tnow.year(), DEC);
Serial.print(tnow.year(), DEC);
Serial.print('/');
Serial.print(tnow.month(), DEC);
Serial.print('/');
Serial.print(tnow.day(), DEC);
Serial.print(' ');
Serial.print(tnow.hour(), DEC);
Serial.print(':');
Serial.print(tnow.minute(), DEC);
Serial.print(':');
Serial.println(tnow.second(), DEC);
}
//ーーー時刻を描く通常動作ーーーー
void loop() {
int i = 0;
DateTime now = RTC.now();
time2serial(now); //現在時刻をシリアルへ書き出し
if (last_min != now.minute()) {
Serial.println("Plot start !!! ");
if (!servo1.attached()) servo1.attach(SERVOPINLIFT);
if (!servo2.attached()) servo2.attach(SERVOPINLEFT);
if (!servo3.attached()) servo3.attach(SERVOPINRIGHT);
lift(0);
while ((i+1)*10 <= now.hour())
{
i++;
}
Serial.println("3-5-19-28");
number(3, 3, 111, 1); // 消去動作
number(5, 25, i, 0.9);
number(19, 25, (now.hour()-i*10), 0.9);
number(28, 25, 11, 0.9); // コロン
i=0;
while ((i+1)*10 <= now.minute())
{
i++;
}
Serial.println("34-48");
number(34, 25, i, 0.9);
number(48, 25, (now.minute()-i*10), 0.9);
lift(2);
Serial.println("end 74");
drawTo(74.2, 47.5);
lift(1);
last_min = now.minute();
servo1.detach(); // モーター停止
servo2.detach();
servo3.detach();
}
delay(10000);
}
//-----------------------------------------------------------------------
// 数字コロンを書く・消去動作
// ペンを数字の最初の左下始点(bx,by)に移動し
// ペンを持ち上げ、数字[ num : 0..9 ]描き、再度持ち上げて終了
// フォントサイズは縦20mmで[ scale ]で指定?
//-----------------------------------------------------------------------
void number(float bx, float by, int num, float scale) {
switch (num) {
case 0:
drawTo(bx + 12 * scale, by + 6 * scale);
lift(0);
bogenGZS(bx + 7 * scale, by + 10 * scale, 10 * scale, -0.8, 6.7, 0.5);
lift(1);
break;
case 1:
drawTo(bx + 3 * scale, by + 15 * scale);
lift(0);
drawTo(bx + 10 * scale, by + 20 * scale);
drawTo(bx + 10 * scale, by + 0 * scale);
lift(1);
break;
case 2:
drawTo(bx + 2 * scale, by + 12 * scale);
lift(0);
bogenUZS(bx + 8 * scale, by + 14 * scale, 6 * scale, 3, -0.8, 1);
drawTo(bx + 1 * scale, by + 0 * scale);
drawTo(bx + 12 * scale, by + 0 * scale);
lift(1);
break;
case 3:
drawTo(bx + 2 * scale, by + 17 * scale);
lift(0);
bogenUZS(bx + 5 * scale, by + 15 * scale, 5 * scale, 3, -2, 1);
bogenUZS(bx + 5 * scale, by + 5 * scale, 5 * scale, 1.57, -3, 1);
lift(1);
break;
case 4:
drawTo(bx + 10 * scale, by + 0 * scale);
lift(0);
drawTo(bx + 10 * scale, by + 20 * scale);
drawTo(bx + 2 * scale, by + 6 * scale);
drawTo(bx + 12 * scale, by + 6 * scale);
lift(1);
break;
case 5:
drawTo(bx + 2 * scale, by + 5 * scale);
lift(0);
bogenGZS(bx + 5 * scale, by + 6 * scale, 6 * scale, -2.5, 2, 1);
drawTo(bx + 5 * scale, by + 20 * scale);
drawTo(bx + 12 * scale, by + 20 * scale);
lift(1);
break;
case 6:
drawTo(bx + 2 * scale, by + 10 * scale);
lift(0);
bogenUZS(bx + 7 * scale, by + 6 * scale, 6 * scale, 2, -4.4, 1);
drawTo(bx + 11 * scale, by + 20 * scale);
lift(1);
break;
case 7:
drawTo(bx + 2 * scale, by + 20 * scale);
lift(0);
drawTo(bx + 12 * scale, by + 20 * scale);
drawTo(bx + 2 * scale, by + 0);
lift(1);
break;
case 8:
drawTo(bx + 5 * scale, by + 10 * scale);
lift(0);
bogenUZS(bx + 5 * scale, by + 15 * scale, 5 * scale, 4.7, -1.6, 1);
bogenGZS(bx + 5 * scale, by + 5 * scale, 5 * scale, -4.7, 2, 1);
lift(1);
break;
case 9:
drawTo(bx + 9 * scale, by + 11 * scale);
lift(0);
bogenUZS(bx + 7 * scale, by + 15 * scale, 5 * scale, 4, -0.5, 1);
drawTo(bx + 5 * scale, by + 0);
lift(1);
break;
case 111:
lift(0);
drawTo(70, 46);
drawTo(65, 43);
drawTo(65, 49);
drawTo(5, 49);
drawTo(5, 45);
drawTo(65, 45);
drawTo(65, 40);
drawTo(5, 40);
drawTo(5, 35);
drawTo(65, 35);
drawTo(65, 30);
drawTo(5, 30);
drawTo(5, 25);
drawTo(65, 25);
drawTo(65, 20);
drawTo(5, 20);
drawTo(60, 44);
drawTo(75.2, 47);
lift(2);
break;
case 11:
drawTo(bx + 5 * scale, by + 15 * scale);
lift(0);
bogenGZS(bx + 5 * scale, by + 15 * scale, 0.1 * scale, 1, -1, 1);
lift(1);
drawTo(bx + 5 * scale, by + 5 * scale);
lift(0);
bogenGZS(bx + 5 * scale, by + 5 * scale, 0.1 * scale, 1, -1, 1);
lift(1);
break;
}
}
//---------------------------------------------------
// Lift処理 サーボパルスを規定値の時間分だけ送り出す
// 0:850 1:150 2:元に戻す? 現在のLift値は変数:servoLiftに保持されている
// servoLift値は信号HIの長さらしく、腕の高さのようだ
//---------------------------------------------------
void lift(char lift) {
switch (lift) {
// room to optimize !
case 0: //850
if (servoLift >= LIFT0) {
while (servoLift >= LIFT0)
{
servoLift--;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT0) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;
case 1: //150
if (servoLift >= LIFT1) {
while (servoLift >= LIFT1) {
servoLift--;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT1) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;
case 2:
if (servoLift >= LIFT2) {
while (servoLift >= LIFT2) {
servoLift--;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT2) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;
}
}
//-------------------------------------------------------------------------
// bogen UZS 関数
// bogenの意味はスキー用語で「(板をV型にして速度を落としつつ)曲がる」ですが・・・
// 少しずつ角度を変えながら描画するのかな?
// UZSとGZS はinkr値が±が逆で、終了条件がちょっと違う程度
//-------------------------------------------------------------------------
void bogenUZS(float bx, float by, float radius, int start, int ende, float sqee) {
float inkr = -0.05;
float count = 0;
do {
drawTo(sqee * radius * cos(start + count) + bx,
radius * sin(start + count) + by);
count += inkr;
}
while ((start + count) > ende);
}
void bogenGZS(float bx, float by, float radius, int start, int ende, float sqee) {
float inkr = 0.05;
float count = 0;
do {
drawTo(sqee * radius * cos(start + count) + bx,
radius * sin(start + count) + by);
count += inkr;
}
while ((start + count) <= ende);
}
//-------------------------------------------------------------------------
// drowTo 関数
// そのまま移動する(ペンがおりてりゃ線を引く、ブラシ持ってれば消すんじゃね?)
// 最終ペン位置は lastX, lastY に保持しておく
//-------------------------------------------------------------------------
void drawTo(double pX, double pY) {
double dx, dy, c;
int i;
// dx dy of new point
dx = pX - lastX;
dy = pY - lastY;
//path lenght in mm, times 4 equals 4 steps per mm
c = floor(4 * sqrt(dx * dx + dy * dy));
if (c < 1) c = 1;
for (i = 0; i <= c; i++) {
// draw line point by point
set_XY(lastX + (i * dx / c), lastY + (i * dy / c));
}
lastX = pX;
lastY = pY;
}
//-------------------------------------------------------------------------
// return_angle 関数
// アークコサイン値を返す
//-------------------------------------------------------------------------
double return_angle(double a, double b, double c) {
// cosine rule for angle between c and a
return acos((a * a + c * c - b * b) / (2 * a * c));
}
//-------------------------------------------------------------------------
// set_XY 関数 三角関数計算の後、
// 指定した角度までサーボホーンを動かすパルスを出力する
//-------------------------------------------------------------------------
void set_XY(double Tx, double Ty)
{
delay(1);
double dx, dy, c, a1, a2, Hx, Hy;
// calculate triangle between pen, servoLeft and arm joint
// cartesian dx/dy
dx = Tx - O1X;
dy = Ty - O1Y;
// polar lemgth (c) and angle (a1)
c = sqrt(dx * dx + dy * dy); //
a1 = atan2(dy, dx); //
a2 = return_angle(L1, L2, c);
servo2.writeMicroseconds(floor(((a2 + a1 - M_PI) * SERVOFAKTORLEFT) + SERVOLEFTNULL));
// calculate joinr arm point for triangle of the right servo arm
a2 = return_angle(L2, L1, c);
Hx = Tx + L3 * cos((a1 - a2 + 0.621) + M_PI); //36,5°
Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);
// calculate triangle between pen joint, servoRight and arm joint
dx = Hx - O2X;
dy = Hy - O2Y;
c = sqrt(dx * dx + dy * dy);
a1 = atan2(dy, dx);
a2 = return_angle(L1, (L2 - L3), c);
servo3.writeMicroseconds(floor(((a1 - a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));
}