มีวิธีหยุดยั้งเซอร์โวไม่ให้“ สั่น” หรือไม่?


20

อย่างง่าย ๆ ฉันควบคุม servos (9g Micro Servos) ตามข้อมูลที่อ่านจากที่อื่น ทุกอย่างทำงานได้ดียกเว้นเซอร์โวจะ "สั่น" อย่างต่อเนื่อง นั่นคือพวกมันสั่นสะเทือนด้วยการเคลื่อนไหวที่ละเอียดอ่อนมาก (ด้วยการเคลื่อนไหวที่ไม่สม่ำเสมอของ 1/2 -> 1 ซม. หรือมากกว่านั้น)

ฉันพยายามแก้ไขปัญหานี้ในซอฟต์แวร์โดยทำสิ่งที่ชอบ:

  do{
    delay(DTIME);
    positionServo();
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("X position: ");
    lcd.print(xRead);
    lcd.setCursor(0,1);
    lcd.print("Y position: ");
    lcd.print(yRead);
  }while( readChange() ); //while there has been change

ที่จำเป็นต้องทำในขณะเริ่มต้นตัวแปรที่เก็บค่า servo ที่แมป (โดยใช้ไลบรารี arduino servo)

ฟังก์ชัน readChange () ถูกกำหนดเป็น:

int readChange(){
  int x_Temp, y_Temp;

  x_Temp = map(analogRead(x_axisReadPin), 0, 1023, 0, 179);
  y_Temp = map(analogRead(y_axisReadPin), 0, 1023, 0, 179);

  if( abs(x_Temp - xRead) < DEG && abs(y_Temp - yRead) < DEG ) return 0; // no change 
  else return 1; //change
}

โดยที่ xRead คือค่าที่เริ่มต้น (เอาต์พุตแรกที่แม็พเซอร์โว)

แม้ว่านี่จะไม่ใช่วิธีการที่ดีจริงๆ มันต้องการให้ค่า BOTH ต้องไม่เปลี่ยนแปลงโดย DEG (~ 10 องศาหรือ ~ 0.28V ในกรณีของฉัน) ถ้าฉันเขียนฟังก์ชันเช่นนั้นหรือน้อยกว่า DEG ถ้าฉันเปลี่ยนเซอร์โวครั้งละหนึ่งครั้งล่ะ ดังนั้นจึงมีข้อผิดพลาดคือ ..

นี่เป็นเพียงคุณสมบัติของเซอร์โว (อาจจะถูกหรือไม่) หรือมีวิธีแก้ปัญหาหรือไม่?


มันจะง่ายกว่ามากถ้าจะรวมลิงค์ของ Pastie นี่คือรหัสเต็ม: http://pastie.org/8191459

ฉันได้แนบเซอร์โวสองตัวพร้อมกับตัวชี้เลเซอร์เพื่อให้มีอิสระสององศา (X, Y) มีตัวเลือกตามสถานะของปุ่มหลายปุ่มเพื่อควบคุมเซอร์โวในรูปแบบต่างๆ อย่างแรกคือ "โมชั่น" ที่ฉันมีสองโฟโต้ต้านทานที่ขึ้นอยู่กับปริมาณของแสงที่กระทบกับตำแหน่งของเซอร์โว ฉันยังไม่ได้ติดตั้งรหัสเพื่อควบคุมเซอร์โวโดยคอนโทรลเลอร์ Xbox และตัวเลือกที่สามเป็นการเคลื่อนไหวแบบสุ่ม

ป้อนคำอธิบายรูปภาพที่นี่


