อัลกอริทึมสำหรับการผสมอินพุตแบบอะนาล็อก 2 แกนเพื่อควบคุมมอเตอร์ขับเคลื่อนที่แตกต่างกัน


9

ฉันกำลังมองหาข้อมูลเกี่ยวกับวิธีการผสมสัญญาณจอยสติ๊กแบบแอนะล็อก 2 แกน (แกน X และแกน Y) อย่างเหมาะสมเพื่อควบคุมไดรฟมอเตอร์ดิฟเฟอเรนเชียลแบบสองทาง uC ใด ๆ ที่มีอินพุต ADC และเอาต์พุต PWM):

ฉันมีอะนาล็อกสติ๊กที่ให้ 2 ค่าอะนาล็อก:

(ทิศทาง) X: 0 ถึง 1023
(เค้น) Y: 0 ถึง 1023

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

ตำแหน่งที่เหลือคือ (ทิศทางและความเป็นกลางของคันเร่ง) 512,512
คันเร่งไปข้างหน้า / ทิศทางซ้ายคือ 0,0
เต็มไปข้างหน้าเต็มไปทางขวาคือ 1,023,0
เป็นต้น

มอเตอร์ถูกควบคุมโดยไดรเวอร์ 2 H-bridge, 2 PWM พินสำหรับแต่ละตัว (ไปข้างหน้า, ถอยหลัง) เช่น:
Left Motor: -255 ถึง 255
Right Motor: -255 ถึง 255
(ค่าบวกเปิดใช้งาน PWM พินไปข้างหน้า, ลบเปิดใช้งานย้อนกลับ PWM pin, 0 ปิดใช้งานทั้งคู่)

เป้าหมายคือการผสมสัญญาณอนาล็อกจอยสติ๊กเพื่อให้ได้การตอบสนองต่อไปนี้:

a) คันเร่งไปข้างหน้าทิศทางที่เป็นกลาง = ยานพาหนะที่กำลังเคลื่อนที่ไปข้างหน้า
b) คันเร่งไปข้างหน้าทิศทางซ้าย = ยานพาหนะที่เคลื่อนที่ไปข้างหน้าและเลี้ยวซ้าย
c) คันเร่งที่เป็นกลางทิศทางซ้าย = รถเลี้ยวซ้ายในสถานที่

... และในทำนองเดียวกันสำหรับชุดค่าผสมอื่น ๆ แน่นอนเอาต์พุตควรเป็น "analog" นั่นคือมันควรยอมให้มีการเปลี่ยนแปลงอย่างค่อยเป็นค่อยไปจากตัวอย่างจากตัวเลือก a) ไปยัง b) ถึง c)

แนวคิดคือ:

http://www.lynxmotion.com/images/html/build123.htm


(1) โปรดทราบว่าอัลกอริทึมพื้นฐานของฉันช่วยให้การควบคุมความเร็วของ 'เปิดใน' เมื่อกดจอยสติ๊กเช่นซ้ายโดย% เต็มสเกล (2) ข้อกำหนดนี้ต้องได้รับการแก้ไขอีกหลายครั้งในขณะนี้ ชุมชนตัวอย่างควรมีคำตอบสำหรับสิ่งนี้ (3) หากผู้รับแปลคำสั่งเป็นความเร็วในการติดตามโดยใช้คำติชมยานพาหนะจะทำงานเหมือนกับสภาพพื้นดินที่เปลี่ยนแปลง แต่หากมีการแปลคำสั่งเป็นพลังงานมอเตอร์หรือแรงดันไฟฟ้าเป็นต้นประสิทธิภาพของยานพาหนะจะแตกต่างกันไปตามสภาพพื้นดิน - น่าจะเป็น 91)
รัสเซลแม็คมาฮอน

รัสเซลฉันลงมือทำอะไรมากมายสำหรับนักสำรวจและฉันก็พบว่ามีอุปกรณ์ควบคุมมอเตอร์จำนวนมากที่พร้อมเชื่อมต่อโดยตรงกับตัวรับสัญญาณ RC แต่ไม่มีข้อมูลเกี่ยวกับอัลกอริทึมภายในมากนัก
Kamil Zadora

ขอให้เป็นวันที่ดี! เรนโฮเป็นลูกพี่ลูกน้องที่พยายามเป็นอัมพาตในวัยแรกเกิดและสร้างรถเข็นคนพิการที่รายการของพวกเขาทำงานได้ดี แต่แรงดันเอาต์พุตต่ำเกินไป! ช่วยฉันด้วย! ฉันใช้อาร์ดิโนอาโน่

