Inspire-подобная рама своими руками с нуля

CZC

Я просто проанализировал блок-схему.

Slevin757
CZC:

А автоматическом режиме нужно будет всегда летать выше пороговой высоты, а то получится - “лучи вверх”-“лучи вниз”…

Да, по логике так оно и будет. Но если вариант с новым винтом (шаг 12 мм) сработает, то опускание шасси будет происходить за секунды и я смогу выставить пороговую высоту небольшой, около 1 - 1.5 м. На такой высоте не планирую много летать, а в исключительных случаях можно будет перейти в ручной режим.

Если же на старом винте придется остаться, то метра 2.5. придется поставить. Но опять же в отдельных случаях ручным попользуюсь.

На сколько я понимаю, чтобы вывести на пульт информацию надо будет одним каналом пожертвовать. Жалко) Хотя за идею спасибо, возможно в будущем к ней добавятся еще какие-то показания для передачи.

skm:

Кстати когда то брал для колхоза с автоподьемом ног такую вот штучку

Любопытная штуковина. Разброс цен на них какой-то странный.

Накрапал скетч для ардуины:

#include <Servo.h>

Servo myservo;

int button = 6; // кнопка перевода в транспортное положение
int pin = 2; // вход с приемника
unsigned long duration; // длинна сигнала

unsigned int dist = 1200; // пороговое расстояние до земли

unsigned int HighLen = 0;
unsigned int LowLen = 0;
unsigned int Len_mm = 0;

void setup()
{
myservo.attach(3);

pinMode(5, OUTPUT);
pinMode(button, INPUT);
pinMode(pin, INPUT);
digitalWrite(5, HIGH);
Serial.begin(9600);
}

void loop()

{

if (digitalRead(button) == HIGH) // если кнопка транспортного положения нажата
myservo.write(90); // лучи в среднем положении

duration = pulseIn(pin, HIGH); // считывается длинна сигнала

if (duration > 1800) // если тумблер в нижнем положении
myservo.write(0); // лучи опускаются вниз

if ((duration > 1200) & (duration < 1800)) // если тумблер посередине
myservo.write(180); // лучи поднимаются вверх

if (duration <= 1000) // если тумблер в верхнем положении
// замеряется расстояние до земли:
{
Serial.flush();
Serial.write(0x55);
delay(10);
if (Serial.available() >= 2)
{
HighLen = Serial.read();
LowLen = Serial.read();
Len_mm = HighLen * 256 + LowLen;
Serial.print(Len_mm, DEC);
Serial.println(“mm”);
}

if (Len_mm <= dist) // если расстояние ниже, равно пороговому
myservo.write(0); // лучи лучи опускаются вниз

if (Len_mm > dist) // если расстояние выше порогового
myservo.write(180); // лучи поднимаются вверх
}

}

На счет его работоспособности пока утвердительного мнения нет. Вроди бы все работает (и кнопка и управление с пульта и автомат). Но в транспортном положении серва периодически подергивается, а должна тико стоять.
Ну и в одну сторону крутится ровно, а в другую с дерганьями (то ровно, то дергается, то встанет, то опять раскрутится). Хотя вне схемы крутится как надо.
Затрудняюсь предполагать в чем может быть дело. Для меня ардуиновская тематика, это почти как шаманизм. Заморочился с ней для удобства, но если не получится достичь стабильной работы, то опять откажусь.

rc468
Slevin757:

myservo.write(0); // лучи опускаются вниз

Slevin757:

myservo.write(90); // лучи в среднем положении

Slevin757:

myservo.write(180); // лучи поднимаются вверх

Нужно ли эти значения постоянно записывать в серву в цикле или достаточно записать один раз, чтобы серва приняла нужное положение и удерживала его?

Slevin757
rc468:

Нужно ли эти значения постоянно записывать в серву в цикле или достаточно записать один раз, чтобы серва приняла нужное положение и удерживала его?

Мои познания в программировании ограничиваются универским курсом и гуглом, но на сколько я понимаю, если записать что-то окончательно, то потом программа перестанет обновлять переменную и схема перестанет реагировать на новые команды. Такой вариант как прямое управление с пульта тут не сработает - все тело программы это цикл.

ssilk