4
เห็นได้ชัดว่าคุณมีความไม่มั่นคงหรือเสียงรบกวนเล็กน้อยในคอนโทรลเลอร์เซอร์โวของคุณ อย่างไรก็ตามคุณเข้าไปดูรายละเอียดของสิ่งต่าง ๆ มากมายที่ดูเหมือนว่าไม่มีอะไรเกี่ยวข้องกับคอนโทรลเลอร์เซอร์โวนอกจากตำแหน่งที่ไม่มีเอกสาร "positionServo ();" ซึ่งเราสามารถเดาได้ว่ารายละเอียดถูกฝังอยู่ที่ไหน คอนโทรลเลอร์เซอร์โวปิดอยู่ในไมโครหรือไม่ ปิดจากภายนอกหรือไม่ อะนาล็อกหรือดิจิตอล หากเป็นดิจิตอลจะทำการวัดความละเอียดเท่าใด แสดงไดอะแกรมของระบบทั้งหมด
Olin Lathrop

คุณใส่เซอร์โวไว้เท่าไหร่?
Chris Laplante

4
@OlinLathrop - (S) เขาใช้เซอร์โวโมเดลควบคุมวิทยุมาตรฐานซึ่งมีวงเซอร์โวทั้งหมดถูกอบเข้าสู่อุปกรณ์ sherrellbc - "Servo" เป็นคำศัพท์ที่ธรรมดามาก น่าเสียดายที่ผู้ผลิตชิ้นส่วนโมเดล RC เลือกเกี่ยวกับคำที่สื่อความหมายน้อยที่สุดสำหรับอุปกรณ์ที่ผลิต เนื่องจากเราจัดการกับเซอร์โวและเซอร์โวระบบต่างชนิดส่วนใหญ่ที่นี่การระบุว่า "เซอร์โว" ของคุณนั้นเป็นเซอร์โวโมเดลที่ควบคุมด้วยวิทยุน่าจะเป็นความคิดที่ดี
Connor Wolf

1
ระบบของคุณซับซ้อนเกินกว่าที่เราจะสามารถแก้ไขปัญหาให้คุณได้ ทำให้มันง่ายขึ้นและดูว่าคุณยังมีปัญหาอยู่หรือไม่ เมื่อคุณมีระบบน้อยที่สุดที่ทำให้เกิดปัญหาขึ้นอีกและคุณยังคงไม่สามารถแก้ไขได้ด้วยตนเองคุณควรขอความช่วยเหลือ
Phil Frostst

12
หมายเหตุทั่วไปสำหรับการออกแบบระบบควบคุมด้วยเลเซอร์: วางมิเรอร์ลงบนเซอร์โว ด้วยวิธีนี้คุณไม่จำเป็นต้องติดตั้งเซอร์โวตัวใดตัวหนึ่งลงบนอีกตัวหรือไม่ก็ติดตั้งเลเซอร์บนเซอร์โว
pjc50

คำตอบ:


27

เมื่อใช้ไลบรารี Servo บน Arduino แหล่งที่มาทั่วไปของ servo buzz คือรูทีน servo-driven interrupt ไม่ได้ให้พัลส์เอาต์พุตที่เสถียรมาก เนื่องจาก AVR ใช้การขัดจังหวะในการให้บริการนาฬิกา millis () และสิ่งอื่น ๆ ในรันไทม์ Arduino, ความกระวนกระวายใจในห้องสมุดเซอร์โวนั้นอยู่ในลำดับของไมโครวินาทีซึ่งแปลเป็นจำนวนมากในเซอร์โว

การแก้ไขสำหรับสิ่งนี้คือการเขียนชีพจรของคุณเอง บางสิ่งเช่นนี้

cli();
long start = micros();
digitalWrite(PIN, HIGH);
while (micros() - start < duration)
  ;
digitalWrite(PIN, LOW);
sei();

สิ่งนี้จะปิดการขัดจังหวะอื่น ๆ และสร้างพัลส์ PWM ที่สะอาดกว่ามาก อย่างไรก็ตามมันจะทำให้ตัวจับเวลา "millis () พลาดติ๊กนาฬิกา (ฟังก์ชั่น" micros () "อาจเรียกได้ว่าเป็นอย่างอื่น - ฉันลืมไปเลย)