@ Johnny ยินดีต้อนรับสู่ Electronics.Stackexchange! โปรดดูคำถามที่พบบ่อยเพื่อทำความเข้าใจว่าเว็บไซต์นี้ทำงานอย่างไรและหากคุณมีคำถามที่จะถามโปรดใช้ปุ่มเฉพาะที่มุมบนขวาของหน้า
clabacchio

มันใช้งานได้หรือไม่
Russell McMahon

คำตอบ:


4

การผสม "เหมาะสม" เปิดให้มีการอภิปราย :-)

ปัญหาคือคุณต้องตัดสินใจว่าแทร็กนั้นเคลื่อนที่เร็วเพียงใดภายใต้สัญญาณบริสุทธิ์จากหม้อหนึ่งและสิ่งที่ต้องทำเมื่อรวมสัญญาณจากหม้ออื่น ๆ เข้าด้วยกัน ตัวอย่างเช่นถ้าคุณผลัก FB (Forward-Backward pot ไปข้างหน้าอย่างเต็มที่) และหากมอเตอร์ทั้งสองนั้นวิ่งด้วยความเร็วเต็มหน้าคุณจะจัดการกับการเพิ่มจำนวน LR (ซ้าย - ขวา) ลงในหม้อได้อย่างไร รับการหมุนคุณจะต้องมีหนึ่งแทร็คที่จะวิ่งเร็วกว่าอีกอันดังนั้นหากคุณวิ่งด้วยความเร็วสูงสุดไปข้างหน้าบนมอเตอร์ทั้งสองตัวคุณจะต้องลดความเร็วแทร็กหนึ่งหรือแทร็คอื่น ๆ จะเร่งหนึ่งหรือแทร็กอื่นเพื่อให้ได้ผลลัพธ์เดียวกัน

ทั้งหมดที่กล่าวมานี่เป็นวิธีแก้ปัญหาการเริ่มต้นง่ายๆจากหัวของฉันซึ่งดูเหมือนว่าจะเป็นการเริ่มต้นที่ดี

หากกระถางมีความเป็นอิสระทางกลไกทั้งคู่สามารถอยู่ที่ 100% พร้อมกัน
หากทั้งคู่อยู่ในประเภทจอยสติกถ้า Yaxis = 100% และ Xaxis = 0% การเพิ่ม B บางอย่างมักจะลด A. จอยสติ๊กสามารถสร้างได้โดยที่ไม่เป็นความจริง แต่สิ่งเหล่านี้ผิดปกติ
สมมติว่าจอยสติกเป็นประเภทที่เพิ่ม Y% เมื่อ X = 100% จะลด X. สามารถสร้างสมมติฐานอื่น ๆ ได้

FB = หม้อหน้า - หลัง จัดกึ่งกลางของศูนย์, + Ve สำหรับการเคลื่อนที่ไปข้างหน้าของหม้อ

LR = หม้อซ้ายขวา ศูนย์ศูนย์ + หาหม้อที่ถูกต้อง

K เป็นตัวประกอบสเกลในขั้นต้น 1
หากผลลัพธ์ใดเกิน 100% ให้ปรับค่า K ดังนั้นผลลัพธ์ = 100% และใช้ค่า K เดียวกันสำหรับมอเตอร์อื่นด้วยเช่นกัน

  • เช่นถ้าผลลัพธ์ของมอเตอร์ด้านซ้าย = 125 และผลลัพธ์ของมอเตอร์ด้านขวา = 80 แล้ว
    เท่ากับ 125 x 0.8 = 100 ให้ตั้ง K = 0.8 แล้วก็
    ซ้าย = 125 x 0.8 = 100% ขวา = 80 x 0.8 = 64%

แล้ว:

  • มอเตอร์ซ้าย = K x (Front_Back + Left_Right)

  • มอเตอร์ทางขวา = K x (Front_Back - Left_Right)

ตรวจสอบสติ:

  • LR = 0 (กึ่งกลาง), FB = เต็ม fwd -> มอเตอร์ทั้งคู่วิ่งไปข้างหน้าอย่างเต็มที่

  • LR = ซ้ายเต็ม, FB = 0 ->
    มอเตอร์ด้านซ้ายวิ่งไปข้างหลังเต็ม,
    มอเตอร์ขวาวิ่งไปข้างหน้าเต็ม
    ยานพาหนะหมุนทวนเข็มนาฬิกา

  • FB คือ 100%, Lr = 0% เพิ่ม 10% ของ LR ไปทางขวา
    L = FB + LR = 100% - + 10% R = FB-LR = 100% - - 10%

