Goblin 700 RAW Nitro (Benzin)
Авторотирует RAW Nitro просто замечательно. Низкий вес и большАя площадь ротора позволяют ротировать на более низких оборотах в сравнении с Thunder плюс меньшие потери в трансмиссии позволяют это делать дольше 😃
Сегодня время в авторотации приближалось к минуте. Конечно же это субъективно.
Мне больше нравится эффект производимый на публику, а именно, когда я летал электро так никто и не замечал когда я мотор выключал в 100 метрах над землей, а сейчас “заглохший” бензиныч замечают все.
Авторотации на RAW Nitro.
Холостой ход в режиме холд установлен на 4000 оборотов. Его удержанием занимается PID регулятор, a скрипт испоняется самим передатчиком. Частота опроса сенсора оборотов 5Hz, частота коррекции 2.5Hz. Скорость реакции регулятора не большая, но я это учел при наладке и сейчас система работает без овершотов и автоколебаний. При холодном старте, когда правильная позиция дросселя неизвестна система стабилизируется за 5-7 секунд, а уже при переключении между полетным режимом и холд за 4 секунды.
Код отлаженого регулятора.
local input = { { "Idle", SOURCE } }
local output = { "idlv", "rpmt", "rpm", "errp", "erri", "errd" }
local id_temp = getFieldInfo( "engT" ).id
local id_rpm = getFieldInfo( "RPM" ).id
local id_gvar1 = getFieldInfo( "gvar1" ).id
local id_gvar2 = getFieldInfo( "gvar2" ).id
local id_gvar3 = getFieldInfo( "gvar3" ).id
local id_gvar4 = getFieldInfo( "gvar4" ).id
local id_ls1 = getFieldInfo( "ls1" ).id
local idle_v = 0
local err_p = 0
local err_p_last = 0
local err_i = 0
local err_d = 0
local rpm_ctrl_min = 3000
local rpm_ctrl_range = 4000
local temp_min = 10
local temp_max = 75
local temp_range = ( temp_max - temp_min )
local temp_rpm_offset = 1750
local idle_source_weight = .2
local idle_source_setpoint = 0
local time_ctrl_next = 0
local time_ctrl_ramp_down = 0
local rpm = 0
local rpm_target = 0
local rpm_deadband = 2.
local mode_Off = 0
local mode_Idle = 1
local mode_Run = 2
local mode_RampDown = 3
local mode_ctrl = mode_Off
local function init_func()
time_ctrl_next = getTime()
end
local function run_func( idle_source )
if getTime() > time_ctrl_next then
time_ctrl_next = time_ctrl_next + 40
rpm = getValue( id_rpm )
rpm_target = getValue( id_gvar1 ) * 10
local eng_T = getValue( id_temp )
local ls1 = getValue( id_ls1 )
if eng_T < temp_min then
rpm_target = rpm_target + temp_rpm_offset
elseif eng_T < temp_max then
rpm_target = rpm_target + ( temp_rpm_offset / ( temp_range ) * ( temp_max - eng_T ) )
end
if rpm < rpm_ctrl_min then
mode_ctrl = mode_Off
end
if mode_ctrl == mode_Off then
idle_source_setpoint = idle_source * idle_source_weight - ( 1024 * ( 1. - idle_source_weight ) )
idle_v = idle_source_setpoint
if rpm > rpm_ctrl_min and ls1 > 0 then
err_i = 0
mode_ctrl = mode_Idle
end
elseif mode_ctrl == mode_Idle then
err_p = ( rpm_target - rpm ) / ( rpm_ctrl_range / idle_source_weight ) * 1024
err_i = err_i + err_p
if err_p < 10.24 * rpm_deadband and err_p > -10.24 * rpm_deadband then
err_p = 0
elseif err_p > 10.24 * rpm_deadband then
err_p = err_p - 10.24 * rpm_deadband
elseif err_p < -10.24 * rpm_deadband then
err_p = err_p + 10.24 * rpm_deadband
end
err_d = err_p - err_p_last
err_p_last = err_p
if err_d < 10.24 * rpm_deadband and err_d > -10.24 * rpm_deadband then
--err_d = 0
end
idle_v = idle_source_setpoint + err_p * ( getValue( id_gvar2 ) / 100 ) +
err_i * ( getValue( id_gvar3 ) / 100 ) +
err_d * ( getValue( id_gvar4 ) / 100 )
if ls1 < 0 then
idle_v = idle_v + 10.24
idle_source_setpoint = idle_v
err_i = 0 ---err_i
err_p_last = 0
mode_ctrl = mode_Run
end
if idle_v > ( -1024 * ( 1. - idle_source_weight ) ) then
idle_v = ( -1024 * ( 1. - idle_source_weight ) )
elseif idle_v < -1024 then
idle_v = -1024
end
elseif mode_ctrl == mode_Run then
if ls1 > 0 then
time_ctrl_ramp_down = getTime() + 400
mode_ctrl = mode_RampDown
end
elseif mode_ctrl == mode_RampDown then
if ls1 > 0 then
if time_ctrl_ramp_down < getTime() then
mode_ctrl = mode_Idle
end
else
mode_ctrl = mode_Run
end
end
end
return idle_v, rpm_target / 10 * 1024 * .01, rpm / 10 * 1024 * .01, err_p, err_i, err_d
end
return { input=input, output=output, run=run_func, init=init_func }
На Raw Nitro готовят ретрофит хвостового ремня.
Unfortunately, we are experiencing some “TAIL BELT” breaks on the RAW 700 NITRO model. [SG746]
The problem is not related to the project but is due to a defect in the belt.
We immediately contacted the supplier to have a new batch for these belts as soon as possible. The times are about 2 weeks
At the end of the month we will ship a retrofit KIT for the necessary replacement
Not all belts presents the problem but as we do not know which ones are right and which are not, for safety reasons it is recommended to wait for the new belt;
More details on how to get the replacement next week.
We apologize for this inconvenience.
Достойное поведение от САБ … правда немного запоздалое …
Но как говорится “лучше поздно чем никогда” 😉
В догонку. Отправлять будет сам САБ всем, кто напишет в поддержку. Требуется серийный номер и доказательство заказа.
RAW NITRO SG746 update
The new belts were shipped from the supplier to our factory in Vietnam.
As soon as they are delivered; we will pack the retrofit kits including the new belt and the M3 bolt for the tail bell crank.
To all customers who have already emailed support@goblin-helicoper we will ship with priority.
For those who have not done so, please send an email with your kit’s serial number and proof of purchase.Thank you
Не понимаю зачем SAB просит регистрировать купленные модели у них на сайте, если он владельцам конкретной зарегистрированной модели не сообщает о признанном ими дефекте ремня и что его будет менять, а я узнаю об этом на русском форуме.
На новом моторе стремительно приближаюсь к отметке 15 литров. Уже нетерпится разобрать мотор и проинспектировать стопоры. Оригинальные запчасти от RCJapan на днях приехали и на данный момент у меня 6 пар запасных стопоров 😃
Еще два поршня с кольцами и новый лейнер лежат про запас, а старый мотор все еще в гарантийном ремонте.
Посмотрим. Если на стопорах будет виден износ, то буду их менять заблаговременно. Ну а если нет, тогда надо будет искать причину их вылета в другом месте.
P.S. С RCJapan мне сейчас получается дешевле покупать чем в местных магазинах даже с учетом доставки. Не знаю как они это делают, но таможня не задержала ни одну из двух посылок.
Есть новости по мотору, но не совсем приятные. Моя теория, что стопор стачивается о палец, теряет прочность и выпрыгивает не подтвердилась. Сегодня я разобрал мотор и ни на пальце ни на стопорах следов контакта как таковых нет, а обнаружилось следующее.
Если снизу мотора через окно я палец достал с умеренным усилием, то когда поршень был на столе и я достал второй стопор я увидел небольшую развальцовку канавки стопора с внешней стороны. Соответственно палец через поршень на вылет не проходит, а упирается в ту ступеньку, что свидетельствует о повреждении самого посадочного места стопора. 6мм разверткой я геометрию отверстия подправил, палец стал проходить, но как понимаете это не решение основной проблемы.
Развальцовка наблюдается в обоих посадочных местах стопора, но в этот раз сильнее в верхнем.
Заметная глазом разница в размерах стопоров. Верхний это тот, который я достал из развальцованного посадочного, а снизу из более менее нормального.
А вот то что у стопора в нижнем посадочном приподнято правое ухо я заметил уже когда просматривал фото. Такое впечатление будто под ним какой то мусор или наплыв материала самого поршня.
Не знаю пока что с этим делать и почему так происходит. Менять каждые 16 литров поршень - это так себе вариант. Завтра подправлю посадочные и поставлю новые стопоры ушами к днищу поршня где посадочные еще не разбитые, а после 10 литров снова проконтролирую состояние посадочных мест.
Ниже фото разобранной поршневой после спаленых 16+ литров бензина. Перед тем как делать фото ничего не мыл. Если вкратце, то состояние очень хорошее. Износ минимален.
Лейнер. По всей поверхности присутствует следы хонинговки, но и встречаются незначительные потертости в основном вблизи камеры сгорания.
состояние очень хорошее
ничего хорошего не увидел )
Мне то же все не сильно нравитЦо … 😦
Ты считаешь что такой нагар на поршне приемлемый?
Кольцо не должно притереться до зеркала?
Палец стремно выглядит … почему такой темный в местах контакта с поршнем? Смазки не хватает?
Когда делал фото, то акцент делал именно на износе трущихся поверхностей, а не на том чтоб фото получились красивые и всем нравились. Детали маленькие с большой кривизной потому у меня не получилось сделать фото так, чтоб например поршень по всей поверхности не имел отражений окружающих предметов, а это действительно воспринимается как потертости. Потому пробовал фокусиротся в центр и делать фото с нескольких сторон.
Ну а нагар это такое, он ведь постоянно и бесконечно не накапливается там, а вырастает до определенной толщины слоя и постоянно обновляется. Мне главное, что бы этот нагар не присутствовал на юбке. Примерно такое же количество нагара присутствовало на всех 4х тактниках которые я разбирал, будь то инжектор или карбюратор, а там масло в бензин не добавляется.
Вот фото отмытого поршня при дневном освещении.
Чтобы понять насколько изношена юбка нужно присмотреться к следу от резца который присутствовал на новом поршне. След все еще присутствует по всей площади юбки. При царапании юбки ногтем слышно характерный звук как от мелкой гребенки. О чем это говорит? О том что износ юбки поршня не превышает глубину канавки от резца после точения.
Вот новый поршень для сравнения.
Кольцо похоже все еще на 100% не приработано. При увеличении, на поверхности видна та шероховатость которая присутствовала на новом. Это к слову об эффективности обкатки на холостых. Если зеркала на кольце нет после 16+ литров в воздухе, то в чем смысл обкатывать бак на холостых.
Палец вместе контакта с поршнем похоже попросту не двигался достаточно, что бы оксидная пленка истиралась. Не знаю. Меня больше интересует откуда там синий цвет побежалости. Неужели палец до 500 градусов разогревался
Замок у кольца симметричный. Надеюсь кольцо отметили как стояло, если перевернуть на 180 градусов то притирка начнется заново.
Палец в месте контакта с поршнем и не должен двигаться. Синий цвет это означает перегрев (бедная смесь, недостаточное охлаждение и т.п.).
Из практики: стопорные кольца пальца вылетают - неисправные подшипники коленвала (передний или коренной без разницы), в добавок разбивает нижнюю головку шатуна.
С кольцом момент я учел. Его не пришлось помечать, потому что нижняя сторона притерта к поршню и блестит, а верхняя черная и матовая.
Из практики: стопорные кольца пальца вылетают - неисправные подшипники коленвала (передний или коренной без разницы), в добавок разбивает нижнюю головку шатуна.
Поршень при этом долбит дном головку? Еще учтите возможность детонации, тоже замечательная штука.
Я немного ошибся с определением температуры по цвету побежалости. Синий это ~300 градусов, а не 500, что вполне ожидаемо учитывая сколько времени мотор работал на максимальной мощности. Такая температура хоть и кажется высокой, но не критична для поршневой.
Палец стремно выглядит … почему такой темный в местах контакта с поршнем?
Получается что это тоже цвет побежалости - фиолетово/коричневый, а это ~270 градусов
В общем, посадочные я поправил и поставил новые стопоры. 2 бака успел отлетать. Решение именно менять стопоры принял потому, что старые уменьшились в диаметре на 0.5мм в свободном состоянии в сравнении с новыми и я подумал, что может в этом причина их вылета. Так же один старый слегка изменил свою форму.
Потом, на одном из стопоров я все таки обнаружил следы трения о палец, так что мое первое предположение, что стопоры истираются о палец, имеет место быть и его надо будет так же проверить при следующей разборке мотора.
А для чего нужны отверстия (те что мелкие 😃) в бобышках поршня ?
Палец смазывается?
Где палец тогда “фиксируется”: в поршне или в шатуне? Или и там, и там гуляет?
Получается, что нужны именно для смазки. Палец свободно проворачивается как в шатуне так и в поршне.
Получается, что за такт работы он при поворачивается в поршне и “пилит” торцом “ушки” стопоров … 😦
Единственный простой вариант - полирнуть торцы пальца 😃
я полировал, чё потом стало не знаю) продал
раньше были другие стопра, плоские
Упал при выполнении авторотации. Немного не рассчитал точку приземления. На трех метрах щелкнул отмену, но было уже поздно. Обороты были слишком малы и мотор неуспел раскрутиться. Упал в траву на ноги. При дальнейшей попытке взлететь верт начал заваливаться на правый бок и на циклик почему то не реагировал. Холд и верт уже на боку.
И снова технический отказ. Вот в таком положении была серва элеватора после падения.
Я поначалу думал, что это при падении срезало винт, но присмотревшись обнаружил вот такие потертости как на суппорте так и на кронштейне серво.
По следам видно, что кронштейн был приподнят и в таком состоянии находился достаточно долго. Тоесть винт срезало не сегодня и не вчера. Однако, почему циклик был неуправляем по элеронам, а не по элеватору для меня загадка.
Остатки винта я высверлил и установил винт на 2мм длиннее, потому что покоцал начало резьбы, а когда начал монтировать суппорт на редуктор, то внем сорвало одну из двух М3 резьб, блин. Вроде бы и тянул без фанатизма. Короче, и там я поставил винт на 2мм длиннее (отверстие там сквозное, можно упереться болтом в зубчатое колесо!) и залил фиксатором.
Думаю или купить новый корпус редуктора или перенарежу под М4 резьбу. Пока буду так летать.
P.S. На редукторе, под суппортом, с той стороны где сорвало резьбу тоже было видно следы потертости от вибрации, но я не придал этому значение. Возможно вибрациями резьбу ослабило, но в том месте фиксатора было налито щедро. Винты очень туго откручивались.
Единственный простой вариант - полирнуть торцы пальца
я полировал, чё потом стало не знаю)
Думал об этом, но не полировал, так как потертости обнаружил уже после сборки мотора.
Еще момент, истирание ушек свидетельствует о не симметричности стопорного в плоскости. Я это проверил на новых комплектах и таки да. Ушки слегка загнуты в сторону. При сборке я интуитивно устанавливал стопоры так, что бы ушки смотрели наружу, что бы контакт стопора с пальцем происходил по всему периметру. Хотя это врятли решает проблему развальцовки посадочного места стопора.
Увидим какое состояние посадочных будет после следующих 10-15 литров.
А параллельно остальным проблемам я еще улучшил регулятор холостого хода. На преходных режимах реагирует быстрее и минимум осцилляций. Плюс добавил логи коэффициентов регулятора и частотный фильтр производной.
local input = { { "thri", SOURCE } }
local output = { "thro", "rpmt", "rpm", "errp", "erri", "errd" }
local id_temp = getFieldInfo( "engT" ).id
local id_rpm = getFieldInfo( "RPM" ).id
local id_gvar1 = getFieldInfo( "gvar1" ).id
local id_gvar2 = getFieldInfo( "gvar2" ).id
local id_gvar3 = getFieldInfo( "gvar3" ).id
local id_gvar4 = getFieldInfo( "gvar4" ).id
local id_ls1 = getFieldInfo( "ls1" ).id
local id_s2 = getFieldInfo( "s2" ).id
local id_sa = getFieldInfo( "sa" ).id
local id_sf = getFieldInfo( "sf" ).id
-------- PID State ----------
local throttle_out = 0
local err_last_input = 0
local err_last_error = 0
local err_p = 0
local err_i = 0
local err_d = 0
local err_d_tau = 0.6
local err_i_max = 20 * 10.24
-----------------------------
local err_input_max = 2000
local rpm_ctrl_min = 3000
local rpm_ctrl_range = 2000
local temp_min = 10
local temp_max = 75
local temp_range = ( temp_max - temp_min )
local temp_rpm_offset = 2000
local thr_source_weight = 0
local thr_source_setpoint = 0
local thr_source_setpoint_ref = 0
local thr_source_min = -1024 + 10.24 * 0
local time_ctrl_next = 0
local time_ctrl_ramp_down = 0
local time_ctrl_sim_next = 0
local rpm = 0
local rpm_target = 0
local rpm_deadband = 300
local rpm_ctrl_setpoint_ref = 6000
local mode_Off = 0
local mode_Idle = 1
local mode_Run = 2
local mode_RampDown = 3
local mode_ctrl = mode_Off
local pid_sample_time_S = .25
local sim_sample_time_S = .1
local sim_rpm_store_filtered = rpm_ctrl_min
local sim_rpm_store_not_filtered = 0
local sim_rpm_store = rpm_ctrl_min
local sim_rpm_accel_max = 1000
local is_sim_enabled = 0
local elapsedTime = 0
local function sim_rpm( set_point )
local ls1 = getValue( id_ls1 )
if mode_ctrl == mode_Run then
sim_rpm_store = 14000
elseif mode_ctrl == mode_Idle and thr_source_weight > 0 then
sim_rpm_store = sim_rpm_store + ( sim_rpm_accel_max * sim_sample_time_S ) * ( ( ( -0.5 - 0.32 * ( 1 - ( rpm_ctrl_setpoint_ref - rpm_target ) / 2000 ) ) + set_point / thr_source_weight ) )
end
local rpm_a = .1
sim_rpm_store_not_filtered = sim_rpm_store + 2000 * ( getValue( id_s2 ) / 1024 ) + -200 + math.random( 400 )
sim_rpm_store_filtered = sim_rpm_store_not_filtered * rpm_a + ( 1 - rpm_a ) * sim_rpm_store_filtered
return sim_rpm_store_filtered
end
local function recalc_with_deadband( anError, aDeadBand )
local ret = anError
if ret <= aDeadBand and ret >= -aDeadBand then
ret = 0
elseif ret > aDeadBand then
ret = ret - aDeadBand
elseif ret < -aDeadBand then
ret = ret + aDeadBand
end
return ret
end
local function recalc_with_limits( aValue, aMin, aMax )
local ret = aValue
if ret < aMin then
ret = aMin
elseif ret > aMax then
ret = aMax
end
return ret
end
local function recalc_with_expo( aValue, anExpo )
return anExpo * ( aValue ^ 3 ) + ( 1 - anExpo ) * aValue
end
local function rpm_ctrl_loop()
local err_input = recalc_with_limits( ( rpm_target - rpm ), -err_input_max, err_input_max )
if err_input >= -rpm_deadband and err_input < 0 then
err_input = 0
elseif err_input < -rpm_deadband then
err_input = err_input + rpm_deadband
end
--err_input = recalc_with_deadband( err_input, rpm_deadband )
err_p = err_input * ( getValue( id_gvar2 ) / 100 ) * thr_source_weight
if throttle_out > thr_source_min and throttle_out < thr_source_setpoint then
err_i = err_i + ( ( err_input + err_last_error ) * ( getValue( id_gvar3 ) / 100 * pid_sample_time_S ) * 0.5 * thr_source_weight )
err_i = recalc_with_limits( err_i, -err_i_max, err_i_max )
end
err_last_error = err_input
err_d = ( ( ( err_last_input - rpm ) * ( getValue( id_gvar4 ) / 100 ) * 2. ) + ( 2. * err_d_tau - pid_sample_time_S ) * err_d ) /
( 2. * err_d_tau + pid_sample_time_S ) * thr_source_weight
err_last_input = rpm
return thr_source_setpoint_ref + err_p + err_i + err_d
end
local function set_setpoint_ref( aRef )
thr_source_setpoint_ref = aRef
thr_source_weight = ( ( 1024 + thr_source_setpoint ) / 2 ) / rpm_ctrl_range
err_i = 0
end
local function set_rpm_target( aRpm )
--err_last_input = err_last_input + ( aRpm - rpm_target )
rpm_target = aRpm
end
local g_log_file = nil
local function init_func()
time_ctrl_next = getTime()
time_ctrl_sim_next = getTime()
end
local function run_func( thr_source )
local theNow = getTime()
if theNow > time_ctrl_next then
time_ctrl_next = time_ctrl_next + 100 * pid_sample_time_S
elapsedTime = elapsedTime + 1000 * pid_sample_time_S
if is_sim_enabled == 0 then
rpm = getValue( id_rpm )
end
local ls1 = getValue( id_ls1 )
if rpm < rpm_ctrl_min or getValue( id_sa ) > -512 or getValue( id_sf ) > 0 then
err_p = 0
err_i = 0
err_d = 0
mode_ctrl = mode_Off
end
if mode_ctrl == mode_Off then
thr_source_setpoint = thr_source
set_setpoint_ref( thr_source )
set_rpm_target( rpm_ctrl_setpoint_ref )
throttle_out = thr_source_setpoint
if rpm > rpm_ctrl_min and ls1 > 0 then
err_i = 0
err_last_input = rpm
mode_ctrl = mode_Idle
end
elseif mode_ctrl == mode_Idle then
if ls1 < 0 then
throttle_out = throttle_out + 10.24 * 1
err_i = err_i + 10.24 * 1
mode_ctrl = mode_Run
else
local theTargetRpm = getValue( id_gvar1 ) * 10
local eng_T = 0
if is_sim_enabled == 0 then
eng_T = getValue( id_temp )
else
eng_T = 30
end
if eng_T < temp_min then
theTargetRpm = theTargetRpm + temp_rpm_offset
elseif eng_T < temp_max then
theTargetRpm = theTargetRpm + ( temp_rpm_offset / ( temp_range ) * ( temp_max - eng_T ) )
end
if theTargetRpm < rpm_target - 200 * pid_sample_time_S then
set_rpm_target( rpm_target - 200 * pid_sample_time_S )
else
set_rpm_target( theTargetRpm )
end
throttle_out = rpm_ctrl_loop()
throttle_out = recalc_with_limits( throttle_out, thr_source_min, thr_source_setpoint )
end
elseif mode_ctrl == mode_Run then
if ls1 > 0 then
time_ctrl_ramp_down = theNow + 300
mode_ctrl = mode_RampDown
end
elseif mode_ctrl == mode_RampDown then
if ls1 > 0 then
if time_ctrl_ramp_down < theNow then
err_last_input = rpm
if rpm > rpm_ctrl_setpoint_ref then
set_rpm_target( rpm )
else
set_rpm_target( rpm_ctrl_setpoint_ref )
end
mode_ctrl = mode_Idle
end
else
mode_ctrl = mode_Run
end
end
----------------------------------- Logging ---------------------------------------
if g_log_file ~= nil then
local datenow = getDateTime()
io.write( g_log_file, datenow.year.."-"..string.format("%02d",datenow.mon).."-"..string.format("%02d",datenow.day)..","
..string.format("%02d", ( elapsedTime / ( 60000 * 24 ) ) % 24 )..":"..string.format("%02d", ( elapsedTime / 60000 ) % 60 )..":"..string.format("%02d", ( elapsedTime / 1000 ) % 60 ).."."
..string.format("%03d",( elapsedTime % 1000 ) )..",",
string.format("%.1f", ( 1024 + throttle_out ) / 10.24 ), ",", string.format("%.2f", rpm_target ), ",", string.format("%.2f", rpm ), ",",
string.format("%.2f", sim_rpm_store_filtered ), ",", string.format("%.2f", sim_rpm_store_not_filtered ), ",",
string.format("%.1f", err_p / 10.24 ), ",", string.format("%.1f", err_i / 10.24 ), ",", string.format("%.1f", err_d / 10.24 ), "\n" )
end
------------------------------------------------------------------------------------
end
-------------------------------------- Simulation -------------------------------------
if is_sim_enabled == 1 and getTime() > time_ctrl_sim_next then
time_ctrl_sim_next = time_ctrl_sim_next + 100 * sim_sample_time_S
if getValue( id_sf ) < 0 then
if g_log_file == nil then
g_log_file = assert( io.open( "/LOGS/_debug.csv", "wb" ), "Cannot open file" )
io.write( g_log_file, "Date,Time,throttle_out,rpm_target,rpm,rpm_filtered,rpm_not_filtered,err_p,err_i,err_d\n" )
end
rpm = sim_rpm( ( 1024 + throttle_out ) / 10.24 / 200 )
else
if g_log_file ~= nil then
io.close( g_log_file )
g_log_file = nil
end
rpm = 0
end
end
----------------------------------------------------------------------------------------
return throttle_out, rpm_target / 10 * 1024 * .01, rpm / 10 * 1024 * .01, err_p, err_i, err_d
end
return { input=input, output=output, run=run_func, init=init_func }