โดยทั่วไปสำหรับรหัสกำหนดเวลาที่สำคัญคุณต้องการกำจัด Arduino runtime ทั้งหมดและเขียนของคุณเองโดยใช้คอมไพเลอร์ avr-gcc และไลบรารี avr-libc ที่ขับเคลื่อนสภาพแวดล้อม Arduino จากนั้นคุณสามารถตั้งค่าตัวจับเวลาเพื่อทำเครื่องหมาย 4 ครั้งต่อไมโครวินาทีหรือแม้แต่ 16 ครั้งต่อไมโครวินาทีและรับความละเอียดที่ดีขึ้นใน PWM ของคุณ

อีกสาเหตุที่ทำให้เกิดเสียงกระหึ่มในเซอร์โวคือเซอร์โวราคาถูกที่มีเซ็นเซอร์ราคาถูกซึ่งเซ็นเซอร์ดังเกินไปหรือเมื่อตำแหน่งที่แน่นอนที่ร้องขอด้วยพัลส์ไม่สามารถเข้ารหัสด้วยเซ็นเซอร์ได้ เซอร์โวจะเห็น "ย้ายไปที่ตำแหน่ง 1822" และลองทำ แต่จบลงด้วยการอ่านเซ็นเซอร์ 2366 จากนั้นเซอร์โวจะพูดว่า "เลื่อนกลับเล็กน้อย" และจบลงด้วยการอ่านเซ็นเซอร์ 1821 ทำซ้ำ! การแก้ไขสำหรับสิ่งนี้คือการใช้เซอร์โวคุณภาพสูง เป็นการดีที่ไม่ใช่เซอร์โวงานอดิเรกเลย แต่เป็นเซอร์โวที่แท้จริงที่มีเอนโค้ดเดอร์แบบสัมบูรณ์หรือแบบแม่เหล็ก

ในที่สุดหากเซอร์โวไม่ได้รับพลังงานเพียงพอหรือหากคุณลองขับพลังงานจากราง 5V บน Arduino สิ่งนี้จะสร้างเสียงกระหึ่มที่เกิดจากแรงดันไฟฟ้าในเซอร์โวดังที่ได้กล่าวไว้ข้างต้น คุณอาจจะสามารถแก้ไขได้ด้วยตัวเก็บประจุด้วยไฟฟ้าขนาดใหญ่ (ซึ่งเป็นความคิดที่ดีสำหรับการกรองทั่วไปอยู่ดี) แต่คุณมีแนวโน้มที่จะทำให้แน่ใจว่าแหล่งพลังงานของเซอร์โวของคุณสามารถส่งกระแสไฟฟ้าได้หลายแอมป์ที่แรงดันเซอร์โว


1
สัญญาณควบคุมเซอร์โว R / C คือ PWM ความกว้างของพัลส์คือในนาม 1-2 มิลลิวินาทีช่วงเวลาการทำซ้ำของชีพจรอยู่ที่ใดก็ได้จาก 20 ถึง 50 มิลลิวินาที ฉันคาดหวังว่าจะมีการเปลี่ยนแปลงมากกว่า 10 ไมโครวินาทีในความกว้างพัลส์เพื่อให้เซอร์โวสั่นไหว กระวนกระวายใจใน PRI โดยทั่วไปจะไม่เป็นปัญหาหากความกว้างของพัลส์คงที่ (ตัวควบคุมที่เรียบง่ายของฉัน 555 ตัวควบคุมความกว้างของพัลส์และ PRI ตามจำนวนเดียวกัน: เซอร์โวไม่สนใจ)
John R. Strohm

