์์์ ์์ฑํ ์ค์ค์ด 5ํธ์ 6ํธ๋ฅผ ์ ์ํ๊ณ , ๋ชจํฐ๋ฅผ ๋ฐ๊พธ๊ธฐ ์ด๋ ค์ธ ๋ฟ๋๋ฌ, ์ค๋ค๋ฆฌ๊ธฐ์ ์ ์ฉํ๊ธฐ ์ด๋ ค์ด ๋ชจ์ต์ด๋ผ๋ ํ๊ณ์ ์ํด์ ์ค์ค์ด 7ํธ๋ฅผ ์ ์ํ๊ฒ ๋์๋ค.
์ค์ค์ด 7ํธ๋ฅผ ๊ธํ๊ฒ ๋ง๋ค๊ฒ ๋๋ฉด์ ์ํฌ๋ฆด์ด ์๋ mdf๋ฅผ ์ง์ ์์ฐ๋ก ์ปคํ ํ๊ณ , ์ ์ํ ๋๋ฌธ์ ์ด์ง ์ด์คํ ๋ชจ์ต์ด๋ผ๊ณ ์๊ฐํ๋ค...ใ ใ
๊ฐ๋จํ ๋ณด์๋ฉด ํฌ์ธํธ๋ ๋ค์๊ณผ ๊ฐ๋ค.
1. ๋ฐํด์ ๊ณ ๋ฌด ํจํน์ ์งํํด, ๋ง์ฐฐ์ ๋๋ ค ๊ฐ๋ ๋ณด์ ์ด ์ฝ๋๋ก ๋ง๋ค์๋ค.
2. ์์์ ๋งํ ๊ฒ๊ณผ ๊ฐ์ด mdf๋ก ๋ง๋ค๋ฉฐ ์ค๋ค๋ฆฌ๊ธฐ๋ฅผ ์งํํ๊ธฐ์ ์ ํฉํ ๊ตฌ์กฐ๋ก ์ ์ํ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ ์ํ์ฌ ์๋์ ๊ฐ์ด ๊ฐ๋๋ฅผ ์ ์งํ ์ ์๋ ๊ฐ์ ๋ํด์ ํ ์คํธ๋ฅผ ์งํํด๋ณด์๋ค.
https://youtu.be/joFds-6ifk0 (์คํ ์์)
์ ์ฌ์ง์ ๋ณด๋ฉด 10๋์์๋ ๊ฐ๋๋ฅผ ์ถฉ๋ถํ ์ ์งํ ์ ์์์ ๋ณผ ์ ์์๋ค.
์ด ๊ณผ์ ์์ ์ค์ ๋ฌถ๋ ์์น๋ฅผ ๊ณ ์ ์ํค๋ ์ค์ด ๋ง์ฐฐ์ด ๋๋ฉด์ ์คํ์ด ์ ๋๋ก ์๋๋ฉฐ, ์ค์ ์์น๊ฐ ๋ฌธ์ ๊ฐ ์๊ธด๋ค๋ ๊ฒ์ ์๊ฒ ๋์ด ๊ตฌ๋ฉ์ ์ค์ค์ด ์ค๊ฐ์ ๋์ด๋ณ๋ก 4๊ฐ๋ฅผ ๋ซ์ด์ ์ฐ๋ง๋ด์ ๋ฃ์ด์ ์ค์ ๋ง์ฐฐ์ ์ต์ํํ๊ณ ์ ํ์๋ค.
์ค์ ๋์ด๋ฅผ ํธ๊ธฐ์ฌ์ ๊ฐ์ง๊ณ ๋ฐ๊ฟ๋ณธ ๊ฒฐ๊ณผ ์ค์ ์์น์ ๋ฐ๋ผ์, ์ฆ ์ค์ ๋์ด ์ก๋๊ฐ ํน์ ๋ฎ๊ฒ ์ก๋๊ฐ์ ๋ฐ๋ผ์ ๊ฒฐ๊ณผ๊ฐ ๋ง์ด ๋ฌ๋ผ์ง์ ์๊ณ , ๋ก๋ด์ ์ฌ๋์ ๋น๊ตํ์ฌ ์ต๋ํ ํ์ ๋ฑ ๋ผ์์ ์งํํ ์ ์๋ ๋์ด๋ฅผ ์ก๊ณ ์ ํ์๋ค. ๋ํ ๋์ด์ ๋ฐ๋ผ์ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ์๋ ์๋ค๋ ์๊ฐ์ ํ๊ฒ ๋์ด ์ดํ ๋ค์ ์ค์ค์ด๋ฅผ ์ ์ํ๋ค๋ฉด ์ค์ ๋ฌถ์ ์ ์๋ ๋์ด๋ฅผ ์กฐ์ ํ ์ ์๋๋ก ํ์๋ ๊ฒฐ๋ก ์ด ๋์๋ค.
๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ด ๋ก๋ด์ ๋ง๋ค์์ผ๋ฉฐ, ๋ฌผ๊ฑด(์์)๋ฅผ ๋น๊ธฐ๋ ์ํฉ์ ์๋ ์ฌ์ง์ฒ๋ผ ๋ง๋ค์ด์ ์คํ์ ์งํํ๋ค.
๋ํ, ์ ์๋ค์ ์์ง ๋ฐ๋์ ์ค๋ค๋ ๊ฒ์ ์๋ ์ํฉ์์ ์ด๋ฅผ ๋ก๋ด์ ์ด๋ป๊ฒ ์ ์ฉํ๋ฉด ์ข์์ง์ ๋ํด์ ์ด์ผ๊ธฐํด๋ณธ ๊ฒฐ๊ณผ ์ฝ๋์์์ ๋ชฉํ๊ฐ์ ๋ฐ๊พธ์๋ ๊ฒฐ๋ก ์ ๊ฐ์ง๊ณ ๋ฐ๋์ ์ฃผ๊ณ ์ ํ์์ผ๋ฉฐ ์ด๋ ์๋ ์ฌ์ง์ฒ๋ผ ์์๋ฅผ ๋์ด์ค๋ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์๋ค.
๋ฐ๋์ ์ฃผ๊ธฐ ์์ํ ์ฝ๋
// PID ๋ฐ ๋ณ์ ์ค์
// ================================================================
// === Rebound ===
// ================================================================
void Rebound(double theta_0, double theta_b, unsigned long time_start, unsigned long time_b, unsigned long T)
// theta_0๋ ๊ธฐ๋ณธ ์ธํ
๊ฐ๋, theta_b๋ ๋ฐ์ด๋ ๋ ๊ฐ๋, time_start๋ ๋ฐ๋ ์์ ํ์ด๋ฐ, time_b๋ ๋ฐ์ด๋ ๋ ๊ฐ๋์ ์ ์ง ์๊ฐ, T์ ์ฃผ๊ธฐ
{
timer = millis();
setpoint = theta_0; // degree(90) = 0, degree(60) = -30
if(timer >= time_start && timer <= time_start + time_b)
{
setpoint = theta_b;
}
if(timer >= T)
{
timer0_millis=0;
}
}
// ================================================================
// === Setup ===
// ================================================================
void setup(){
i2cSetup();
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
MPU6050_connect();
// ๋ก๋ด์ด ์๋ ์ค 13๋ฒ LED๋ฅผ ๊น๋นก๊ฑฐ๋ฆฌ๊ธฐ ์ํด OUTPUT์ผ๋ก ์ด๊ธฐํํฉ๋๋ค
pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// === Loop ===
// ================================================================
void loop()
{
Rebound(-40, -60, 750, 1000, 2500);
PID_update_and_motor_control();
etc_need_setup();
check_imu_working();
Serial.println(timer);
Serial.println(",");
Serial.println(setpoint);
}
์ ์ฒด ์ฝ๋
#include <I2Cdev.h>
// arduino ==> ์
ํ๋ฐธ๋ฐ์ฑ๋ก๋ด์ ๋ง๋ค์ด ์คํํด๋ณธ ์ฝ๋
//------------------------------------------------------------
// PID ์ ์ด, ๋ชจํฐ ์ ์ด, MPU6050์ผ์ ๊ฐ์ ๋ฐ๊ธฐ ์ํ ์ ์ธ๋ฌธ
#include <PID_v1.h>
#include <LMotorController.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
//MPU ๊ฐ์ฒด๋ฅผ ์ ์ธํฉ๋๋ค
MPU6050 mpu;
//------------------------------------------------------------
#define OUTPUT_READABLE_YAWPITCHROLL // Yaw, Pitch, Roll ๊ฐ์ ์ป๊ธฐ ์ํด ์ ์ธํฉ๋๋ค
#define INTERRUPT_PIN 2 // MPU6050 ์ผ์์ INT ํ์ด ๊ฝํ์๋ ๋ฒํธ๋ฅผ ์ค์ ํฉ๋๋ค. ๋ณดํต 2๋ฒ
#define LED_PIN 13 // Arudino Uno์ 13๋ฒํ LED๋ฅผ ๋์ ์ค์ ๋ฐ์ง๊ฑฐ๋ฆฌ๊ฒ ํ๋ ค๊ณ ์ ์ธํฉ๋๋ค
unsigned long timer; // ์๊ฐ ์ ์
extern volatile unsigned long timer0_millis;
// ================================================================
// === i2c SETUP Items ===
// ================================================================
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
void i2cSetup()
{
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
}
// ================================================================
// === MPU DMP SETUP ===
// ================================================================
#define OUTPUT_TEAPOT 1 // Processing์ ํตํด MPU6050 ์ผ์๋ฅผ Visualize ํ๊ณ ์ถ์ ๊ฒฝ์ฐ 1, ์๋๋ฉด 0์ผ๋ก ์ ์ธํฉ๋๋ค
//------------------------------------------------------------
// MPU control/status vars
bool blinkState = false; // LED๋ฅผ ๋ฐ์ง๊ฑฐ๋ฆฌ๊ฒ ํ๊ธฐ ์ํ ๋ณ์
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
//------------------------------------------------------------
// MPU6050 ์ผ์๋ฅผ ํตํด ์ฟผํฐ๋์ธ๊ณผ ์ค์ผ๋ฌ๊ฐ, Yaw, Pitch, Roll ๊ฐ์ ์ป๊ธฐ ์ํด ์ ์ธํฉ๋๋ค
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements
VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements
VectorFloat gravity; // [x, y, z] gravity vector
float euler[3]; // [psi, theta, phi] Euler angle container
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
// ================================================================
// === PID Setup ===
// ================================================================
double originalSetpoint;
double setpoint = originalSetpoint;
double movingAngleOffset = 0.3;
double fKp=50, fKi=200, fKd=0.8; //front Kpid 50 > 75
double bKp=32, bKi=100, bKd=0.6; //back Kpid 32 > 20
/*
1. ๋จผ์ Kp๋ฅผ ์กฐ์ ํฉ๋๋ค.
Kp๊ฐ์ด ๋๋ฌด ์์ผ๋ฉด ๋ก๋ด์ด ์ฝ๊ฒ ๋์ด์ง๋ฉฐ
Kp๊ฐ์ด ๋๋ฌด ํฌ๋ฉด ๋ก๋ด์ด ์๋ค๋ก ์ฌํ๊ฒ ํ๋ค๋ฆฌ๊ฒ ๋ฉ๋๋ค.
๋ก๋ด์ด ์๋ค๋ก ์กฐ๊ธ์ฉ ํ๋ค๋ฆฌ๋ ์ํ๊ฐ ์ต์ ์ ์ํ์
๋๋ค.
2. Kp๊ฐ ์ค์ ๋๋ฉด ๋ค์์ Kd๋ฅผ ์กฐ์ ํฉ๋๋ค.
์ต์ ์ Kd๊ฐ์ ๋ก๋ด์ด ์์ ์ ์ ์งํ๋ ๋์ ์ง๋์ ๊ฐ์์ํค๋ฉฐ
์์ผ๋ก ๋ฐ์ด๋ ๋ก๋ด์ด ๋ฐ๋ก ๋ณต๊ท๋๊ฒ ํฉ๋๋ค.
3. ๋ง์ง๋ง์ผ๋ก Ki๋ฅผ ์กฐ์ ํฉ๋๋ค.
Kp์ Kd๊ฐ ์ค์ ๋๋๋ผ๋ ์์ ๋ ์ํ๋ก ๋๋ฌํ๋ ๋์ ์ง๋์ ํ๊ฒ ๋ฉ๋๋ค.
์ต์ ์ Ki๊ฐ์ ๋ก๋ด์ด ์์ ๋๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ๋จ์ถ์ํฌ ์ ์์ต๋๋ค.
*/
// PID ์ ์ด์ฉ input, output ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค
double input, output;
// PID๊ฐ์ ์ค์ ํด์ค๋ค
PID pid(&input, &output, &setpoint, fKp, fKi, fKd, DIRECT);
void PID_RL()
{
double gap = input - setpoint; // Pitch ๊ฐ์ back์ผ๋ก ๊ฐ ์๋ก ๊ฐ์ด ์ปค์ง๋ค.
// ๋์ฐ๋ฉด gap์ ์์, ์ผ์ด์๋ฉด gap์ ์์์ ๊ฐ์ ์ง๋๊ฒ ๋จ.
if(setpoint >= -30)
{
pid.SetTunings(bKp, bKi, bKd);
}
else if(setpoint < -30)
{
if(gap <= 0) // ๋ค๋ก ๋์
{
pid.SetTunings(bKp, bKi, bKd);
}
else if(gap > 0) // ์์ผ๋ก ๊ฐ
{
pid.SetTunings(fKp, fKi, fKd);
}
}
}
// ================================================================
// === Motor Setup ===
// ================================================================
#define MIN_ABS_SPEED 30 // ๋ชจํฐ์ ์ต์ ์๋๋ฅผ ์ค์ ํฉ๋๋ค. 0 ~ 255 ๊ฐ ์ค ์ ํ
// ๋ชจํฐ ์ ์ด์ฉ ๋ณ์ ์ ์ธ
// EnA, EnB๋ ์๋์ ์ด์ฉ(pwm), IN1,2,3,4๋ ๋ฐฉํฅ์ ์ด์ฉ ํ์
๋๋ค
int ENA = 10;
int IN1 = 6;
int IN2 = 12;
int IN3 = 9;
int IN4 = 8;
int ENB = 11;
// motorController ๊ฐ์ฒด ์์ฑ, ๋งจ ๋ ํ๋ผ๋ฏธํฐ 1,1์ ๊ฐ๊ฐ ์ข์ธก, ์ฐ์ธก๋ชจํฐ์ ์ต๋์๋(%) ์
๋๋ค.
LMotorController motorController(ENA, IN2, IN1, ENB, IN4, IN3, 1, 1);
// ================================================================
// === Visualize ===
// ================================================================
//------------------------------------------------------------
// Processing์ผ๋ก MPU6050 ์ผ์๋ฅผ Visualize ํ๊ธฐ ์ํ ๋ณ์
// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };
void MPU6050_connect()
{
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
// devStatus ๊ฐ์ด 0 ์ด๋ฉด ์ ์์๋, 0์ด ์๋๋ฉด ์ค์๋์
๋๋ค
// make sure it worked (returns 0 if so)
if (devStatus == 0){
// turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
// MPU6050 ์ผ์๊ฐ ์ ์ญ์๋ํ๋ฉด PID ์ ์ด์ฉ ์ฝ๋๋ฅผ ์ด๊ธฐํํฉ๋๋ค
pid.SetMode(AUTOMATIC);
pid.SetSampleTime(10);
pid.SetOutputLimits(-255, 255);
}
else{ // MPU6050 ์ผ์๊ฐ ์ค์๋ํ ๊ฒฝ์ฐ
// ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}
// ================================================================
// === INTERRUPT DETECTION ROUTINE ===
// ================================================================
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
mpuInterrupt = true;
}
// ================================================================
// === MPU6050 ===
// ================================================================
void PID_update_and_motor_control()
{
// if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize){
//no mpu data - performing PID calculations and output to motors
pid.Compute(); // ๋ฃจํ๋ฅผ ๋๋ฉด์ pid ๊ฐ์ ์
๋ฐ์ดํธํฉ๋๋ค
motorController.move(output, MIN_ABS_SPEED); // pid ์ฐ์ฐ์ผ๋ก ๋์จ output ๊ฐ์ motorController๋ก ์ ์กํฉ๋๋ค. (๋ชจํฐ์ ์ด)
}
}
void etc_need_setup()
{
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
}
void Get_ypr_input()
{
// wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
#ifdef OUTPUT_READABLE_YAWPITCHROLL // ์ผ์๋ฅผ ํตํด ๊ตฌํ Yaw, Pitch, Roll ๊ฐ์ Serial Monitor์ ํ์ํฉ๋๋ค
Serial.print("ypr\t");
Serial.print(ypr[0] * 180/M_PI);
Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print("\t");
Serial.println(ypr[2] * 180/M_PI);
#endif
// PID ์ ์ด๋ฅผ ํ๊ธฐ ์ํด input ๋ณ์์ Pitch ๊ฐ์ ๋ฃ์ต๋๋ค
input = ypr[1] * 180/M_PI;
}
void check_imu_working()
{
// MPU6050 ์ผ์๊ฐ ์ ์์๋ํ๋ ๊ฒฝ์ฐ์๋ง PID์ ์ด๋ฅผ ํด์ผํ๋ฏ๋ก ์๋์ ๊ฐ์ด if-else๋ฌธ์ ์์ฑํฉ๋๋ค
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024)
{
// reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
}
// MPU6050 ์ผ์๊ฐ ์ ์์๋ํ๋ ๊ฒฝ์ฐ
else if (mpuIntStatus & 0x02)
{
Get_ypr_input();
PID_RL();
MPU6050_visualize();
}
}
void MPU6050_visualize()
{
#ifdef OUTPUT_TEAPOT // Processing์ผ๋ก MPU6050์ผ์์ ์์ง์์ Visualize ํ๊ธฐ ์ํ ์ฝ๋
// display quaternion values in InvenSense Teapot demo format:
teapotPacket[2] = fifoBuffer[0];
teapotPacket[3] = fifoBuffer[1];
teapotPacket[4] = fifoBuffer[4];
teapotPacket[5] = fifoBuffer[5];
teapotPacket[6] = fifoBuffer[8];
teapotPacket[7] = fifoBuffer[9];
teapotPacket[8] = fifoBuffer[12];
teapotPacket[9] = fifoBuffer[13];
Serial.write(teapotPacket, 14);
teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
#endif
}
// ================================================================
// === Rebound ===
// ================================================================
void Rebound(double theta_0, double theta_b, unsigned long time_start, unsigned long time_b, unsigned long T)
// theta_0๋ ๊ธฐ๋ณธ ์ธํ
๊ฐ๋, theta_b๋ ๋ฐ์ด๋ ๋ ๊ฐ๋, time_start๋ ๋ฐ๋ ์์ ํ์ด๋ฐ, time_b๋ ๋ฐ์ด๋ ๋ ๊ฐ๋์ ์ ์ง ์๊ฐ, T์ ์ฃผ๊ธฐ
{
timer = millis();
setpoint = theta_0; // degree(90) = 0, degree(60) = -30
if(timer >= time_start && timer <= time_start + time_b)
{
setpoint = theta_b;
}
if(timer >= T)
{
timer0_millis=0;
}
}
// ================================================================
// === Setup ===
// ================================================================
void setup(){
i2cSetup();
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
MPU6050_connect();
// ๋ก๋ด์ด ์๋ ์ค 13๋ฒ LED๋ฅผ ๊น๋นก๊ฑฐ๋ฆฌ๊ธฐ ์ํด OUTPUT์ผ๋ก ์ด๊ธฐํํฉ๋๋ค
pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// === Loop ===
// ================================================================
void loop()
{
Rebound(-40, -60, 750, 1000, 2500);
PID_update_and_motor_control();
etc_need_setup();
check_imu_working();
Serial.println(timer);
Serial.println(",");
Serial.println(setpoint);
}
์ดํ ์ด๋ฅผ ํตํด์ ์คํ์ ์งํํ์ผ๋ฉด ์ข์๊ฒ ์ง๋ง, ์์ฝ๊ฒ๋ ์ ์์ ํค๋ ๊ณผ์ ์์ ์ ์์ ๋ณด์ง ๋ชปํ๊ณ ํค๋ ์ํฉ์ด ๋ฐ์ํ์ฌ ์์์ ์ด์ด ๋จ๊ธด ์์ฒ์ ํจ๊ป ์ค์ค์ด 7ํธ๋ฅผ ํ๊ธฐํ๊ณ ๋ค์ 8ํธ๋ฅผ ์ค๊ณํ๋ฉด์ ์คํ์ ์งํํ๊ฒ ๋์๋ค.
https://github.com/MOSW626/Tug_of_War_Robot_Project_-2022-.git
GitHub - MOSW626/Tug_of_War_Robot_Project_-2022-
Contribute to MOSW626/Tug_of_War_Robot_Project_-2022- development by creating an account on GitHub.
github.com