Guest User

Untitled

a guest
Jul 19th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.16 KB | None | 0 0
  1. //開機時夾子夾兩次,進入操控模式
  2. //開機時按住搖桿A按鈕,夾子夾四次,進入錄製模式。
  3. //每做一次動作,按A按鈕錄製,重複到完成動作,按B按鈕開始重複執行
  4. //
  5. #include <Servo.h>
  6. // 初始化參數
  7.  
  8. // 總共有幾顆伺服馬達
  9. const int SERVOS = 4;
  10. // 搖桿至少扳動多少才開始動作
  11. const int sensityOffset = 50;
  12. // 設定讀取間隔時間(毫秒)
  13. const int delayTime = 20;
  14. // 搖桿未使用狀態計數器達多少次後, 將馬達斷線
  15. const int idleTime = 100;
  16. // 顯示狀態的Led pin腳
  17. const int ledPin = 3;
  18. // 設定按鈕 pin腳
  19. const int buttonL = 2, buttonR = 4;
  20.  
  21. // 最大記憶動作數
  22. const int maxMemory = 100;
  23. // 記憶播放速度 1x 2x 3x
  24. int playSpeed = 1;
  25. int maxSpeed = 10;
  26.  
  27. int servoConfig[SERVOS][5] = {
  28. //JoystickPin, servoPin, minAngle, maxAngle, initialAngle(搖桿類比腳位,伺服機腳位,最大角度,最小角度,預設角度)
  29. {0, 11, 0, 180, 90}, //A0 L.X Base
  30. {1, 9, 60, 160, 90}, //A1 L.Y Right
  31. {2, 10, 40, 120, 40}, //A2 R.Y Left
  32. {3, 5, 0, 90, 60} //A3 R.X Claw
  33. };
  34.  
  35. Servo myservo[SERVOS];
  36. int armMode = 0; // 預設0為控制模式, 1為錄製模式, 2為播放模式
  37. int actionCounter = 0; // 記憶目前動作數目
  38. int idle[SERVOS]; // 閒置計數器
  39. int actionMemory[maxMemory][SERVOS]; //記憶角度
  40. int buttonPreState = 0;
  41.  
  42. void setup() {
  43. Serial.begin(9600);
  44. // 初始化針腳模式 (Button按下為0, 不按為1)
  45. pinMode(buttonL, INPUT_PULLUP);
  46. pinMode(buttonR, INPUT_PULLUP);
  47. // 馬達初始化
  48. for(int i = 0; i < SERVOS; i++) {
  49. myservo[i].attach(servoConfig[i][1]);
  50. myservo[i].write(servoConfig[i][4]);
  51. // 初始化閒置時間
  52. idle[i] = 0;
  53. }
  54.  
  55. if(!digitalRead(buttonL)) {
  56. Serial.println("Change to Record Mode");
  57. armMode = 1;
  58. cutcut();
  59. cutcut();
  60. } else {
  61. cutcut();
  62. // 指示燈恆亮
  63. digitalWrite(ledPin, HIGH);
  64. }
  65.  
  66. // 顯示完成初始化
  67. Serial.println("Initialized");
  68. }
  69.  
  70. void loop() {
  71. if(armMode != 2) {
  72. // 播放模式無法控制外, 其餘模式都可以操作
  73. move_controller();
  74. }
  75.  
  76. if(armMode != 0) {
  77. armActionMemory();
  78. }
  79. }
  80.  
  81. // 控制夾子
  82. void claw(boolean mode) {
  83. // 未連接則先連接
  84. if(!myservo[3].attached()) {
  85. myservo[3].attach(servoConfig[3][1]);
  86. }
  87. // 夾子開關 (0:open, 1:close)
  88. if(!mode) {
  89. myservo[3].write(servoConfig[3][3]);
  90. } else {
  91. myservo[3].write(servoConfig[3][2]);
  92. }
  93. }
  94. // 夾夾指示 (連續開合兩次)
  95. void cutcut(){
  96. delay(500);
  97. for(int i = 0; i < 2; i++) {
  98. claw(true);
  99. delay(150);
  100. claw(false);
  101. delay(150);
  102. }
  103. }
  104.  
  105. // 手臂移動
  106. void move_controller() {
  107. boolean shouldMove = false;
  108. int value[SERVOS];
  109. int currentAngle[SERVOS];
  110.  
  111. for(int i = 0; i < SERVOS; i++) {
  112. // 讀取搖桿數值與當前角度
  113. value[i] = analogRead(servoConfig[i][0]);
  114. currentAngle[i] = myservo[i].read();
  115.  
  116. // 當搖桿向右或向下移動
  117. if(value[i] > (512 + sensityOffset) ) {
  118. if(i != SERVOS - 1 && currentAngle[i] > servoConfig[i][2]) {
  119. currentAngle[i] -= 1 + ((value[i] > (1023 - sensityOffset/2)) ? 1 : 0);
  120. shouldMove = true;
  121. idle[i] = 0;
  122. } else if(i == SERVOS - 1) {
  123. claw(0);
  124. idle[i] = 0;
  125. }
  126. // 當搖桿向左或向上移動
  127. } else if(value[i] < (512 - sensityOffset)) {
  128. if(i != SERVOS - 1 && currentAngle[i] < servoConfig[i][3]) {
  129. currentAngle[i] += 1 + ((value[i] < sensityOffset/2) ? 1 : 0);
  130. shouldMove = true;
  131. idle[i] = 0;
  132. } else if(i == SERVOS - 1) {
  133. claw(1);
  134. idle[i] = 0;
  135. }
  136. } else {
  137. // 閒置狀態
  138. idle[i]++;
  139. }
  140.  
  141. if(idle[i] >= idleTime) {
  142. myservo[i].detach();
  143. idle[i] = 0;
  144. }
  145. }
  146.  
  147. if(shouldMove) {
  148. for(int i = 0; i < SERVOS; i++) {
  149. if(!myservo[i].attached()) {
  150. myservo[i].attach(servoConfig[i][1]);
  151. }
  152. myservo[i].write(currentAngle[i]);
  153. }
  154. }
  155. delay(delayTime);
  156. }
  157.  
  158. // 錄製動作
  159. void armActionMemory() {
  160. if(armMode == 1) {
  161. if(!digitalRead(buttonR)) {
  162. armMode = 2;
  163. Serial.println("Change to play mode by button");
  164. return;
  165. }
  166. int buttonPressed = !digitalRead(buttonL);
  167. // 重複讀取按則 return
  168. if(buttonPreState && buttonPressed) {
  169. return;
  170. } else if(!buttonPreState && buttonPressed) {
  171. buttonPreState = true;
  172. if(actionCounter < maxMemory) {
  173. for(int i = 0; i < SERVOS; i++) {
  174. actionMemory[actionCounter][i] = myservo[i].read();
  175. }
  176. actionCounter++;
  177. Serial.println("Saved Action!");
  178. if(actionMemory == maxMemory) {
  179. armMode = 2;
  180. Serial.println("Change to play mode by full memory");
  181. }
  182. }
  183. } else {
  184. buttonPreState = buttonPressed;
  185. }
  186. // 記錄同時按下播放
  187. if(!digitalRead(buttonR)) {
  188. armMode = 2;
  189. Serial.println("Change to play mode by button");
  190. }
  191. } else {
  192. //播放模式
  193. autoPlay();
  194. }
  195. }
  196.  
  197. // 播放模式
  198. void autoPlay() {
  199. // 未連接馬達則連接, 並回到初始位置
  200. for(int i = 0; i < SERVOS; i++) {
  201. if(!myservo[i].attached()) {
  202. myservo[i].attach(servoConfig[i][1]);
  203. }
  204. myservo[i].write(servoConfig[i][4]);
  205. }
  206.  
  207. delay(1000);
  208. Serial.println("Start Playing...");
  209. while(1) {
  210. for(int i = 0; i < actionCounter - 1; i++) {
  211. if(!digitalRead(buttonL) || !digitalRead(buttonR)) {
  212. armMode = 0;
  213. return;
  214. }
  215. armfromto(actionMemory[i], actionMemory[i+1]);
  216. }
  217. delay(500/playSpeed);
  218. armfromto(actionMemory[actionCounter - 1], actionMemory[0]); //back to the first action
  219. delay(500/playSpeed);
  220. }
  221. }
  222.  
  223. // 讓移動比較順暢
  224. void armfromto(int *arrf, int *arrt){
  225. int maxAngles = 0;
  226. float lp[4];
  227.  
  228. // 調整速度
  229. adjustSpeed();
  230.  
  231. maxAngles = max(max(abs(arrt[0] - arrf[0]), abs(arrt[1] - arrf[1])), abs(arrt[2] - arrf[2]));
  232. maxAngles /= playSpeed;
  233. maxAngles = maxAngles < 1 ? 1 : maxAngles;
  234.  
  235. for (int i = 0; i < SERVOS-1; i++){
  236. lp[i] = float(arrt[i] - arrf[i])/float(maxAngles);
  237. }
  238.  
  239. for (int j = 1; j <= maxAngles; j++){
  240. for (int i = 0; i < SERVOS - 1; i++){
  241. myservo[i].write(arrf[i] + j * lp[i]);
  242. }
  243. delay(25);
  244. }
  245.  
  246. // 爪子角度
  247. myservo[SERVOS-1].write(arrt[SERVOS-1]);
  248. delay(50);
  249. }
  250.  
  251. void adjustSpeed(){
  252. for (int i = 0; i < SERVOS; i++){
  253. if (analogRead(i) > 512 + sensityOffset) playSpeed++;
  254. if (analogRead(i) < 512 - sensityOffset) playSpeed--;
  255. }
  256. playSpeed = playSpeed < 1 ? 1 : playSpeed;
  257. playSpeed = playSpeed > maxSpeed ? maxSpeed : playSpeed;
  258. }
Add Comment
Please, Sign In to add comment