ทุกสิ่งที่คุณพูดนั้นเป็นความจริงยกเว้นกระวนกระวายใจ - เซอร์โวจะกระวนกระวายใจก่อนที่ความกว้างของคลื่นจะ "ปิด" โดย 10 เรา และกระวนกระวายใจขัดจังหวะสำหรับ Arduino ธรรมดา (ก่อนที่คุณจะเพิ่มห้องสมุด) สามารถไปสูงถึง 10 เรา! รหัสที่ฉันวางมีจุดประสงค์เพื่อสร้างพัลส์ที่มั่นคงของหินในสภาพแวดล้อม Arduino ซึ่งโดยทั่วไปจะไม่ดีเท่าของเซอร์โวที่เสถียรของร็อคในขณะที่วงจร 555 โดยเฉพาะ
Jon Watte

4
ฉันเพิ่งเขียนบทความที่แสดงวิธีการสร้างพัลส์ที่แม่นยำบน Arduinoเช่นโค้ดด้านบนยกเว้นว่าจะใช้ฮาร์ดแวร์ตัวตั้งเวลา - และไม่จำเป็นต้องปิดการขัดจังหวะ
bigjosh

โปรดทราบว่า Arduino สนับสนุนเฉพาะเอาต์พุตตัวจับเวลาในพินไม่กี่ (พิน PWM) และคุณไม่สามารถใช้พิน Timer0 สำหรับวิธีนี้ได้ ดังนั้นจึงมีเพียง 4 พินที่ใช้งานได้จริงกับ Arduino UNO ปกติ ถ้าคุณต้องการขับเซอร์โว 4 ตัวหรือน้อยกว่าและไม่ต้องการตัวจับเวลาสำหรับสิ่งอื่นนั่นเป็นตัวเลือกที่ดี
Jon Watte

21

สิ่งนี้เรียกว่า "buzz"

มีสองสิ่งที่จะทำให้เกิด ความไม่มั่นคงในอำนาจต่อเซอร์โวนั้นเป็นสาเหตุที่พบบ่อย เซอร์โว R / C สามารถวาดแหลมใหญ่บางอย่างเมื่อพวกเขาวางมอเตอร์ในการเคลื่อนไหวครั้งแรก

หลายปีที่ผ่านมาฉันเล่นกับเซอร์โวทาวเวอร์ไททันมาตรฐานรอยัลควบคุมมันจาก 555 และอินเวอร์เตอร์ทรานซิสเตอร์ วงจรควบคุมแบบตายง่าย ฉันได้เรียนรู้ว่าเซอร์โวมอเตอร์ดึง 250 mA จากแหล่งจ่ายไฟ 5V ขณะเคลื่อนไหวต่อเนื่อง หึ่ง, มันแหลมอย่างแรงได้ครึ่งแอมป์ (อาจมากกว่านี้: ฉันเพิ่งตรวจสอบมิเตอร์ปัจจุบันบนอุปกรณ์จ่ายของฉันไม่ใช่การกำหนดขอบเขตการตรวจจับกระแสไฟฟ้า)

มันใช้ 220 ยูเอฟโดยตรงผ่านเซอร์โวของฉันเพื่อทำให้เชื่อง

ลองใส่ตัวเก็บประจุด้วยไฟฟ้าอย่างน้อย 100 uF ข้ามแหล่งจ่ายไฟไปยังเซอร์โวโดยตรงใกล้ ๆ กับเซอร์โวไฟฟ้าเท่าที่คุณจะทำได้และดูว่ามันช่วยได้ไหม

จากการทดลองเหล่านั้นฉันจะไม่พิจารณาใช้ R / C เซอร์โวสำหรับสิ่งใดโดยไม่เพิ่มตัวเก็บประจุ นั่นรวมถึงรุ่นที่ควบคุมด้วยวิทยุ

สิ่งนี้อาจเกิดจากสิ่งสกปรกในหม้อเซอร์โวภายในเซอร์โว ลองใช้ตัวเก็บประจุก่อน


6

