Официальный сайт компании Arduino по адресу arduino.cc
Запоминание позиий серво
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Ср, 23/05/2012 - 16:10
В программировании чайник, но стало интересно возиться с ардуиной. Возникла проблемка.
Есть серва, положение которой определяется потенциометром. С помощью кнопки заношу в память положение сервы- перевожу потенциометром в другое положение -нажимаю кнопку загрузки памяти. Серва поворачивается в сохранённое положение и сразу возвращается в положение, определяемое потенциометром на данный момент. Как отключить чтение данных с аналогово входа или есть другие решения? Надеюсь на помощ специалистов.
После нажатия на кнопку загрузки из памяти серва остается в сохраненном положении пока значение на аналоговом входе не изменится.
Код свой выложите. Вставка программного кода в тему/комментарий
Вы сами практически ответили на свой вопрос.
"отключить чтение данных с аналогово входа"
Вам нужно завести еще одну какую-то переменную (глобальную, объявленную вне loop), например inputMode, в которой вы будете хранить нужно сейчас читать состояние потенциометра или нет.
обернуть строчки которые вам нужно "отключить" (04-07) в
На у дальше, там где вы работаете с нопками, выставляете inputMode=0, если вам нужно игнорить потенциометр, и inputMode=1, если нужно следить за ним.
Не знаю толком вашей задачи, но, возможно, тут, с точки зрения пользователя, будет более удобней использовать не потенциометр, а энкодер. Типа "кнопкой" из памяти "грубо" установили позицию сервы, потом энкодером "уточнили" и опять кнопой "запомнили" новую позицию.
Хотя с энкодера, конечно, читать данные несколько сложней чем с потенциометра. Зато у него нет такого понятия как "собственная позиция". Он может говорить только "меня повернули на 15 градусов по часовой, или 30 градусов против-часовой", и крутится он без ограничителей.
>Что я делаю не правильно?
Предполагаете наличие телепатов на форуме.
Вы что Ленин в революционные годы, что-бы бумагу экономить? Почему не дать скетч целиком?
Да и форумную переписку зачем комментариями делать? Почему описание ситуации нельзя просто после/до скетча написать?
Да и переменную inputMode вы как-то загадисто объявили. Посмотретие в справочнике (в шапке сайта , ссылка "Программирование"), как переменные объявляются.
Судя по скейтчу у вас кнопки только при включении работают.
И зачем остальные кнопки?
Ну теперь осталось только кнопки читать не один раз, при старте скетча, а в каждом Loop.
Перенести строчки 30-33 в начало loop (вставить в 37-седьмую).
Ну и в строках 64,75 не сравнивать inputMode с нулем и единицей, а менять его значение. Посмотрите как я написал "выставляете ... если вам нужно". И как вы сделали. Найдите отличие (всего один символ ;)
Так же, возможно, при инициализации inputMode, наверное стоит ему указать начальное значение 1, что-бы при старте скетча сразу начинал работать потенциометр (так как сейчас - потенциометр заработает только после нажатия четвертной кнопки.)
кнопка 1-запись положения в память
кнопка 2-загрузка данных из памяти и перевод сервы в сохранённое положение
кнопка 3-очистка памяти
кнопка 4-включение чтения данных с потенциометра и перевод сервы из сохранённого положения в положение определяемое потенциометром
leshak, Спасибо за помощ. Сделал как вы посоветовали - заработало. Правда серва всё время уходит в крайнее положение. Или что-то с записью в память или очисткой памяти. Попробую покопаться может получиться. Ну и дребезг кнопок вставить в скетч.
> Или что-то с записью в память или очисткой памяти.
Конечно....
Вы же читаете в потенциометр в val3, а в память сохраняете val4, которую установили один раз. при инициализации скетча. Причем, извините, способом из серии "почесать правое ухо левой ногой".
Я первый раз в программировании.
Попробовал вычисление val4 перенести в loop для кнопки 1 -то же самое. Застрял. А ещё надо добиться плавного перевода сервы из одного положения в другое...
> Я первый раз в программировании.
Ну и что? Я же не над вами, как личностью, иронизировал, а над способом чтения. Первый раз вижу digitalRead в инициализации переменных.
А "сам себе злобный буратино", так это постоянно бывают и те кто сто тысячный раз в программировании. Причем все :)
Сам процесс програмления, это постоянный цикл "плавных приближений". Итерации "накидал, выяснил почему не работает, поправил". Так что нечего смущатся. Это совершенно естественный процесс написания кода. "Сразу с листа правильно" пишутся только очень примитивные вещи, в несколько строк, и то не всегда :)
А вот навыки выяснения "почему не работает как хотел" - это нужно развивать. Без этого - никак.
>Попробовал вычисление val4 перенести в loop для кнопки 1 -то же самое. Застрял
Ага. Как пробовал и почему застрял опять нужно телепатить? "val4=analogRead(potpin) / 4" в 48-мую строку, не?
Нужно привыкнуть все время представлять себе контроллером, который должен выполнить этот скетч. Представте себе что переменные и память это листики вашего блокнота (именованные), что это вам нужно вписывать в них значения, сравнивать, крутить серву исходя из записей. Тогда легче будет отлавливать ситуации типа "нужно повернуть серву в соотсвесвие с записями на странице 'val4', а там ничего не записанно :( "
Натыкайте, в критических точках, всякие Serial.print("val3:");Serial.println(val3); и смотрите в serial мониторе, чему там равны ваши переменные, смотрите насколько соотсвествует их содержимое вашим предположениям. Поизучайте работу своего скетча.
> А ещё надо добиться плавного перевода сервы из одного положения в другое
А в чем проявляется "неплавность" - снова догадайся. Слишком быстро поворачивается? Нет промежуточных значений? Неплавность при кручении реостата или при чтении-записи из памяти?
Кстати в чем магических смысл делать чтение/запись каждый раз по новому аддресу? Ну то есть "зачем" - догадатся-то можно... экономия циклов перезаписи :), только вот толку? При перезагрузке контроллера, вы же не знаете по какому адресу была последняя запись, первое чтение всегда произойдет по адресу - 0.
Я бы, наверное делал так (хотя IMHO это тоже коряво, но ничего красивше сходу не приходит в голову):
да и еще. при очистеке, перед тем как писать 0 в ячейку, можно делать чтение из нее. Если там уже 0, но незачем лишний раз делать write, нужно поберечь ресурс памяти.
Через serial монитор видно, что загружается вроде как и ожидалось. А вот с чтением ерунда какая то. Попробую разобраться.
По моторам- реостат работает хорошо. Тут проблем нет. Нужно понять как регулировать скорость перехода сервы в положение из памяти и обратно. Здесь движение без потенциометра. Пробовал через delay - не получается
Я бы делал так:
Я бы делал так:
Мне просто неудобно просить за меня делать программу, но , как я уже писал, это моя первая проба в программировании. я просто не знаю где об этом можно почитать и посмотреть примеры. если можно то ссылку сбросьте. как такой метод вообще то правильно называется
Никак этот метод не называется :) Название "придумал что хочу, и записал это програмными конструкциями".
Что вам важнее, "получить результат" или "самому дойти" (обучение)?
В зависимости от этого, я могу либо дать пример кода, либо "наводящими заданиями" вытягиваеть его из вас :)
Первое мне, конечно проще, второе IMHO полезней (и вам приятней, в финале. сам разобрался и написал).
Если учится, то для начала нужно прочитать http://arduino.ru/Reference/For и http://arduino.ru/Reference/While
P.S. По хорошему вообще нужно прочитать все из раздела http://arduino.ru/Reference . Хотя-бы бегло. Что-бы хоть примерно представлять из каких "програмнных кубиков" можно собирать свои скетчи. Пусть не все будет понятно с первого захода, но что-то в памяти отложится. И когда понадобится всплывет "где-то я это читал". И уж тогда внимательно, еще раз, прочитывается кусок который потребовался.
Первое мне, конечно проще, второе IMHO полезней (и вам приятней, в финале. сам разобрался и написал).
конечно если дадут конкретный пример или полное решение проблемы это хорошо и спасибо, но немного хочется и пониматьчто делается и зачем. учусь по немногу
Не ну вы все-таки решите, что вам нужней. Сразу отгадка или "горячо/холоднее"? одновременно это невозможно. Оно же взаимоисключает друг-друга ;)
ПЕРВОЕ! а теорией позанимаюсь потом.
Вообщем примерно так:
И везде в скетче, вместо myServo.write, дальше используем setServo(...) если нужно быстро установить значение сервы и setServoSlow() если медленно.
SERVO_STEP, и STEP_DELAY - подбираем на глаз. Что-бы была медленность, но не было видимой "дергнанности"
А работа сервы с реостатом остаётся как была или тоже надо изменять код
Я жне написал "везде в скетче". Значит там где реостат, myServo.write меняем на setServo()
С очисткой памяти и загрузкой из памяти позиции сервы вроде решил проблему- указал один addres=0 и всё заработало. так можно оставить? До того как было в строчках 57-62 (брал пример из библиотеки EEPROM) при загрузке данных из памяти выдавал 0.
>До того как было в строчках 57-62
Наверное имелось ввиду 59-62.... иначе бред выходит.
Ну откуда я знаю можно или нет.... это же ваш скетч :)
Ну, предположим, я скажу "нельзя"... что дальше делать будете? А вас есть выбор "послушатся меня и иметь не работающий скетч" и проигнорировать меня (зачем тогда спрашивали?) и получить работающий (в чем вы сами убедились).
> указал один addres=0
Так будет изнашиватся одна ячейка памяти, а раньше износ распределялся на много ячеек. Сами решайте как вам лучше - убивать одну ячейку, или "много ячеек но медленее".
leshak, спасибо за помощ! Работает! Теперь наверно самый трудный этап-доработать серву и завести обратную связь - точность возврата в сохранённое положение и потом обратно очень низкая. И ещё вопрос - при пустой памяти и включении кнопки загрузки из памяти серва естественно переходит в 0. Нужна защита от " дурака " - при нажатии кнопки очистки памяти кнопка загрузки отключается, при нажатии кнопки сохранения в память - включается. Пробовал через глобальную переменную типа inputbutton2Mode не получается . Как ещё можно?
Зделайте проще - проверку того что у вас записано в памяти, если 0 то при нажатии на "Загрузить" ничего не происходит.
Но может и 0 быть записан в память-это крайнее положение сервы. Думаю правильнее кнопку блокировать.
Что-то я не пойму, тогда в какой момент может быть 0 если 0 означает, что ячейка стерта, ну не суть... Если вы записываете в ЕЕПРОМ, то значит питание будет отключаться, а значит использование глобальной переменной бессмысленно. Вам нужно, что бы при нажатии на "сохранить" в ЕЕПРОМ по какому нибудь адресу записывалось EEPROM.write(25, 1), а при нажатии нажатии "стереть" записывалось EEPROM.write(25, 0) и при нажатии на "загрузить" происходила проверка:
Когда при пустой памяти случайно нажать кнопку загрузки положения сервы , то серва переходит в крайнее положение соответствующее 0. Это недопустимо.
Так а когда положение 0 допустимо?
Положение 0 будет тогда, когда в этом положении будет сохранение. А так получается, что допустм положение потенциометра 60 град, положение save 100 градусов , стёр память и случайно нажал загрузку из памяти и серва перешла в положение 0.
Понятно, я вам выше написал как это сделать, есть результаты?
Выложите весь код, полностью!
Я там опечатку нашел, так что перекопируйте еще раз.
И если интересно, то ваш код можно вот так немного оптимизировать:
Вот теперь кнопка отключилась. Спасибо maksim. Буду осваивать обратную связь сервы и ардуино. Есть вопрос. Насколько критично использование одной ячейки памяти. В описании написано, что допустимо 100000 перезаписей. Я просто немного задолбался уже-так код работает, а со всеми ячейками нет. Надо переделывать, а нехочется
Если на кнопку "сохранить" нажамать 50 раз в день, то одна ячейка прослужит около 5 лет.
А зачем две ячейки заюзывать? Не проще-ли, пожертвовать одним градусом (фиг его на глаз заметишь), и делать маппинг не 0-179, а 0-178.
Ну и сохранять, не EPROM.write(0,val+1);, а читать val = EEPROM.read(0)+1; , очищать EPROM.write(0,0), проверять есть-ли что-то в ячейка if(EPROM.read(0))
>Надо переделывать, а нехочется
Если цель - учеба, то нужно переделывать. Тем более что там переделывать - нефиг плюнуть
Очистку делать примерно так:
Запись так
Ну и в setup, находить текущий адресс (последняя ячейка больше нуля)
Можно тогда не градусом жертвовать, а просто при нажатии на "стереть" записывать в ячейку не 0, а например число 200 и проверять это при нажатии на "загрузить"
Можно тогда не градусом жертвовать, а просто при нажатии на "стереть" записывать в ячейку не 0, а например число 200 и проверять это при нажатии на "загрузить"
А таки да...
Чуть-чуть проверки тогда будут многословней. Еще равно и 200-ти дописывать нужно :)
И наверное еще, стоит завести такую функию:
И везде использовать ее вместо EPROM.write. Тоже ресурс ячеек будет экономить. Производить запись только если новое значение отличается от содержимого ячейки.
Всё работает, СПАСИБО за помощь! Но есть необычное явление. При движении в запомненную позицию серва в конце движения не доходя 1...2 градуса останавливается на долю секунды и доворачивает. А при обратном ходе делает движение на 1...2 град в другую сторону, а затем поворачивает в исходную позицию. При регулировании положения потенциометром этого нет. Не пойму, это проблемы самой сервы или программные вопросы.
Добавил светодиоды и кнопки - теперь не хватает цифровых пинов. Завёл кнопки через аналоговый вход, но что то с памятью не так. При нажатии кнопки перевода в запомненную позицию просто зависает. Как при таком чтении кнопок правильнее стирать, записывать и загружать eeprom ?
Аналоговые входы могут работать как цифровые входы/выходы....
например на вход:
или на выход:
У меня все цифровые выходы заняты светодиодами и сервами. Пришлось 10 кнопок заводить через аналоговый вход. Светодиодами управляет нормально. Но с памятью проблема, которой не было, когда кнопки были на цифровых пинах. Как правильно записать работу с памятью нескольких кнопок с одного аналогового входа?
Весь код покажите