gpt4 book ai didi

c - Arduino Drone项目,当输出为 "loaded"(甚至上限为gnd)时,输入 "steering"命令开始出现故障

转载 作者:行者123 更新时间:2023-11-30 17:00:20 25 4
gpt4 key购买 nike

Arduino无人机项目,每当输出“加载”时(ESC的“开路”信号输入引脚,甚至接地帽),输入“转向”命令开始出现故障(转到非常低的值<< 1000)。

电机速度是转向命令和 throttle 的函数。 (在这个只有一个电机的测试用例中,如下面的代码所示,unMotorSpeed = unThrottleIn +/- unSteeringIn)

当连接到示波器时,物理输入信号(来自接收器的转向和 throttle )非常好,我什至交换了输入引脚以确保接收器和arduino之间没有问题。问题似乎来自软件,但这没有意义,因为当没有附加“负载”时,输入和输出值都很好且干净。 (我将“负载”放在引号中,因为有时它本质上是一个开路 ->电子速度 Controller (ESC)的超高阻抗输入信号,我什至不接地来完成电路)。

有人可以检查一下代码并看看我是否遗漏了什么吗?

此时,一个稍微快速的解决方法就是不将这些新的故障值写入电机,并在新速度明显低于旧速度时保留旧速度值(并且这些值超过 50khz,所以显然一步的巨大跳跃有点疯狂)。

注意:在代码中,unMotorSpeed 的总输出从servoThrottle 引脚发出。只是我最终没有更改的原始命名...如果您阅读代码并看到所有变量,就很清楚了。

更新:奇怪的是,我只是在没有任何更改的情况下运行了我的设置,一切正常...我多次重新刷新arduino以确保这不是一些幸运的故障,并且它继续工作,一切都设置好了。然后我把 Remote 扔在地上,移动了面包板上的几根电线,在将设置重新组合在一起后,事情又回到了原来的样子。我不知道该怎么办!

// --> starting code found at: rcarduino.blogspot.com
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
with.html


#include <Servo.h>

// Assign your channel in pins
#define THROTTLE_IN_PIN 3
#define STEERING_IN_PIN 2


// Assign your channel out pins
#define THROTTLE_OUT_PIN 9
//#define STEERING_OUT_PIN 9


// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoThrottle;
//Servo servoSteering;


// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define THROTTLE_FLAG 1
#define STEERING_FLAG 2

// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unThrottleInShared;
volatile uint16_t unSteeringInShared;

// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulThrottleStart;
uint32_t ulSteeringStart;
//uint32_t ulAuxStart;

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

// attach servo objects, these will generate the correct
// pulses for driving Electronic speed controllers, servos or other devices
// designed to interface directly with RC Receivers
servoThrottle.attach(THROTTLE_OUT_PIN);

// using the PinChangeInt library, attach the interrupts
// used to read the channels
attachInterrupt(digitalPinToInterrupt(THROTTLE_IN_PIN), calcThrottle,CHANGE);
attachInterrupt(digitalPinToInterrupt(STEERING_IN_PIN), calcSteering,CHANGE);
}

void loop()
{
// create local variables to hold a local copies of the channel inputs
// these are declared static so that thier values will be retained
// between calls to loop.
static uint16_t unThrottleIn;
static uint16_t unSteeringIn;
static uint16_t difference;
static uint16_t unMotorSpeed; // variable that stores overall motor speed
static uint8_t bUpdateFlags; // local copy of update flags

// check shared update flags to see if any channels have a new signal
if(bUpdateFlagsShared)
{
noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

// take a local copy of which channels were updated in case we need to use this in the rest of loop
bUpdateFlags = bUpdateFlagsShared;

// in the current code, the shared values are always populated
// so we could copy them without testing the flags
// however in the future this could change, so lets
// only copy when the flags tell us we can.

if(bUpdateFlags & THROTTLE_FLAG)
{
unThrottleIn = unThrottleInShared;
}

if(bUpdateFlags & STEERING_FLAG)
{
unSteeringIn = unSteeringInShared;
}

// clear shared copy of updated flags as we have already taken the updates
// we still have a local copy if we need to use it in bUpdateFlags
bUpdateFlagsShared = 0;

interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
// as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
// service routines own these and could update them at any time. During the update, the
// shared copies may contain junk. Luckily we have our local copies to work with :-)
}

//Serial.println(unSteeringIn);

// do any processing from here onwards
// only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared
// variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by
// the interrupt routines and should not be used in loop

// the following code provides simple pass through
// this is a good initial test, the Arduino will pass through
// receiver input as if the Arduino is not there.
// This should be used to confirm the circuit and power
// before attempting any custom processing in a project.

// we are checking to see if the channel value has changed, this is indicated
// by the flags. For the simple pass through we don't really need this check,
// but for a more complex project where a new signal requires significant processing
// this allows us to only calculate new values when we have new inputs, rather than
// on every cycle.

///// if-else chain commented out to determine/prove problem with steering signal --> buggy!


if(unSteeringIn < 1400) // if steering joystick moved left
{
difference = 1400 - unSteeringIn;
if(unThrottleIn - difference >= 0)
unMotorSpeed = unThrottleIn - difference;
}
else if(unSteeringIn > 1550) //if steering joystick moved right (needs to be tweaked, but works for now)
{
difference = unSteeringIn - 1600;
if(unThrottleIn + difference < 2000)
unMotorSpeed = unThrottleIn + difference;
}
else
{
unMotorSpeed = unThrottleIn;
}

//Serial.println(unMotorSpeed);
//Serial.println(unSteeringIn);
//Serial.println(unThrottleIn);

if(bUpdateFlags)
{
//Serial.println(servoThrottle.readMicroseconds());
if(servoThrottle.readMicroseconds() != unMotorSpeed)
{
servoThrottle.writeMicroseconds(unMotorSpeed);
Serial.println(unMotorSpeed);
}
}

bUpdateFlags = 0;
}