การสั่นสะเทือนของคุณเกิดขึ้นเมื่ออยู่ในหรือใกล้กับขีด จำกัด ของเซอร์โว (0 องศาหรือ 180 องศา) หรือไม่ ถ้าเป็นเช่นนั้นอาจมีวิธีแก้ไขอย่างง่ายสำหรับคุณ ฉันพบว่าเซอร์โวราคาถูกไม่รู้ว่าจะอยู่ในขอบเขตการเคลื่อนไหวของพวกเขาได้ดีมากซึ่งสามารถทำให้เกิดการสั่นสะเทือน / สั่นคุณพูดถึง อย่างไรก็ตามหากคุณ จำกัด ช่วงของมันไว้ที่ 10 ~ 170 องศาปัญหาจะได้รับการแก้ไข

หากนั่นยังไม่ดีพอสำหรับคุณคุณสามารถติดตามการแก้ไขที่ซับซ้อนกว่าที่ระบุไว้ในคำตอบอื่น ๆ เช่นพลังงานที่ดีกว่าเซ็นเซอร์เซอร์โวที่ดีขึ้น ฯลฯ


ใช่สำหรับ SG90 ของฉันค่าเหล่านี้คือ 18 ถึง 162 จริงๆแล้วมันไม่ได้ทำให้เข้าถึงไม่ได้ 32 องศาบางทีอาจเป็นเพียงครึ่งหนึ่ง
Maxim Kachurovskiy

5

ฉันแก้ไขปัญหาด้วยการ "ปิดเซอร์โว" หลังจากที่ฉันย้าย ตัวอย่าง:

pinMode(PIN, OUTPUT);
myservo.write(degree);
//give servo time to move
delay(5000);
pinMode(PIN, INPUT);

PINคือเข็ม PWM ที่เชื่อมต่อกับเซอร์โวของคุณ ด้วยการเปลี่ยนเป็นโหมดป้อนข้อมูลฉันสามารถปิดการสั่นสะเทือนได้ นี่ไม่ใช่ทางออกที่ดีที่สุดและฉันขอแนะนำให้ลองวิธีอื่นก่อน


ฉันลองใช้วิธีแก้ไขปัญหาอื่น ๆ นี่เป็นวิธีเดียวในการทำงาน +1 ความคิดที่ดีเมื่อทุกอย่างล้มเหลว!
Snappawapa

3

ฉันมีปัญหาเดียวกันกับเซอร์โว MG90S (การกระวนกระวายใจ), สายสัญญาณของฉันค่อนข้างยาว (60 ~ 70 ซม.), การวางตัวเก็บประจุ 103 (10nF) เหนือสัญญาณและสายกราวด์แก้ไขปัญหาให้ฉัน (ฉันวางตัวเก็บประจุไว้ที่อื่น ตรงกลางตรงจุดที่สายเคเบิลเดิมเชื่อมต่อกับสายภายในของฉัน)

นอกจากนี้ฉันไม่สามารถใช้ไลบรารี Servo มาตรฐานได้เนื่องจากตัวจับเวลาตัวแรกที่คว้าบน Arduino Mega คือ Timer-5 และฉันต้องการสิ่งนั้นสำหรับการวัดความถี่ เนื่องจากฉันใช้ 10 เซอร์โวเท่านั้นฉันจึงดึงรหัสคีย์จากไลบรารีเซอร์โวและเปลี่ยนเป็นการใช้ตัวจับเวลา -1 (แต่ละตัวจับเวลารองรับเซอร์โวสูงสุด 12 เมกกะ)

รหัสสแตนด์อโลนอยู่ด้านล่างสำหรับการอ้างอิงถ้าคุณต้องการที่จะรวมไว้ในโครงการของคุณเองคุณสามารถใช้ส่วนบนเท่านั้นส่วนล่างคือการทดสอบส่วนบน (มันฟังพอร์ตอนุกรมคุณสามารถให้ sX และคำสั่ง vX โดยที่ sX เลือก servo, s0 จะเลือก servo ตัวแรก vX ตั้งค่าตำแหน่ง servo ในเราดังนั้น v1500 จะตั้งค่า servo0 ให้อยู่ในตำแหน่งตรงกลางโดยสมมติว่าคุณให้คำสั่ง s0 ก่อน)