หากแกนที่ใหญ่ที่สุด <100% ปรับมาตราส่วนจนถึง = 100%
จากนั้นปรับขนาดแกนอื่น ๆ ด้วยจำนวนเดียวกัน


ขอบคุณรัสเซล - ฉันจะพยายามใช้สิ่งนี้ในการตั้งค่าแบบจำลองของฉัน BTW, จอยสติ๊กของฉันสามารถเดินหน้าต่อไปได้ในขณะที่แพนกล้องจากซ้ายไปขวาและอีกด้านหนึ่งคล้ายกับสิ่งนี้: static.sparkfun.com/images/products/09032-03-L_i_ma.jpg
Kamil Zadora

1
ขณะนี้ฉันกำลังมอบหมายให้แก้ปัญหาเดียวกันในที่ทำงาน ฉันมีคอนโทรลเลอร์แบบ 2 แกนของ wii nunchuk และจำเป็นต้องควบคุมมอเตอร์ 2 ตัวตามที่อธิบายในคำถาม ฉันมีปัญหาเล็กน้อยในการทำความเข้าใจตรรกะที่นี่ k1 / K1 หมายถึงอะไรกันแน่? หนึ่งคือตัวพิมพ์เล็กและอีกหนึ่งตัวพิมพ์ใหญ่ - ต่างกันหรือไม่? + Ve คืออะไร
Tal

1
ยอดเยี่ยม - ขอบคุณสำหรับความกระจ่าง ฉันต้องการนี้เขียนในหลามดังนั้นถ้าฉันเข้าใจถูกต้องนี้ควรทำมันpastebin.com/sWDakvLp มันดูเหมือนว่าฉันขาดอะไรไปหรือเปล่า? ดูเหมือนว่าจะทำงานในสภาพแวดล้อมการทดสอบของฉัน - ฉันจะต้องเชื่อมต่อกับมอเตอร์สุดท้ายที่ฉันจะต้องรู้แน่
Tal

1
1) ความเร็วมอเตอร์ถูกควบคุมโดย PWM ซึ่งใช้ค่าตั้งแต่ 0 - 100 เท่านั้นซึ่งเป็นเหตุผลที่ฉันใช้ 100 เป็นค่าสูงสุด 2) ฉันใช้ abs เพื่อค้นหาว่าจำเป็นต้องปรับขนาด (เช่นที่คุณพูด) และเพื่อให้ได้ขนาด ถ้าฉันลงเอยด้วยตัวคูณสเกล 0.8 เช่นและใช้กับจำนวนลบ, -125 * 0.8 = -100 รักษาทิศทางไว้ ฉันคิดว่ามันใช้งานได้เว้นแต่ฉันจะพลาดบางสิ่ง ฉันยังไม่ได้มีโอกาสลองใช้กับมอเตอร์ตัวสุดท้าย - เจ้านายของฉันจะสร้างแพลตฟอร์มทดสอบพร้อมมอเตอร์ที่ติดอยู่ซึ่งฉันจะสามารถทดสอบได้
Tal

1
ฉันไม่แน่ใจว่ารหัสของฉันจะใช้งานได้จริงหรือไม่ดังนั้นฉันจึงตั้งค่าลิงก์ Pastebin ก่อนหน้านี้ให้หมดอายุหลังจากหนึ่งสัปดาห์ เพราะมันดูเหมือนว่าจะทำงานที่นี่เป็นลิงค์ถาวรมากขึ้นที่มีความคิดเห็นไม่กี่มากขึ้นถ้าทุกคนมาเจอปัญหาอีกครั้ง: pastebin.com/EKguJ1KP ฉันจะใส่คำตอบลงไป แต่ดูเหมือนว่าฉันไม่มีตัวแทนเพียงพอที่จะโพสต์คำตอบ รหัสทั้งหมดขึ้นอยู่กับคำตอบของรัสเซลมาฮอน - เครดิตไปถึงเขา - ขอบคุณรัสเซล
Tal

5

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

ความคิดนั้นง่าย สมมติว่าค่าจอยสติ๊ก (x, y) เป็นพิกัดคาร์ทีเซียนบนระนาบสี่เหลี่ยม ทีนี้ลองนึกภาพว่าระนาบสี่เหลี่ยมจัตุรัสเล็ก ๆ หมุน45ºข้างใน

เครื่องบินตัวอย่าง

