顯示具有 靈動狗 標籤的文章。 顯示所有文章
顯示具有 靈動狗 標籤的文章。 顯示所有文章

2026年2月8日 星期日

[靈動狗] 持續循環:坐下 3 秒 → 站立 3 秒

 






程式:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <Arduino.h>
#include <ESP32Servo.h>
#include <Preferences.h>

/* ====== 腳位(沿用你原本)====== */
#define LEFTHAND_CTRL_PIN  0
#define RIGHTHAND_CTRL_PIN 1
#define LEFTLEG_CTRL_PIN   10
#define RIGHTLEG_CTRL_PIN  7

Servo leftHandServo, rightHandServo, leftLegServo, rightLegServo;

/* ====== 舵機角度(沿用你原本的變數)====== */
int leftHandAngle  = 90;
int rightHandAngle = 90;
int leftLegAngle   = 90;
int rightLegAngle  = 90;

/* ====== 校正偏移(可選:沿用你原本的 Preferences)====== */
int leftHandOffset  = 0;
int rightHandOffset = 0;
int leftLegOffset   = 0;
int rightLegOffset  = 0;
Preferences preferences;

/* ====== 函式宣告 ====== */
void updateServo(uint8_t ucLeftHand, uint8_t ucRightHand, uint8_t ucLeftLeg, uint8_t ucRightLeg);
void standUp();
void sitDown();

void setup() {
  Serial.begin(115200);

  // 舵機 50Hz
  leftHandServo.setPeriodHertz(50);
  rightHandServo.setPeriodHertz(50);
  leftLegServo.setPeriodHertz(50);
  rightLegServo.setPeriodHertz(50);

  // attach(腳位, 最小脈寬, 最大脈寬)
  leftHandServo.attach(LEFTHAND_CTRL_PIN, 500, 2500);
  rightHandServo.attach(RIGHTHAND_CTRL_PIN, 500, 2500);
  leftLegServo.attach(LEFTLEG_CTRL_PIN, 500, 2500);
  rightLegServo.attach(RIGHTLEG_CTRL_PIN, 500, 2500);

  // 讀取偏移(沒有存過就會是0)
  preferences.begin("servo", true);
  leftHandOffset  = preferences.getInt("leftHandOffset", 0);
  rightHandOffset = preferences.getInt("rightHandOffset", 0);
  leftLegOffset   = preferences.getInt("leftLegOffset", 0);
  rightLegOffset  = preferences.getInt("rightLegOffset", 0);
  preferences.end();

  // 先站好
  standUp();
  delay(500);
}

void loop() {
  // 坐下 3 秒
  Serial.println("Sit down");
  sitDown();
  delay(3000);

  // 站立 3 秒
  Serial.println("Stand up");
  standUp();
  delay(3000);
}

/* ====== 舵機更新(沿用你原本邏輯:加偏移 + 右邊反轉)====== */
void updateServo(uint8_t ucLeftHand, uint8_t ucRightHand, uint8_t ucLeftLeg, uint8_t ucRightLeg) {
  int leftHand  = (int)ucLeftHand  + leftHandOffset;
  int rightHand = (int)ucRightHand + rightHandOffset;
  int leftLeg   = (int)ucLeftLeg   + leftLegOffset;
  int rightLeg  = (int)ucRightLeg  + rightLegOffset;

  leftHand  = constrain(leftHand,  0, 180);
  rightHand = constrain(rightHand, 0, 180);
  leftLeg   = constrain(leftLeg,   0, 180);
  rightLeg  = constrain(rightLeg,  0, 180);

  // 右側舵機角度反轉(沿用你原本)
  rightHand = 180 - rightHand;
  rightLeg  = 180 - rightLeg;

  leftHandServo.write(leftHand);
  rightHandServo.write(rightHand);
  leftLegServo.write(leftLeg);
  rightLegServo.write(rightLeg);
}