//----------------------------------------------------------------
// This is the actual servo code extracted from the servo library
//----------------------------------------------------------------

#include <avr/pgmspace.h>

//----converts microseconds to tick (assumes prescale of 8)
#define usToTicks(_us)    (( clockCyclesPerMicrosecond()* _us) / 8)

#define MIN_PULSE_WIDTH     544     // the shortest pulse sent to a servo  
#define MAX_PULSE_WIDTH     2400    // the longest pulse sent to a servo 
#define DEFAULT_PULSE_WIDTH 1500    // default pulse width when servo is attached
#define REFRESH_INTERVAL    20000   // minumim time to refresh servos in microseconds

#define TRIM_DURATION       2       // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009

struct s_servar {
    //----counter for the servo being pulsed for each timer (or -1 if refresh interval)
    int8_t  channel;
};
static volatile struct s_servar gl_vars;

//----maximum number of servos controlled by one timer 
#define SERVOS_PER_TIMER    12
//----this can not be higher than SERVOS_PER_TIMER
#define SERVO_AMOUNT        6

struct s_servo {
    volatile unsigned int   ticks;
    unsigned char           pin;
};
struct s_servo  gl_servos[SERVO_AMOUNT] = {
    { usToTicks(DEFAULT_PULSE_WIDTH), 22 },
    { usToTicks(DEFAULT_PULSE_WIDTH), 23 },
    { usToTicks(DEFAULT_PULSE_WIDTH), 24 },
    { usToTicks(DEFAULT_PULSE_WIDTH), 25 },
    { usToTicks(DEFAULT_PULSE_WIDTH), 26 },
    { usToTicks(DEFAULT_PULSE_WIDTH), 27 },
};

ISR(TIMER1_COMPA_vect) {
    unsigned char       servooff;
    if(gl_vars.channel < 0 ) {
        //----channel set to -1 indicated that refresh interval completed so reset the timer
        TCNT1 = 0;
    }
    else{
        servooff = gl_vars.channel;
        if(servooff < SERVO_AMOUNT) {
            //----end the pulse
            digitalWrite(gl_servos[servooff].pin, LOW);
        }
    }
    //----increment to the next channel
    gl_vars.channel++;
    servooff = gl_vars.channel;
    if(servooff < SERVO_AMOUNT) {
        //----set timer interrupt for pulse length
        OCR1A = TCNT1 + gl_servos[servooff].ticks;
        //----start the pulse
        digitalWrite(gl_servos[servooff].pin, HIGH);
    }
    else {
        // finished all channels so wait for the refresh period to expire before starting over
        //----allow a few ticks to ensure the next OCR1A not missed
        if(((unsigned)TCNT1) + 4 < usToTicks(REFRESH_INTERVAL)) {
            OCR1A = (unsigned int)usToTicks(REFRESH_INTERVAL);
        }
        else {
            //----at least REFRESH_INTERVAL has elapsed
            OCR1A = TCNT1 + 4; 
        }
        //----this will get incremented at the end of the refresh period to start again at the first channel
        gl_vars.channel = -1;
    }
}

void InitServoISR() {
    unsigned char   ct;
    gl_vars.channel = -1;
    //----init timer 1
    TCCR1A = 0;             // normal counting mode
    TCCR1B = _BV(CS11);     // set prescaler of 8
    TCNT1 = 0;              // clear the timer count
    TIFR1 |= _BV(OCF1A);    // clear any pending interrupts;
    TIMSK1 |= _BV(OCIE1A);  // enable the output compare interrupt
    //----set all servo pins to output
    for(ct = 0; ct < SERVO_AMOUNT; ct++) {
        pinMode(gl_servos[ct].pin, OUTPUT); 
    }
}