พิกัดของแท่งควบคุมให้จุดในสี่เหลี่ยมที่ใหญ่ขึ้นและจุดเดียวกันที่ซ้อนทับในสี่เหลี่ยมที่เล็กกว่าจะให้ค่าของมอเตอร์ คุณเพียงแค่ต้องแปลงพิกัดจากจตุรัสหนึ่งไปอีกจัตุรัสหนึ่งโดย จำกัด ค่าใหม่ (x, y) ไปทางด้านข้างของสี่เหลี่ยมเล็ก ๆ

มีหลายวิธีในการทำ Conversion วิธีที่ฉันชอบคือ:

  1. แปลงพิกัดเริ่มต้น (x, y) เป็นพิกัดเชิงขั้ว
  2. หมุนพวกมัน 45 องศา
  3. แปลงพิกัดเชิงขั้วกลับเป็นคาร์ทีเซียน
  4. Rescale พิกัดใหม่เป็น -1.0 / + 1.0
  5. ยึดค่าใหม่เป็น -1.0 / + 1.0

นี่ถือว่าเริ่มต้น (x, y) พิกัดอยู่ในช่วง -1.0 / + 1.0 ด้านของตารางด้านในจะเท่ากันเสมอไปl * sqrt(2)/2ดังนั้นขั้นตอนที่ 4 sqrt(2)เป็นเพียงเกี่ยวกับการคูณค่าโดย

นี่คือตัวอย่างการใช้ Python

import math

def steering(x, y):
    # convert to polar
    r = math.hypot(x, y)
    t = math.atan2(y, x)

    # rotate by 45 degrees
    t += math.pi / 4

    # back to cartesian
    left = r * math.cos(t)
    right = r * math.sin(t)

    # rescale the new coords
    left = left * math.sqrt(2)
    right = right * math.sqrt(2)

    # clamp to -1/+1
    left = max(-1, min(left, 1))
    right = max(-1, min(right, 1))

    return left, right

ความคิดเดิมสำหรับวิธีนี้ - มีวิธีการเปลี่ยนแปลงมากมีความซับซ้อนมากขึ้น - มาจากบทความนี้


0

ด้านล่างเป็นตัวอย่างของการใช้อัลกอริทึมผสมตามที่อธิบายโดยคำตอบของ Russel McMahon:

http://www.youtube.com/watch?v=sGpgWDIVsoE

//Atmega328p based Arduino code (should work withouth modifications with Atmega168/88), tested on RBBB Arduino clone by Modern Device:
const byte joysticYA = A0; //Analog Jostick Y axis
const byte joysticXA = A1; //Analog Jostick X axis

const byte controllerFA = 10; //PWM FORWARD PIN for OSMC Controller A (left motor)
const byte controllerRA = 9;  //PWM REVERSE PIN for OSMC Controller A (left motor)
const byte controllerFB = 6;  //PWM FORWARD PIN for OSMC Controller B (right motor)
const byte controllerRB = 5;  //PWM REVERSE PIN for OSMC Controller B (right motor)
const byte disablePin = 2; //OSMC disable, pull LOW to enable motor controller

int analogTmp = 0; //temporary variable to store 
int throttle, direction = 0; //throttle (Y axis) and direction (X axis) 

int leftMotor,leftMotorScaled = 0; //left Motor helper variables
float leftMotorScale = 0;

int rightMotor,rightMotorScaled = 0; //right Motor helper variables
float rightMotorScale = 0;

float maxMotorScale = 0; //holds the mixed output scaling factor

int deadZone = 10; //jostick dead zone 

void setup()  { 

  //initialization of pins  
  Serial.begin(19200);
  pinMode(controllerFA, OUTPUT);
  pinMode(controllerRA, OUTPUT);
  pinMode(controllerFB, OUTPUT);
  pinMode(controllerRB, OUTPUT);  

  pinMode(disablePin, OUTPUT);
  digitalWrite(disablePin, LOW);
} 