Хе-хе…) Вот Вы неугомонный…) То у Вас автопилот интеллектуал, хоть в “ЧтоГдеКогда” играй, теперь в серву что то можно записать…)
Серва просто поворачивается на угол, соответствующий ширине сервоимпулься на выходе ардуины…) Ширина 1000 микросекунд равна углу 0 градусов, ширина 1500 - 90 градусов, ширина 2000=180 градусов. До тех пор пока на выходе ардуины эта ширина не изменится, мотор сервы не сдвинется с места.
В данном случае, команда write(90) заставляет МК выставить на заранее определенном пине импульсы длительностью 1500 и частотой 50 герц. И эта хрень будет там присутствовать до тех пор, пока не поступит команда с другой длительностью…

Slevin757
ssilk:

теперь в серву что то можно записать

Я имел ввиду перезапись и обновление переменных на ардуине в соответствии с управляющими командами.

Считывал ширину входящего сигнала ардуиной, получилось что значения немного плавают, поэтому ставил граничные условия вроде “if ((duration > 1200) & (duration < 1800))” вместо четчих чисел. Чтобы сигнал с приемника точно попал в пределы.

rc468
Slevin757:

Я имел ввиду перезапись и обновление переменных на ардуине в соответствии с управляющими командами.

Попробуйте не писать в цикле одни и те же значения.
А сделать следующим образом:

до цикла:
int servo_mode = -1;

Slevin757:

if (digitalRead(button) == HIGH) // если кнопка транспортного положения нажата myservo.write(90); // лучи в среднем положении

меняем на:
if (digitalRead(button) == HIGH) { // если кнопка транспортного положения нажата
if (servo_mode != 90) {

myservo.write(90); // лучи в среднем положении
servo_mode = 90;
}
}

и аналогично для других режимов.
в результате значения будут писаться только один раз при смене режима.
возможно, это повлияет на подергивания сервы.

Slevin757
rc468:

Попробуйте не писать в цикле одни и те же значения.
А сделать следующим образом:

О! Круто! не знал про такой прием. Испробую!
Стесняюсь спросить - а что означает восклицательный знак после имени переменной?) “servo_mode != 90”

rc468
Slevin757:

а что означает восклицательный знак

== это равно
!= это не равно

Slevin757
rc468:

== это равно
!= это не равно

А, блин, точно, он же к логическому оператору относится, а не к имени))… программист из меня еще тот

rc468

Да, и еще.
Допустим, у вас нажата кнопка.
Тогда срабатывает
myservo.write(90); // лучи в среднем положении

Но вслед за этим проверяется длина сигнала и может сработать что-то еще.
Т.е. если нажата кнопка, то в цикле у вас получится так, что сначала всегда пишется 90, а затем пишется что-то еще в зависимости от длины сигнала.

Slevin757
rc468:

Но вслед за этим проверяется длина сигнала и может сработать что-то еще.

А может тогда дописать еще одно условие после проверки кнопки?

if (digitalRead(button) != HIGH)
{
… и пошло дальше

rc468

Вот такой оптимизированный цикл:
int last_servo_mode = -1;
int servo_mode = -1;

void loop() {
if (digitalRead(button) == HIGH) {
// если кнопка транспортного положения нажата
servo_mode = 90; // лучи в среднем положении
}

duration = pulseIn(pin, HIGH); // считывается длинна сигнала

if (duration > 1800) {
// если тумблер в нижнем положении
servo_mode = 0; // лучи опускаются вниз
} else if (duration > 1200) {
// если тумблер посередине
servo_mode = 180; // лучи поднимаются вверх
} else {
// если тумблер в верхнем положении
// замеряется расстояние до земли:
Serial.flush();
Serial.write(0x55);
delay(10);
if (Serial.available() >= 2) {
HighLen = Serial.read();
LowLen = Serial.read();
Len_mm = HighLen << 8 + LowLen;
Serial.print(Len_mm, DEC);
Serial.println(“mm”);
}

if (Len_mm <= dist) {
// если расстояние ниже, равно пороговому
servo_mode = 0; // лучи лучи опускаются вниз
} else {
// если расстояние выше порогового
servo_mode = 180; // лучи поднимаются вверх
}
}

if (servo_mode != last_servo_mode) {
myservo.write(servo_mode);
last_servo_mode = servo_mode;
}
}

Slevin757:

А может тогда дописать еще одно условие после проверки кнопки?

А у вас кнопка или переключатель имеет приоритет? Если кнопка, то после обработки кнопки надо пропустить остальную часть (поместить ее в else), если переключатель, то оставить как есть. (Но писать все равно один раз за цикл, как я запостил выше).

Slevin757
rc468:

А у вас кнопка или переключатель имеет приоритет?

Кнопка в приоритете. Так как нажимается только при подготовке к полету и при завершении.

я тут пока испробовал код по первой рекомендации - в транспортном положении стоит ровно, не гудит и не дергается. А в остальных режимах дергает.
Сейчас разберусь в коде второй рекомендации. Благодарю, что потратили время на написание.

rc468

Тогда обработку кнопки достаточно перенести вниз после обработки переключателя и до записи окончательного значения в серву. Она будет выполняться последней и переустановит любое значение, которое было установлено до этого.

Slevin757

Вот так?

… if (Len_mm <= dist) {

servo_mode = 0;
}
else
{
servo_mode = 180;
}
}