void SetServoMicroSecs(unsigned char servooff, unsigned short value) {
    uint8_t oldSREG;
    if(servooff < SERVO_AMOUNT) {
        //----ensure pulse width is in range
        if(value < MIN_PULSE_WIDTH) { value = MIN_PULSE_WIDTH; }
        else {
            if(value > MAX_PULSE_WIDTH) { value = MAX_PULSE_WIDTH; }
        }
        value -= TRIM_DURATION;
        value = usToTicks(value);
        oldSREG = SREG;
        cli();
        gl_servos[servooff].ticks = value;
        SREG = oldSREG;
    }
}

//------------------------------------------------
// This is code to test the above servo functions
//------------------------------------------------

#define ERR_OK          0
#define ERR_UNKNOWN     1
#define ERR_OUTOFRANGE  2

#define SERDEBUG_CODE
#define MAX_SER_BUF     12

void setup() { 
    InitServoISR();

    #ifdef SERDEBUG_CODE
    Serial.begin(9600);
    Serial.println(F("Start"));
    #endif
}


void loop() {
    #ifdef SERDEBUG_CODE
    uint8_t         ct, chr;
    char            buf[MAX_SER_BUF];
    ct = 0;
    #endif   
    //----main while loop
    while(1) {
        #ifdef SERDEBUG_CODE
        //--------------------
        // Serial Port
        //--------------------
        while (Serial.available() > 0) {
            chr = Serial.read();
            if(chr == '\n') {
                ProcSerCmd(buf, ct);
                ct = 0;
            }
            else {
                //----if for some reason we exceed buffer size we wrap around
                if(ct >= MAX_SER_BUF) { ct = 0; } 
                buf[ct] = chr;
                ct++;
            }
        }
        #endif
    }
}

//------------------------------
// Serial Port Code
//------------------------------

#ifdef SERDEBUG_CODE
uint16_t RetrieveNumber(char *buf, uint8_t size) {
    //--------------------------------------------------------------
    // This function tries to convert a string into a 16 bit number
    // Mainly for test so no strict checking
    //--------------------------------------------------------------
    int8_t  ct;
    uint16_t    out, mult, chr;
    out = 0;
    mult = 1;
    for(ct = size - 1; ct >= 0; ct--) {
        chr = buf[ct];
        if(chr < '0' || chr > '9') { continue; }
        chr -= '0';
        chr *= mult;
        out += chr;
        mult *= 10;
    }
    return(out);
}

void ProcSerCmd(char *buf, uint8_t size) {
    //-----------------------------------------------------------
    // supported test commands
    // sX   X = 0 to SERVO_AMOUNT       Sets the servo for test
    // vX   X = MIN to MAX PULSE WIDTH  Sets the test servo to value X
    //-----------------------------------------------------------
    static unsigned char    lgl_servooff = 0;
    uint8_t                 chr, errcode;
    uint16_t                value;
    errcode = 0;
    while(1) {
        chr = buf[0];
        //----test commands (used during development)
        if(chr == 's') {
            value = RetrieveNumber(buf + 1, size - 1);
            if(value < 0 || value >= SERVO_AMOUNT) { errcode = ERR_OUTOFRANGE; break; }
            lgl_servooff = (unsigned char)value;
            break;
        }
        if(chr == 'v') {
            value = RetrieveNumber(buf + 1, size - 1);
            if(value < MIN_PULSE_WIDTH || value > MAX_PULSE_WIDTH) { errcode = ERR_OUTOFRANGE; break; }
            SetServoMicroSecs(lgl_servooff, value);
            break;
        }
        errcode = ERR_UNKNOWN;
        break;
    }
    if(errcode == 0) {
        Serial.println(F("OK"));
    }
    else {
        Serial.write('E');    
        Serial.println(errcode);
    }
}
#endif