/* ====== 站立(沿用你原本的坐標與步進)====== */
void standUp() {
  // 腿先回到 90
  while ((abs(leftLegAngle - 90) > 5) || (abs(rightLegAngle - 90) > 5)) {
    if (leftLegAngle > 90) leftLegAngle -= 3;
    else if (leftLegAngle < 90) leftLegAngle += 3;

    if (rightLegAngle > 90) rightLegAngle -= 3;
    else if (rightLegAngle < 90) rightLegAngle += 3;

    delay(20);
    updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);
  }
  leftLegAngle = 90;
  rightLegAngle = 90;
  updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);

  // 手回到 90
  while ((abs(leftHandAngle - 90) > 5) || (abs(rightHandAngle - 90) > 5)) {
    if (leftHandAngle > 90) leftHandAngle -= 5;
    else if (leftHandAngle < 90) leftHandAngle += 5;

    if (rightHandAngle > 90) rightHandAngle -= 5;
    else if (rightHandAngle < 90) rightHandAngle += 5;

    delay(20);
    updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);
  }
  leftHandAngle = 90;
  rightHandAngle = 90;
  updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);
}

/* ====== 坐下(沿用你原本的坐標與步進)====== */
void sitDown() {
  // 腿到 40
  while ((abs(leftLegAngle - 40) > 5) || (abs(rightLegAngle - 40) > 5)) {
    if (leftLegAngle > 40) leftLegAngle -= 3;
    else if (leftLegAngle < 40) leftLegAngle += 3;

    if (rightLegAngle > 40) rightLegAngle -= 3;
    else if (rightLegAngle < 40) rightLegAngle += 3;

    delay(20);
    updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);
  }
  leftLegAngle = 40;
  rightLegAngle = 40;
  updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);

  // 手到 100
  while ((abs(leftHandAngle - 100) > 5) || (abs(rightHandAngle - 100) > 5)) {
    if (leftHandAngle > 100) leftHandAngle -= 5;
    else if (leftHandAngle < 100) leftHandAngle += 5;

    if (rightHandAngle > 100) rightHandAngle -= 5;
    else if (rightHandAngle < 100) rightHandAngle += 5;

    delay(20);
    updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);
  }
  leftHandAngle = 100;
  rightHandAngle = 100;
  updateServo(leftHandAngle, rightHandAngle, leftLegAngle, rightLegAngle);
}


[靈動狗] 改變眼睛的顏色

 



Arduino程式:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>

// 依照你原本的腳位
#define EYES_CTRL_PIN 6
#define TOUCH_SW_PIN  4
#define EYES_NUM      2

Adafruit_NeoPixel strip(EYES_NUM, EYES_CTRL_PIN, NEO_GRB + NEO_KHZ800);

// 顏色清單(紅、綠、藍、黃、紫、白)
uint8_t colors[][3] = {
  {255, 0,   0  },  // 紅
  {0,   255, 0  },  // 綠
  {0,   0,   255},  // 藍
  {255, 255, 0  },  // 黃
  {255, 0,   255},  // 紫
  {255, 255, 255}   // 白
};

int colorIndex = 0;

void setEyes(uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) {
  for (int i = 0; i < EYES_NUM; i++) {
    strip.setPixelColor(i, strip.Color(r, g, b));
  }
  strip.setBrightness(brightness); // 0~255
  strip.show();
}

void setup() {
  Serial.begin(115200);

  // 眼睛燈初始化
  strip.begin();
  strip.show(); // 先清空

  // 觸碰按鍵(你原本用的是 INPUT_PULLDOWN)
  pinMode(TOUCH_SW_PIN, INPUT_PULLDOWN);

  // 先亮白色當作「開機成功」
  setEyes(255, 255, 255, 80);
}

void loop() {
  // 讀按鍵:按下是 HIGH
  if (digitalRead(TOUCH_SW_PIN) == HIGH) {
    delay(30); // 防彈跳(避免按一下變很多次)

    // 等到放開(只算一次)
    while (digitalRead(TOUCH_SW_PIN) == HIGH) {
      delay(10);
    }

    // 換到下一個顏色
    colorIndex++;
    if (colorIndex >= (int)(sizeof(colors) / sizeof(colors[0]))) {
      colorIndex = 0;
    }

    // 顯示顏色(亮度用 80,不會刺眼)
    setEyes(colors[colorIndex][0], colors[colorIndex][1], colors[colorIndex][2], 80);

    // 印出目前顏色編號(給老師看)
    Serial.print("Color index = ");
    Serial.println(colorIndex);
  }

  delay(10);
}

執行結果:
Color index = 1
Color index = 2