if (digitalRead(button) == HIGH) {
// если кнопка транспортного положения нажата
myservo.write(90); // лучи в среднем положении
servo_mode = 90;
}

if (servo_mode != last_servo_mode) {
myservo.write(servo_mode);

last_servo_mode = servo_mode;
}

}

На кнопку стал правильно реагировать, но вращение мотора испортилось. После первой рекомендации он в АВТО плохо себя вел, но зато в ручном крутил отлично. А сейчас в обоих режимах в одну сторону крутит, а в другую дергается.

rc468
Slevin757:

Вот так?

Да.

Slevin757:

вращение мотора испортилось

Трудно понять на расстоянии. Буду думать.

Slevin757

Тааакс… Подправил граничные условия в одном месте, вернул старый скетч эхолота и стер фрагмент про кнопку - пошло на пользу. Мотор ровно крутит в обе стороны и в обоих режимах. На сонар реагирует корректно.

Теперь надо фрагмент про кнопку правильно вставить.

Нее, если в то место вставляю, то картина портится.
Попробую в начало

Не, чет не то… Без кнопки все прям прекрасно работает. А фрагмент с кнопкой все резко портит. Андрей, кажется вы писали про оператор Continue, но потом редактировали. Он может помочь при размещении кода кнопки в начале цикла?

Текущее работоспособное состояние цикла без кнопки:

void loop()

{

duration = pulseIn(pin, HIGH);

if (duration > 1800)
{
servo_mode = 0;
} else if ((duration > 1300)&(duration <= 1700))
{
servo_mode = 180;
}
else
{
Serial.flush();
Serial.write(0x55);
delay(10);
if (Serial.available() >= 2)
{
HighLen = Serial.read();
LowLen = Serial.read();
Len_mm = HighLen * 256 + LowLen;
Serial.print(Len_mm, DEC);
Serial.println(“mm”);
}
if (Len_mm <= dist)
{
servo_mode = 0;
}
else
{
servo_mode = 180;
}
}
if (servo_mode != last_servo_mode)
{
myservo.write(servo_mode);
last_servo_mode = servo_mode;
}
}

rc468
Slevin757:

писали про оператор Continue, но потом редактировали

continue это переход на следующий шаг цикла с текущего места, его использовать нельзя, потому что это не цикл for или while, поэтому я и отредактировал. Он не может помочь.
Надо понять, почему кнопка влияет так.

А вы можете наоборот все убрать и оставить только кнопку?

Оставить только кнопку и дополнить реакцию на отжатие:
if (digitalRead(button) == HIGH) {
// если кнопка транспортного положения нажата
servo_mode = 90; // лучи в среднем положении
} else {
servo_mode = 0; // в любом другом положении
}

Slevin757
rc468:

А вы можете наоборот все убрать и оставить только кнопку?

Сама по себе стопорит она нормально. Но своим присутствием этот фрагмент кода влияет на остальной цикл и серва начинает неровно крутиться, стопориться, дергалься

if (digitalRead(button) == HIGH)
{myservo.write(90);
servo_mode = 90;}

Мне кажется хорошо бы воткнуть его вначале, чтобы программа проверила его, и если кнопка включена, то оставшаяся часть кода была бы проигнорирована за ненадобностью.
А если кнопка не нажата, то цикл выполнялся бы полностью.

rc468:

А вы можете наоборот все убрать и оставить только кнопку?

сейчас попробую…

rc468
Slevin757:

Но своим присутствием этот фрагмент кода влияет на остальной цикл и серва начинает неровно крутиться, стопориться, дергалься if (digitalRead(button) == HIGH) {myservo.write(90); servo_mode = 90;}

Погодите, именно этот фрагмент?
С ним будет дергаться, потому что в нем запись происходит. В нем должно быть только servo_mode = 90 и больше ничего. Запись производится после всех проверок один раз в конце цикла.