// simple interrupt service routine
void calcThrottle()
{
// if the pin is high, its a rising edge of the signal pulse, so lets record its value
if(digitalRead(THROTTLE_IN_PIN) == HIGH)
{
ulThrottleStart = micros();
}
else
{
// else it must be a falling edge, so lets get the time and subtract the time of the rising edge
// this gives use the time between the rising and falling edges i.e. the pulse duration.
unThrottleInShared = (uint16_t)(micros() - ulThrottleStart); // pulse duration

// use set the throttle flag to indicate that a new throttle signal has been received
bUpdateFlagsShared |= THROTTLE_FLAG;
}
}

void calcSteering()
{
if(digitalRead(STEERING_IN_PIN) == HIGH)
{
ulSteeringStart = micros();
}
else
{
unSteeringInShared = (uint16_t)(micros() - ulSteeringStart); // pulse duration
bUpdateFlagsShared |= STEERING_FLAG;
}
}

最佳答案

您应该阅读 AttachInterrupt() 的文档- 在“关于中断服务例程”部分中,它提供了有关从中断调用时某些函数如何行为的信息。对于 micros() 它指出:

micros() works initially, but will start behaving erratically after 1-2 ms.

我认为这意味着 ISR 运行了超过 1 毫秒,而不是一般的 1 毫秒,因此可能不适用于这种情况,但您可能需要考虑如何在 ISR 中进行计时。这是 Arduino 的问题 - 糟糕的文档!

一个可能是原因的明确问题是 unSteeringInShared 是非原子的。它是 8 位硬件上的 16 位值,因此需要多个指令来读取和写入,并且该过程可能会被中断。因此,可以在 loop() 上下文中读取值的一个字节,然后在读取第二个字节之前通过中断上下文更改两个字节,这样您就可以得到两个字节的两半不同的值。

要解决此问题,您可以在读取时禁用中断:

noInterrupts() ;
unSteeringIn = unSteeringInShared ;
interrupts() ;

或者您可以自旋锁定读取:

do
{
unSteeringIn = unSteeringInShared ;

} while( unSteeringIn != unSteeringInShared ) ;

您也应该对 unThrottleInShared 执行相同的操作,尽管尚不清楚为什么您没有看到任何问题 - 这可能不是您当前正在观察的问题,但绝对是任何问题案例。

或者,如果 8 位分辨率足够,您可以将输入编码为原子 8 位值,如下所示:

uint8_t unSteeringInShared ;


...


int32_t timeus = micros() - ulSteeringStart - 1000 ;
if( timeus < 0 )
{
unSteeringInShared = 0 ;
}
else if( timeus > 1000 )
{
unSteeringInShared = 255;
}
else
{
unSteeringInShared = (uint8_t)(time * 255 / 1000) ;
}

当然,将比例从 1000 到 2000 更改为 0 到 255 需要更改其余代码。例如,将 0 到 255 范围内的值 x 转换为伺服脉冲宽度:

 pulsew = (x * 1000 / 256) + 1000 ;

关于c - Arduino Drone项目,当输出为 "loaded"(甚至上限为gnd)时,输入 "steering"命令开始出现故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37670899/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com