программировать это умение составлять алгоритм, т.е. составлять последовательность действий. для этого нужно понимать что и как работает на достаточном для определённой задачи уровне. и только в последнюю очередь это знание языка. где-то в сторонке еще знание математики, физики и т.д.
тренируйся путешествовать во времени. есть несколько временных рядов, представь, что это рядышком лежит несколько старых фотоплёнок с разными размерами снимков. для микроконтроллера у тебя 2 или больше таких временных ряда, вот тебе и нужно вникать, в каком состоянии находится что-либо (серва, контроллер и т.д.) в каждый момент. нужно одновременно понимать, как всё работает в общем и как каждая штука в частности, уметь абстрагироваться и понимать, насколько детально что-то нужно рассматривать.
один временной ряд - это прерывание таймера, очень условно допустим с шагом 20мс. вот каждые 20мс прекращает работать основной код и мк начинает выполнять код ф-и прерывания, в которой в нужный момент на определённых ножках мк выставляется высокий или низкий уровень. потом этот код прекращает работать и продолжает выполнятся основной код. разобрался. допустим в основном коде ты уже присвоил переменным нужные значения (вызвал ф-ю servo.write). а теперь нажимаешь конопочку плэй и проигрываешь эту плёночку, смотря, что у тебя на сигнальном пине сервы. как-то так
Вложение:
s.png [ 64.34 КиБ | Просмотров: 2251 ]
у тебя есть сервы. им переодически подаётся управляющий сигнал, выше было предположение, что это с переодичностью 20мс. в секунде 1000мс, т.е. 50 раз в секунду. электроника сервы получает этот сигнал, получает данные с потенциометра (переменного резистора) и пытается вращать мотор, что бы провернуть вал в нужную позицию. как быстро будет проварачиваться вал это зависит от сервы и в данном случае может зависить от напряжения питания сервы и от нагрузки на валу. вот для сервы 20-ти миллисекундные интервалы. у микроконтроллера кроме ряда прерывания есть ряд, где основной код выполняется. у него совсем мелкий шаг - это такты микроконтроллера, а их за секунду миллионы (8млн или 16млн или ещё сколько). что происходит прям каждый такт в данном случае рассматривать не нужно, так что короткими перебежками.
Код:
void loop()
{
servo3.write(10); // нога назад
servo4.write(20); // колено разогнуто
delay(500);
servo3.write(60); // нога вперед
servo4.write(60); // колено согнуть
delay(500);
servo4.write(20); // колено разогнуть
servo3.write(40); // нога чуток назад
delay(500);
}
задал положения для серв. ждешь пол секунды. опять задал положения. опять ждешь. в третий раз задал положение. опять ждешь. а потом весь цикл по новой.
абстрагирование. знаешь, что каждые 20мс на управляющих пинах для серв выставляются соответствующие уровни (в зависимости от неких переменных, которые ты задал через servo.write). что там как работает в этом прерывание для данной задачи, как серва сравнивает сигналы и управляет мотором, значения не имеет. абстрагируешся от этих ненужностей. т.е. у тебя остаётся два временых ряда - основной код и положение серв. примерно прикидываешь, на какой угол проворачивается серва за некий период. вот попробуй совместить эти два ряда и одновременно их проиграть. проигрывать это всё в уме или в экселе/на листочке табличкой чиселки записывать или ещё как значения не имеет, придумай как тебе удобней будет понимать, что и когда происходит. для понимания разницы между желаемым положением и реальным поиграйся с изменением значения задержки. замени в delay 500 на 1 и опять проиграй. замени на 2000 и проиграй. позаменяй углы в вызовах servo.write.
вот создавать алгоритм это в данном случае и означает придумывание, в какой момент какие значения задавать функцией servo.write и как это делать. можно потренироваться управлять скоростью вращения сервы. допустим задаёшь для сервы почти крайнее положение (10, 20, 160 или 170 или ещё какой угол, который для твоей сервы безопасно устанавливать), делаешь задержку в 1-2 секунды. а потом в цикле с небольшой задержкой понемногу меняй угол
Код:
int servoDelay=15;
Код:
void loop(){
for (pos=20; pos<=160; pos=pos+1) {
servo.write(pos);
delay(servoDelay);
}
for (pos=160; pos>=20; pos=pos-1) {
myPointer.write(pos);
delay(servoDelay);
}
или так
Код:
void loop(){
servoDelay=15;
servo.write(20);
delay(2000);
for (pos=20; pos<=160; pos=pos+1) {
servo.write(pos);
delay(servoDelay);
}
поиграйся со значениями. а потом можно усложнить, управляя двумя сервами. выставляешь первоначальное значение, делаешь достаточную задержку и с небольшими задержками изменяешь значение желаемого положения для серв. знаешь, с какой примерно скоростью вал вращается? начальные положения такие-то, а за некое время хочешь переместить в такие-то. вот и вычисляешь значения задержек и на какой угол проворачивать.
поигравшись так, можно и с другим вариантом пробовать. для дуни есть возможность получать значение миллисекунд, прошедших с момента включения дуни.
https://www.arduino.cc/en/reference/millis. присвоив переменной в каком-нибудь месте это значение получаешь возможность определять, сколько времени прошло с некоего момента. вот зная первоначальное положение, желаемое конечное и за какое время оно должно в него переместится, можно вычислять, какое положение задавать при вызове servo.write. накидал примерно как это может выглядеть
Код:
void loop() {
int pos = 0;
int tergetPos = 110;
unsigned long time, diff;
unsigned long travelTime = 1500; //milliseconds
servo.write(20);
delay(2000);
time = millis();
while(pos < tergetPos)
{
diff = time - millis();
pos = вычисли здесь сам;
servo.write(pos);
}
}