void loop()  { 
  //aquire the analog input for Y  and rescale the 0..1023 range to -255..255 range
  analogTmp = analogRead(joysticYA);
  throttle = (512-analogTmp)/2;

  delayMicroseconds(100);
  //...and  the same for X axis
  analogTmp = analogRead(joysticXA);
  direction = -(512-analogTmp)/2;

  //mix throttle and direction
  leftMotor = throttle+direction;
  rightMotor = throttle-direction;

  //print the initial mix results
  Serial.print("LIN:"); Serial.print( leftMotor, DEC);
  Serial.print(", RIN:"); Serial.print( rightMotor, DEC);

  //calculate the scale of the results in comparision base 8 bit PWM resolution
  leftMotorScale =  leftMotor/255.0;
  leftMotorScale = abs(leftMotorScale);
  rightMotorScale =  rightMotor/255.0;
  rightMotorScale = abs(rightMotorScale);

  Serial.print("| LSCALE:"); Serial.print( leftMotorScale,2);
  Serial.print(", RSCALE:"); Serial.print( rightMotorScale,2);

  //choose the max scale value if it is above 1
  maxMotorScale = max(leftMotorScale,rightMotorScale);
  maxMotorScale = max(1,maxMotorScale);

  //and apply it to the mixed values
  leftMotorScaled = constrain(leftMotor/maxMotorScale,-255,255);
  rightMotorScaled = constrain(rightMotor/maxMotorScale,-255,255);

  Serial.print("| LOUT:"); Serial.print( leftMotorScaled);
  Serial.print(", ROUT:"); Serial.print( rightMotorScaled);

  Serial.print(" |");

  //apply the results to appropriate uC PWM outputs for the LEFT motor:
  if(abs(leftMotorScaled)>deadZone)
  {

    if (leftMotorScaled > 0)
    {
      Serial.print("F");
      Serial.print(abs(leftMotorScaled),DEC);

      analogWrite(controllerRA,0);
      analogWrite(controllerFA,abs(leftMotorScaled));            
    }
    else 
    {
      Serial.print("R");
      Serial.print(abs(leftMotorScaled),DEC);

      analogWrite(controllerFA,0);
      analogWrite(controllerRA,abs(leftMotorScaled));  
    }
  }  
  else 
  {
  Serial.print("IDLE");
  analogWrite(controllerFA,0);
  analogWrite(controllerRA,0);
  } 

  //apply the results to appropriate uC PWM outputs for the RIGHT motor:  
  if(abs(rightMotorScaled)>deadZone)
  {

    if (rightMotorScaled > 0)
    {
      Serial.print("F");
      Serial.print(abs(rightMotorScaled),DEC);

      analogWrite(controllerRB,0);
      analogWrite(controllerFB,abs(rightMotorScaled));            
    }
    else 
    {
      Serial.print("R");
      Serial.print(abs(rightMotorScaled),DEC);

      analogWrite(controllerFB,0);
      analogWrite(controllerRB,abs(rightMotorScaled));  
    }
  }  
  else 
  {
  Serial.print("IDLE");
  analogWrite(controllerFB,0);
  analogWrite(controllerRB,0);
  } 

  Serial.println("");

  //To do: throttle change limiting, to avoid radical changes of direction for large DC motors

  delay(10);

}

น่าสนใจรหัสนี้ดูเหมือนว่ากำลังป้อนขาอะนาล็อก 2 ตัวกับตัวควบคุมมอเตอร์ 2 ตัว ฉันจะพยายามปรับเปลี่ยนรหัสและแก้ไขการตั้งค่าของฉัน บอร์ดควบคุม Arduino Uno + 1 Sabertooth จอยสติ๊ก 1 ตัวไปยังอะนาล็อก pinA0 (x) pinA1 (y) การอ่านและการส่งค่าไปยังเข็ม PWM 10 & 3 ไปที่ S1 & S2 ของ Sabertooth ฉันคิดว่าฉันสนิท แต่ฉันสับสนในการตั้งค่า dipswitch บนกระดาน Sabertooth ตอนนี้ฉันกำลังตั้งค่าสวิตช์เพื่อรับอินพุตแบบอะนาล็อกสวิตช์ 4 ยังคงอยู่ในตำแหน่งสำหรับไดรฟ์ที่แตกต่างกัน แต่จะนำกลับไปที่โหมดอิสระในภายหลังเพื่อการทดสอบเพิ่มเติม ฉันคิดว่าต้นกำเนิดนี้

@ user20514 ยินดีต้อนรับสู่ electronics.stackexchange! ดังที่คุณอาจสังเกตเห็นว่านี่ไม่ใช่ฟอรัม แต่เป็นเว็บไซต์ถามตอบดังนั้นพื้นที่ของคำตอบไม่ได้มีไว้สำหรับการอภิปราย โปรดอย่าลังเลที่จะถามคำถามใหม่หากคุณมีสิ่งที่จะถามหรือใช้ความคิดเห็นเพื่อ (แสดงความคิดเห็น) จริง ๆ เกี่ยวกับคำถามและคำตอบที่มีอยู่
clabacchio

1
@Kamil - วิดีโอแสดงเป็นส่วนตัว มันยังว่างอยู่ไหม? youtube.com/watch?v=sGpgWDIVsoE
Russell McMahon

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