零基础入门学用Arduino-MeArm机械臂篇 - YouTube
重點整理:
2022.02.20
- 關於MeArm機械臂的學習做個總結:
- 買了兩座機械臂,第一座組裝時弄斷了一片部件,以快速膠黏上後可用,但組裝後前臂始終卡卡的,因此再買了一套,小心奕奕地組好後,前臂仍是卡卡的,導致操作不順。猜測應是所買的這套 MeArm 公差太大,也有可能是出在五金零件(螺絲)的公差。如果重來(雖然不可能),絕對去買太极创客在淘寶的套件:mearm机械臂 (含电源) / 太极创客 / 零基础入门学用Arduino教程-淘宝网
- 要遙控,HC-06藍芽模塊是非買不可。雙搖桿模塊則是必買的部件(賣家所附的範例程式太完整,沒什麼改動就能上傳直接使用,程式碼值得好好學習),能精簡排線,甚至還預留接腳可以再插上HC-06藍芽模塊。
- Arduino UNO R3 一定要買官方版,學習上才不會造成困擾。開發版雖然較便宜,這次就碰到問題學到了教訓。
- 零基础入门学用Arduino-MeArm机械臂篇 - YouTube 系列循序漸進的教學,是自我學習最佳的教學影片。
2022.02.19
- 紅外線遙控版的確可以作動,只是感應不夠靈敏,改以 IR感測器的範例卻又不會,最後才注意到 IR感測器的接收情形有異常:IR感測器的範例只有按遙控器的按鍵時IR感測器上的 Led 燈才會閃一下,表示接收到訊號,但改用零基础入门学用Arduino-MeArm机械臂篇-16 开发机械臂程序-3 - YouTube 附的範例程式修改紅外線遙控版,就看到IR感測器上的 Led 燈一直在閃,表示一直在接收訊號,問題是---沒有按遙控器啊!
- 沒有按遙控器卻一直有訊號進來,程式需要不斷解碼,導致按鍵的反應會不靈敏,顯然是程式有 Bug 或者是其他的問題。
- 經過了大半天時間最後發現是這段程式碼造成的原因:
base.attach(11); // base 伺服舵机连接引脚11 舵机代号'b' rArm.attach(10); // rArm 伺服舵机连接引脚10 舵机代号'r' fArm.attach(9); // fArm 伺服舵机连接引脚9 舵机代号'f' claw.attach(5); // claw 伺服舵机连接引脚6 舵机代号'c'
- 這意味著舵機與 IR 感測器是無法共存的(這大概就是教學影片為何使用的是 HC-06 藍芽模塊的原因吧)。由於學習到這裡,該了解的也差不多都會了,HC-06 藍芽模塊也不需要再購買,這個階段的學習到此結束,可以進入下一階段了。
2022.02.19
- 利用 零基础入门学用Arduino-MeArm机械臂篇-16 开发机械臂程序-3 - YouTube 附的範例程式配合 IR感測器的範例很容易就改成紅外線遙控版本:
- 這只是初步階段,目前還無法如前述能夠記錄動作並重播,需要從賣家附的程式拷貝如何記錄動及重播的部分程式碼,當然需要加以修改,確定都沒問題後,才能算是完成這個階段的學習。
2022.02.18
- 雙搖桿到貨後,把賣家附的程式略為修改就能很方便地使用:
- 主要的修改在四個舵機的最大與最小極限值,而這些都是在之前學習時已測出並記錄下來。
- 因為沒有使用 hc06 bluetooth 模塊,所以把程式碼裡相關的部分註解掉。
- 底下是程式碼:
#include <Servo.h> #include <SoftwareSerial.h> SoftwareSerial mySerial(12, 13); // hc06 bluetooth rx/tx const int SERVOS = 4, MAXSPEED = 10; // servo pin 11/10/9/6 base/left/right/gripper int PIN[SERVOS], value[SERVOS], currentAngle[SERVOS], MIN[SERVOS], MAX[SERVOS], INITANGLE[SERVOS]; Servo myservo[SERVOS]; int aOrg[] = {90, 90, 90}; // initial angle for base/left/right arm arm int demoActions[9][4] = { { 90, 55, 165, 30}, // demo mode by pressing right button when boot { 45, 145, 90, 0}, { 90, 55, 165, 0}, {135, 145, 90, 30}, { 90, 55, 165, 30}, {135, 145, 90, 0}, { 90, 55, 165, 0}, { 45, 145, 90, 30}, { 90, 55, 165, 30} }; int DELAYTIME = 200; int servo_moving[SERVOS] = {0,0,0,0}; boolean stringComplete = false; int bt_servo = 0; int bt_move = 0; int idle[] = {0,0,0,0}; boolean learningMode = false, autoPlayMode = false, autoDemoMode = false; boolean clawClosed = false, bootbuttonPressed = false; int const maxAutoActions = 100; int autoAction[maxAutoActions][SERVOS]; // can record up to 20 actions int actionIndex = 0; // total steps of an movement int buttonPreState = 0; int buttonL = 2, buttonR = 4; int threshL = 300, threshR = 700; int clawOpenangle = 10, clawCloseangle = 95; int demospeed = 1; //1 for 1x, 2 for 2x... void setup() { Serial.begin(9600); // RX/TX = D0/D1 pinMode(2, INPUT_PULLUP); //2 to memorize pinMode(4, INPUT_PULLUP); //4 to start actions pinMode(3, OUTPUT); digitalWrite(3, HIGH); Serial.print(digitalRead(buttonL)); Serial.print(" , "); Serial.println(digitalRead(buttonR)); // mySerial.begin(38400); // RX/TX = D12/D13 for bluetooth init_Pins(); cutcut(); // long press left button for recording mode if (digitalRead(buttonL)) { //這裡 ! 拿掉直接進入記錄模式,不然就無法進入。 learningMode = true; buttonPreState = 1; delay(500); //原為 1000 ,有點長,改成 500 剛剛好。 digitalWrite(3, LOW); Serial.println("learningMode!!"); } // long press right button for demo mode if (!digitalRead(buttonR)) { //記錄完畢後,按下這個鍵就可以重覆播放記錄的動作 autoDemoMode = true; buttonPreState = 1; auto_mode(); } } void loop() { // move_bt(); // move based on instruction from bluetooth move_joy(); // move based on instruction from joystick move_mem(); // move based on instruction from recording } void init_Pins(){ //這裡需要更改為之前測的各個舵機的最大、最小值 PIN[0] = 11; // pin to attach servo MIN[0] = 10; // minimal angle of this servo based on mechanic structure MAX[0] = 170; // maximum angle of this servo based on mechanic structure INITANGLE[0] = 90; // initial angle at start up PIN[1] = 10; MIN[1] = 45; MAX[1] = 180; INITANGLE[1] = 90; PIN[2] = 9; MIN[2] = 15; MAX[2] = 125; INITANGLE[2] = 90; PIN[3] = 6; MIN[3] = 0; MAX[3] = 195; INITANGLE[3] = 60; //set motors to initial angles initMotors(); // reset autoaction angles to record for (int i = 0 ; i < maxAutoActions; i++){ for (int j = 0 ; j < SERVOS; j++){ autoAction[i][j] = 0; } } // set autoAction[0][] = aOrg[]; for (int i = 0 ; i < SERVOS-1; i++){ autoAction[0][i] = aOrg[i]; } autoAction[0][SERVOS-1] = clawOpenangle; } /* 未來這裡修改為 IR 紅外遙控的方式 void move_bt(){ checkSoftSerial(); // read bluetooth and set servo_moving[i] for each servo, format +1/0/-1 for (int i = 0; i < SERVOS; i++){ currentAngle[i] = myservo[i].read(); // get existing serveo angle if (servo_moving[i] != 0){ currentAngle[i] += servo_moving[i]; // +/- angles based on the info from bluetooth currentAngle[i] = currentAngle[i] > MAX[i] ? --currentAngle[i] : currentAngle[i]; // ensure target angle within safe range currentAngle[i] = currentAngle[i] < MIN[i] ? ++currentAngle[i] : currentAngle[i]; myservo[i].write(currentAngle[i]); // rotate each servo delay(20); } } } // read from bluetooth and illustrate into angle change // the format is 2 digit like "31", the first digit is servo , the 2nd digit is 1 or 2 for +/- angle void checkSoftSerial() { String str = ""; if (mySerial.available()){ for (int i = 0 ; i < 2; i++){ str += (char)mySerial.read(); } // the servo to move int value = str.toInt(); bt_servo = value / 10; // the direction to move int angle = value % 10; if (angle == 2) bt_move = 1; else if (angle == 1) bt_move = -1; else bt_move = 0; servo_moving[bt_servo] = bt_move; // so we set +1/0/-1 into array to be used in move_bt() } } */ void move_joy(){ boolean joyChanged = false; for (int i = 0; i < SERVOS; i++){ value[i] = analogRead(i); // read the joystick value from analog port 0~3 delay(2); currentAngle[i] = myservo[i].read(); // get existing angles if (value[i] > threshR) { idle[i] = 0; // reset idle because someone touch the joystick joyChanged = true; if (currentAngle[i] > MIN[i]) --currentAngle[i]; // adjust the angle according to joystick direction if (i == SERVOS-1) currentAngle[i] = clawCloseangle; // for claw, only open/close mode } else if (value[i] < threshL) { idle[i] = 0; joyChanged = true; if (currentAngle[i] < MAX[i]) ++currentAngle[i]; if (i == SERVOS-1) currentAngle[i] = clawOpenangle; } else { ++idle[i]; } if (idle[i] >= 100){ //myservo[i].detach(); // optional: detach servo after idle for a while idle[i] = 0; } } if (joyChanged){ for (int i = 0 ; i < SERVOS; i++){ // before write angle , let's attach servo if not if (!myservo[i].attached()) myservo[i].attach(PIN[i]); myservo[i].write(currentAngle[i]); } } delay(20); } // memorize the actions void move_mem(){ if (!autoPlayMode){ if (learningMode){ //Serial.println("learningMode"); // if one of any button pressed, memorize the angles if (!digitalRead(buttonR)) { // done recoding, going to auto play autoPlayMode = true; return; } int buttonPressed = !digitalRead(buttonL); //Serial.print("buttonPressed = "); //if (buttonPressed) Serial.println("buttonPressed"); delay(1); if (buttonPreState && buttonPressed) return; // repeated count of the same press else if (!buttonPreState && buttonPressed){ // Left button pressed to record actionIndex++; buttonPreState = true; if (actionIndex < maxAutoActions){ Serial.print("actionIndex = "); Serial.println(actionIndex); for(int i = 0; i < SERVOS; i++){ int tmp = myservo[i].read(); Serial.print(tmp); Serial.print(" , "); autoAction[actionIndex][i] = tmp; } Serial.println(""); if (actionIndex == maxAutoActions) autoPlayMode = true; } } else buttonPreState = buttonPressed; if (!digitalRead(buttonR)) { // Right button pressed autoPlayMode = true; } } } else { // auto Playing Mode autoPlay(); } //delay(100); } // open and close the claw 2 times void cutcut(){ delay(1000); for (int i = 0; i < 2; i++){ closeclaw(true); delay(250); closeclaw(false); delay(250); } } // auto mode for demo purpose, can be paused any time if joystick is touched void auto_mode(){ int elements = sizeof(demoActions) / (4*sizeof(int)); Serial.print("elements = "); Serial.println(elements); cutcut(); while(1){ for (int i = 0; i < elements-1; i++){ if (buttonPressed()) { learningMode = false; autoPlayMode = false; autoDemoMode = false; return; } armfromto(demoActions[i], demoActions[i+1]); } } } //play recorded mode void autoPlay(){ digitalWrite(3, HIGH); // moving from current to the first position //Serial.print("autoPlay: last one to 0 : total "); //Serial.println(actionIndex); //armfromto(autoAction[actionIndex], autoAction[0]); initMotors(); delay(1000); cutcut(); while(1){ for (int i = 0; i < actionIndex; i++){ Serial.println("start playing..."); // pause if joystick touched, resume if touch again if (buttonPressed()) { learningMode = false; autoPlayMode = false; autoDemoMode = false; return; } Serial.print("autoplay : ============="); Serial.println(i); armfromto(autoAction[i], autoAction[i+1]); } delay(500/demospeed); armfromto(autoAction[actionIndex], autoAction[0]); //back to the first action delay(500/demospeed); } } // rotate all servos at a time smoothly by using "for" loop and delay(30) void armfromto(int *arrf, int *arrt){ int maxAngles = 0; float lp[4]; // adjust speed adjustSpeed(); maxAngles = max(max(abs(arrt[0] - arrf[0]), abs(arrt[1] - arrf[1])), abs(arrt[2] - arrf[2])); maxAngles /= demospeed; maxAngles = maxAngles < 1 ? 1 : maxAngles; Serial.print("speed = "); Serial.println(demospeed); for (int i = 0; i < SERVOS-1; i++){ // Serial.print(arrt[i] - arrf[i]); // Serial.print(" "); } //Serial.println(" === Delta"); for (int i = 0; i < SERVOS-1; i++){ lp[i] = float(arrt[i] - arrf[i])/float(maxAngles); //Serial.print(lp[i]); //Serial.print(" "); //Serial.println(); } for (int j = 1; j <= maxAngles; j++){ for (int i = 0; i < SERVOS-1; i++){ //Serial.print(arrf[i]+j*lp[i]); //Serial.print(" "); myservo[i].write(arrf[i]+j*lp[i]); } // Serial.print(" === "); // Serial.println(j); delay(20); } // the claw myservo[SERVOS-1].write(arrt[SERVOS-1]); delay(20); if (autoPlayMode || autoDemoMode){ //Serial.print("claw angle: "); //Serial.println(clawCloseangle); //myservo[SERVOS-1].write(arrt[SERVOS-1]); //delay(20); } } // close the claw void closeclaw(boolean op){ if (op){ myservo[SERVOS-1].write(clawCloseangle); } else { myservo[SERVOS-1].write(clawOpenangle); } } // check if joystick touched to stop the auto mode boolean joystickTouched(){ int tmp = 500; for (int i = 0; i < SERVOS; i++){ tmp = analogRead(i); delay(1); if (tmp > threshR || tmp < threshL) return true; } return false; } void initMotors(){ // attach servos to pins for (int i = 0; i < SERVOS; i++){ myservo[i].attach(PIN[i]); myservo[i].write(INITANGLE[i]); value[i] = 0; idle[i] = 0; } } void adjustSpeed(){ //if (learningMode) { for (int i = 0; i < SERVOS; i++){ if (analogRead(i) > threshR) demospeed++; if (analogRead(i) < threshL) demospeed--; } demospeed = demospeed < 1 ? 1 : demospeed; demospeed = demospeed > MAXSPEED ? MAXSPEED : demospeed; //} } boolean buttonPressed(){ //return true when any button pressed and not previously pressed if(!buttonPreState && (!digitalRead(buttonR) || !digitalRead(buttonL))) { buttonPreState = 1; return true; } else if (digitalRead(buttonR) && digitalRead(buttonL)){ buttonPreState = 0; } return false; }
- 關於操作:
- 接上電源後,機器手臂即處於「記錄」模式,例如影片中要將物體從左邊拿到右邊的動作,會需要記錄許多「關鍵」的 Action,每個Action 要記錄就要按一下左搖桿,便會把這個 Action 完後四個舵機的位置記錄在一個陣列中(本程式最多記錄 20 次的 Action )。
- 記錄完後,按一下右搖桿便開始重播剛剛記錄的動作。
- 要重新記錄新的動作,需要按 UNO 板子上的 Reset 。
- 現在要重覆的動作不用於程式中寫死,可以在每次使用時先記錄要重覆的動作,然後重播,就可以反覆的執行:
- 影片中行動電源上的遙控器底下壓著的是已連好的紅外線感測器,下一個目標是把這個裝置改成以紅外線遙控。
- 由於本次的改動完全沒有動到程式核心的部分,因此要改成紅外線遙控才是真正的挑戰開始。
- 看了 IR規格,目前先把紅外線感測器接在 Pin 5 上,用一條 M-M杜邦線接在搖桿板子上的 D5, 先以 IR 的範例測試,底下為遙控器按鍵對應的控制碼:
#include "IRremote.h" int receiver = 5; // Signal Pin of IR receiver to Arduino Digital Pin 11 /*-----( Declare objects )-----*/ IRrecv irrecv(receiver); // create instance of 'irrecv' decode_results results; // create instance of 'decode_results' /*-----( Function )-----*/ void translateIR() // takes action based on IR code received // describing Remote IR codes { switch(results.value) { case 0xFFA25D: Serial.println("1"); break; case 0xFFE21D: Serial.println("3"); break; case 0xFF629D: Serial.println("2"); break; case 0xFF22DD: Serial.println("4"); break; case 0xFF02FD: Serial.println("5"); break; case 0xFFC23D: Serial.println("6"); break; case 0xFFE01F: Serial.println("7"); break; case 0xFFA857: Serial.println("8"); break; case 0xFF906F: Serial.println("9"); break; case 0xFF9867: Serial.println("0"); break; case 0xFFB04F: Serial.println("#"); break; case 0xFF6897: Serial.println("*"); break; case 0xFF18E7: Serial.println("UP"); break; case 0xFF10EF: Serial.println("LEFT"); break; case 0xFF38C7: Serial.println("OK"); break; case 0xFF5AA5: Serial.println("RIGHT"); break; case 0xFF4AB5: Serial.println("DOWN"); break; case 0xFFFFFFFF: Serial.println(" REPEAT");break; default: Serial.println(" other button "); }// End Case delay(500); // Do not get immediate repeat } //END translateIR void setup() /*----( SETUP: RUNS ONCE )----*/ { Serial.begin(9600); Serial.println("IR Receiver Button Decode"); irrecv.enableIRIn(); // Start the receiver }/*--(end setup )---*/ void loop() /*----( LOOP: RUNS CONSTANTLY )----*/ { if (irrecv.decode(&results)) // have we received an IR signal? { translateIR(); irrecv.resume(); // receive the next value } }/* --(end main loop )-- */
- 未來再來修改程式碼讓各個按鍵對應四個舵機的動作,目前的規劃:
- Base 舵機往左⟺⬅︎
- Base 舵機往右⟺➡︎
- fArm 舵機往上⟺⬆︎
- fArm 舵機往下⟺⬇︎
- rArm 舵機往前⟺2
- rArm 舵機往後⟺8
- claw 舵機閉合⟺4
- claw 舵機張開⟺6
- 記錄模式⟺*
- 重播模式⟺#
2022.02.17
2022.02.15
- 等雙搖桿到貨,寫好程式,沒問題後就可以來嚐試遙控,不過不買教學影片裡的 HC-06 藍芽模塊,來試試買的套裝裡的紅外線遙控方式。
2022.02.14
- 雙搖桿仍未到貨,閒著也是閒著,在 Mac Boot Camp 裡的 Windows 10 安裝了 Arduino IDE 及 CH340 驅動,並上傳前述的程式到後來購買的 Arduino UNO R3 開發版,結果還是會當掉,有時還會來個大迴轉把線都捲在一起,而接另一片官方版的 R3 跑個幾十遍都沒問題,這才想起在 零基础入门学用Arduino-基础知识篇 - YouTube 一開始就提到初學者最好買官方版,免得問題多多,所以之前最先買的就是官方套裝版,使用上一直都沒有問題。也好在因為有了這片官方版可以做對比才找出問題的所在,假如只有這片開發版,大概會被它搞死,因為會以為是自己的程式有問題,說不定就半途而廢了。
- 把上述問題與賣家說明,並提出願加差價換成官方版,賣家也爽快答應,真不錯!隔天就來把開發版寄回。
- 未來購買,不是官方版不買。
2022.02.13
- 程式很快就改寫好了,真的就如工廠的機器人手臂一樣,可以放到生產線了:
- 程式的改寫其實只有一點點,幾乎全部都抄自範例,但至少說明範例程式讀通了,底下是程式碼:
/* 本程式主要是改寫 MeArm机械臂控制程序-5(by 太极创客 (2017-06-02) www.taichi-maker.com 而成 */ #include <Servo.h> Servo base, rArm, fArm, claw ; //建立4个舵机对象 int DSD = 30; //Default Servo Delay (默认电机运动延迟时间) //此变量用于控制电机运行速度.增大此变量数值将 //降低电机运行速度从而控制机械臂动作速度。 //存储电机极限值(const指定该数值为常量,常量数值在程序运行中不能改变) const int baseMin = 0; const int baseMax = 180; const int rArmMin = 25; const int rArmMax = 180; const int fArmMin = 35; const int fArmMax = 90; const int clawMin = 0; const int clawMax = 115; void setup() { base.attach(11); // base 伺服舵机连接引脚11 舵机代号'b' delay(200); // 稳定性等待 rArm.attach(10); // rArm 伺服舵机连接引脚10 舵机代号'r' delay(200); // 稳定性等待 fArm.attach(9); // fArm 伺服舵机连接引脚9 舵机代号'f' delay(200); // 稳定性等待 claw.attach(6); // claw 伺服舵机连接引脚6 舵机代号'c' delay(200); // 稳定性等待 base.write(90); delay(DSD); fArm.write(90); delay(DSD); rArm.write(90); delay(DSD); claw.write(90); delay(DSD); } void loop(){ Demo(); armIniPos(); } void servoCmd(char servoName, int toPos, int servoDelay){ //從範例直接搬過來的函數,完全未改 Servo servo2go; //创建servo对象 int fromPos; //建立变量,存储电机起始运动角度值 switch(servoName){ case 'b': if(toPos >= baseMin && toPos <= baseMax){ servo2go = base; fromPos = base.read(); // 获取当前电机角度值用于“电机运动起始角度值” break; } case 'c': if(toPos >= clawMin && toPos <= clawMax){ servo2go = claw; fromPos = claw.read(); // 获取当前电机角度值用于“电机运动起始角度值” break; } case 'f': if(toPos >= fArmMin && toPos <= fArmMax){ servo2go = fArm; fromPos = fArm.read(); // 获取当前电机角度值用于“电机运动起始角度值” break; } case 'r': if(toPos >= rArmMin && toPos <= rArmMax){ servo2go = rArm; fromPos = rArm.read(); // 获取当前电机角度值用于“电机运动起始角度值” break; } } //指挥电机运行 if (fromPos <= toPos){ //如果“起始角度值”小于“目标角度值” for (int i=fromPos; i<=toPos; i++){ servo2go.write(i); delay (servoDelay); } } else { //否则“起始角度值”大于“目标角度值” for (int i=fromPos; i>=toPos; i--){ servo2go.write(i); delay (servoDelay); } } } void Demo(){ //這部份只是簡單改寫 armIniPos() 函數而已 int robotDemoArray[11][3] = { //利用範例記錄下各個位置然後寫入陣列 {'c', 45, DSD}, {'b', 55, DSD}, {'r', 142, DSD}, {'f', 80, DSD}, {'c', 110, DSD}, {'r', 90, DSD}, {'b', 115, DSD}, {'r', 135, DSD}, {'c', 45, DSD}, {'f', 65, DSD}, {'r', 90, DSD} }; for (int i = 0; i < 11; i++){ servoCmd(robotDemoArray[i][0], robotDemoArray[i][1], robotDemoArray[i][2]); } } void armIniPos(){ Serial.println("+Command: Restore Initial Position."); int robotIniPosArray[4][3] = { {'b', 90, DSD}, {'r', 90, DSD}, {'f', 90, DSD}, {'c', 90, DSD} }; for (int i = 0; i < 4; i++){ servoCmd(robotIniPosArray[i][0], robotIniPosArray[i][1], robotIniPosArray[i][2]); } }
- 雙搖桿賣家連貨都還沒出,接下來不知道能再做些什麼?倒是在 YouTube 看到可以先用搖桿做出上述的動作,然後把動作「記憶」下來讓機器人不斷重覆,這樣就更彈性,不像上述影片把動作寫死,要更改得要連接電腦重新記錄動作的陣列並上傳。
2022.02.13
- 雙搖桿還沒到貨,暫時還無法進一步學習,不過稍為把MeArm_Servo_Chk.ino 改寫了一下,轉動速度變慢,變成自動展示:
- 看了一陣,想到或許與之前靠 Serial Monitor 下指令取物的動作結合,利用零基础入门学用Arduino-MeArm机械臂篇-16 开发机械臂程序-3 - YouTube 附的範例 meArm5.ino 把取物動作需要的每個座標記錄下來,儲存成二維陣列放在改寫的 MeArm_Servo_Chk.ino 讓它自動執行,這樣不就變成工廠裡的機器手臂一樣---嗯,可以來試試......
2022.02.12
- 74HC595 便宜又好用,當初買的套裝只有一顆,做了時鐘用掉了,於是在蝦皮找到有賣的,一顆才 4 元:【樂意創客官方店】74HC595直插 74HC595 8位元串列輸入/輸出/並行輸出暫存器DIP-16 LED驅動使用 | 蝦皮購物,買了三顆備用。
- 為了能免運,加上未來 meArm 完成後會用掉一片 Arduino UNO ,所以再加買了一片:【樂意創客官方店】《附發票》Arduino UNO R3 Atmega328p 開源版 CH340驅動 送傳輸線 | 蝦皮購物,到貨後,第一步就是先安裝 CH340 的驅動程式,結果在 Arduino IDE 下無法連接,起先還以為是這片有問題,沒弄清楚前還是先上 Google 了解一下,找到這篇:Troubleshooting CH340G issues on macOS - FAQ - PlatformIO Community,看完得到一個結論:在 Mac 下不要安裝 CH340 驅動,否則就無法連接(註:若已安裝就要按文章所述,在終端機下這道指令:sudo rm -rf /Library/Extensions/usbserial.kext/ 把已安裝的驅動刪除)。
- 即使這樣仍有一點小問題,這片與 Arduino IDE 雖可連接,但與 Serial Monitor 很容易就斷掉,需要關閉再重開,所以需要從 Serial Monitor 來輸入資料測試程式時會造成困擾(除了這個問題外,還未發現有其他問題),未來再購買 Arduino UNO 時,不要 CH340 的版本。
- 購買 Arduino UNO 時看到 【樂意創客官方店】《附發票》質感爆表 Arduino UNO R3 開發板專用壓克力外殼透明 保護盒壓克力 | 蝦皮購物,也不貴,尤其是看:零基础入门学用Arduino-MeArm机械臂篇 - YouTube 時,演示時用的 Arduino UNO 也都有加上,就一起下訂。安裝對老花眼來說實在有點吃力,不過安裝好了之後,質感升級👍🏼,擴充版也能插上,而且插拔更容易:
- 附的四根長螺絲太長了,裝好凸出底板許多,放在桌上會刮傷桌子,只得切掉並磨平,沒有附上防滑墊子,只好去大台中五金購買,找來找去只有一款 3M 的合用, 12 顆要 69元,比這個保護盒還貴。
- 然後就用這片板子試連 meArm ,並錄了段影片,由於操控稍為熟悉點了,錄了四分多鐘,下指令停頓的片段 Cut 掉,最後得到一分十七秒的影片,動作看起來似乎平順多了:
2022.02.12
- 燒掉的舵機好奇它的內部結構,在丟掉前拆解拍照看個清楚:
2022.02.11
- meArm 機械手臂的初步成果:它的動作是在電腦上下指令操控的,未來會改成使用搖桿來操控:
- 組裝過程中弄斷了一片零件,使用快速膠黏上,後續動作就卡卡的,拆裝了不下三次,最後才有影片這樣,卡卡的程度最小(影片中可看到略為抖動的現象)。
- 測試過程中出現燒焦味,最後還冒煙,然後燒掉了一個舵機及擴充電源模塊(查價後得知一個台幣 24 元),與蝦皮的賣家聊聊後才了解 Arduino 的 5V2A 供電就足夠了。算是學到一個經驗:
- 燒掉的是AMS1117-5V 電源IC:
- meArm 套件不是很貴,為了後續改用搖桿操控時能夠滑順,再向蝦皮賣家買了一套及 PS2雙搖捍。有了幾次的組裝經驗,meArm 不能像之前那樣迫不及待就組好,最後還得拆掉重來。幾次下來的心得:
- 先去這個頁面:零基础入门学用Arduino教程 – MeArm 篇 – 太极创客 ,下載這些檔案:
- 本套教程所有示例程序下载
- MeArm机械臂装配说明(太极创客编制版)
- MeArm安装调试程序
- 一定要照著這一系列影片:零基础入门学用Arduino-MeArm机械臂篇 - YouTube 按照順序一步步來,等學到零基础入门学用Arduino-MeArm机械臂篇-9 组装机械臂-1 - YouTube 時,先把下載的「MeArm机械臂装配说明」大致看一遍了解整個組裝流程。
- 在開始組裝前先利用下載的「MeArm安装调试程序」把四個舵機初始化(其實也可以不必先做,於組裝時要裝上搖臂時,再 Run 一下 MeArm_Servo_Adj.ino 即可,裝上搖臂後再 Run MeArm_Servo_Chk.ino 確認無誤後即可固定)
- 按照解說非常詳盡的這三支影片:零基础入门学用Arduino-MeArm机械臂篇-9 组装机械臂-1 - YouTube、零基础入门学用Arduino-MeArm机械臂篇-10 组装机械臂-2 - YouTube、零基础入门学用Arduino-MeArm机械臂篇-11 组装机械臂-3 - YouTube 就能輕易組裝完成。
- 四個舵機的供電使用 Arduino UNO 的 5V2A 供電即可,不必再使用擴充的電源模塊,品質堪慮。
- 組裝好後,按照零基础入门学用Arduino-MeArm机械臂篇-12 调试MeArm - YouTube 的解說把四個舵機的轉動範圍調出來,上述的影片就是做到這裡,調出來的範圍如下(與原始程式略有不同):
2022.02.10
- 進度來到這裡,把之前組好的MeArm機械臂:Luke 的休閒筆記: MeArm 機械手臂及一些配件到貨,接好線後,上傳 零基础入门学用Arduino-MeArm机械臂篇-6 控制伺服电机-2 - YouTube 的範例程式,MeArm機械臂就開始抖起來,然後一直抖個不停,就知道要拆掉重新來過一遍。
- 也不能隨便亂拆,把當初組裝時根據的教學影片:mearm 機器手臂組裝教學 - YouTube 倒著看來拆卸(由於之前組裝時一片零件斷裂,以快速膠黏上,也黏到其他部份,無法完整拆卸,只好部份拆掉,看能不能完成馬達的調整測試):
沒有留言:
張貼留言
您可以留下意見,但 Luke 可能無法馬上回覆,尚請見諒。