2

ตัวเลือกที่ดีที่สุดของฉันในกรณีนี้คือการแนบและแยกเซอร์โวในแต่ละการดำเนินการ

servo1.attach(pinServo1);
for (pos = 0; pos <= servoMax; pos += 1) {
    servo1.write(pos);
    delay(10);
}
servo1.detach(pinServo1);

PS ที่นี่ไม่มีคุณภาพเลยเพียงแค่แก้ไขปัญหาเท่านั้น


1

ในขณะที่คนอื่น ๆ ได้แนะนำวิธีแก้ปัญหาต่าง ๆ สำหรับปัญหาการส่งเสียงเซอร์โวในหัวข้อนี้และฟอรัม Arduino อื่น ๆ ได้แก่ :

  • สร้างชีพจรของตัวเอง
  • จ่ายไฟ 5V แยกต่างหาก
  • หลีกเลี่ยงการเพิ่มขีด จำกัด (เช่นใช้ 10-170 แทน 0-180)
  • วิ่งผ่านตัวเก็บประจุ
  • ถอดออกหลังจากย้าย

ในกรณีของฉันฉันพบว่าการส่งเสียงพึมพำหยุดเมื่อไฟ 9V / 2A เสียบเข้ากับบอร์ด Arduino แต่ทางออกที่ดีที่สุดที่ง่ายที่สุดคือการย้ายเซอร์โวช้า:

for (pos = servo.read(); pos < 180; pos += 2) {
  servo.write(pos);
  delay(40);
}

YMMV


1
#include <Servo.h>             //Servo library
Servo servo_test;        //initialize a servo object for the connected servo  

int angle = 0;
int sw1 = 7;   // pushbutton connected to digital pin 7
int val=0;

void setup()
{
   servo_test.attach(2);     // attach the signal pin of servo to pin2 of arduino
   pinMode(sw1, INPUT_PULLUP);
}

void loop()
{
    val = digitalRead(sw1);
    if (val == LOW)
    {  
        servo_test.attach(2);     // attach the signal pin of servo to pin2 of arduino
        for(angle = 0; angle < 90; angle += 1)   // command to move from 0 degrees to 90 degrees 
        {                                  
            servo_test.write(angle);                 //command to rotate the servo to the specified angle
            delay(5);                     
        } 
    }
    else
    {
        servo_test.detach();// After servo motor stops we need detach commmand to stop vibration
    }
}

0

สำหรับฉันดูเหมือนว่าข้อผิดพลาดหรือการปรับห่วงข้อเสนอแนะผิด ระบบควบคุมเซอร์โวระดับสูงมีความรู้เกี่ยวกับลักษณะของมอเตอร์ (ตัวเหนี่ยวนำแรงบิดกระแสไฟฟ้าสูงสุดจำนวนขั้ว) ภาระ (โมเมนต์ความเฉื่อย) และสภาวะฉับพลัน (ตำแหน่ง, รอบต่อนาที, แรงเคลื่อนไฟฟ้าย้อนกลับ, กระแสไฟฟ้า) ด้วยข้อมูลนี้โปรแกรมควบคุมมอเตอร์สามารถคาดการณ์เกี่ยวกับสิ่งที่เซอร์โวจะทำเพื่อตอบสนองต่ออินพุตที่กำหนดจากตัวควบคุม (เช่นอินพุตปัจจุบัน / แรงดันไฟฟ้า) และบนพื้นฐานนั้นจะสร้างอินพุตที่เหมาะสมเพื่อให้ได้ผลลัพธ์ที่ต้องการ

อย่างที่คุณสามารถจินตนาการได้สิ่งนี้ค่อนข้างซับซ้อน แต่การค้นหาทางอินเทอร์เน็ตเกี่ยวกับข้อเสนอแนะจากเซอร์โวจะช่วยให้คุณเริ่มต้นได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.