nodemcu + esp8266 + hc-sr04 - tmr.now() difference is incorrect - lua

i've started using nodemcu on esp8266.
I've connected esp with hc-sr04 (ultrasound sensor for distance measurement).
hc-sr04 need to receive high state for trig pin for 10us. After that hc send high state of echo pin. The time of the high state from echo pin can be different (depends of distance). The time is counted in us.
The problem is that this time from echo pin is incorrect (IMHO). I'm not sure but is this possible that tmr. from nodemcu is not as precise as it should? And why there is so big difference between times in each loop?
My code and below you will find time printings from code:
gpio.write(3,gpio.LOW)
gpio.mode(3,gpio.OUTPUT)
gpio.write(4,gpio.LOW)
gpio.mode(4,gpio.INT)
time=0
flag=0
i=1
function startDis(level)
time=tmr.now()
end
function endDis(level)
time=tmr.now()-time
flag=0
end
function trigger()
gpio.write(3,gpio.HIGH)
tmr.delay(10)
gpio.write(3,gpio.LOW)
flag=1
end
gpio.trig(4,'up',startDis)
gpio.trig(4,'down',endDis)
// ---------THIS PART HAS BEEN CHANGED--------
while i<10 do
if flag==0 then
trigger()
end
tmr.delay(1000000)
print(time)
i=i+1
end
//--------------- TO ------------
tmr.alarm(0,2000,1,function()
print(time)
print(i)
if flag==0 then
trigger()
end
i=i+1
if i==10 then tmr.stop(0) end
end)
Code prints:
0
440184038
1999856
442183990
4000221
444184055
6000175
446184287
7999686
Thanks for clues and solutions.

Petre, I'll do this as an answer because it doesn't fit into a quick comment. :(
You need to read some of the other discussion in the FAQ on how the overall SDK schedules tasks. You are assuming in your code that something like this happens:
<every 2mSec>
print(time)
print(i)
if flag==0 then
gpio.write(3,gpio.HIGH)
time=tmr.now()
tmr.delay(10)
gpio.write(3,gpio.LOW)
time=tmr.now()-time
flag=0
flag=1
end
i=i+1
if i==10 then tmr.stop(0) end
where in in reality what happens is closer to:
<every 2mSec task starts>
print(time)
print(i)
if flag==0 then
gpio.write(3,gpio.HIGH)
<H/W interupts calls low level GPIO which books up callback>
time=tmr.now()
tmr.delay(10)
<H/W interupts calls low level GPIO which books down callback>
gpio.write(3,gpio.LOW)
flag=1
end
i=i+1
if i==10 then tmr.stop(0) end
<task ends>
<possible TCP and other tasks run>
<up trigger is delivered>
time=tmr.now()
<task ends>
<possible TCP and other tasks run>
<down trigger is delivered>
time=tmr.now()-time
flag=0
<task ends>
The Esp8266 SDK is not a real Real Time O/S; it is event driven. It's your mindset that needs to get reorientated.
Using the tmr.delay() this way is the correct use, but you need HW test tools such as an oscilloscope or logic analyser to check what the actual delay is because you need to add in the time to process the Lua instructions.
Or even put the tmr.now() calls inline.
The real usecase for the trigger is where you have an input connected to a sensor such as a mechanical open/close detector and this avoids the need to poll it.

Related

How to turn off a function after a desired amount of time?

I know my question would sound silly but I'm new to Lua so I'm trying to make the best practice as I can.
function wait(n)
local start = os.time()
repeat until os.time() > start + n
end
function hi(x)
while x do
print("Hi")
wait(.5)
end
end
hi(true)
For example, I want to turn off the function "hi" after running for 6 seconds and re-enable it after stopping for 2 seconds, how can I do it? Thank you so much!
Try this changes...
function wait(n)
local start = os.clock()
repeat until os.clock() > start + n
end
function hi(x)
for i = 1, x do
print("Hi")
wait(.5)
end
end
hi(4) -- With the hardcoded wait(.5) this will end after 2s
One warning.
Lua is fast so wait() will run in high performance mode.
Let it run by hi(120) for a minute will also run your fans in high cooling mode.
...it is better to have a more CPU friendly wait/sleep.
Easy Peasy with LuaJIT: https://luajit.org/ext_ffi_tutorial.html

(Lua) How do I increment a variable every time one of three if statements runs?

I'm building a moving and sensing bot in CoppelliaSim for school. CopelliaSim uses Lua for scripting. Basically every time the bot's forward sensors hit something, one of three if statements will run. I want it to count how many times any of these if statements runs, and once that count gets to a certain amount (like 20), I'll run something else, which will do the same thing (find collisions, add to the count, reach an amount, and switch back to the first).
i=0
result=sim.readProximitySensor(noseSensor) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+3
print("Collision Detected")
i=i+1
print(i)
end
result=sim.readProximitySensor(noseSensor0) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+3
print("Collision Detected")
i=i+1
print(i)
end
result=sim.readProximitySensor(noseSensor1) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+3
print("Collision Detected")
i=i+1
print(i)
end
Above is the start of a function and one of the three If statements. I'm printing just to see if it actually increments. It is printing, but it is not incrementing (just 1 over and over). This bot has 3 sensors on it (an if statement for each sensor) and it adds 1 to i for the first collision and ignores the rest, even if it's from the same sensor. I feel like my problem is just some simple syntax issue with Lua that I don't know and can't find how to properly fix.
I'm happy to provide more code if this little snippet was not sufficient to answer this question.
Assuming that you have a looping function such as sysCall_actuation which is being executed per simulation step. As Joseph Sible-Reinstate Monica has already stated, you are setting your variable i back to zero every time a simulation step is executed. To achieve your goal, you would have to set your variable to 0 outside your function. There are two appropriate approaches to achieve that:
Define the variable outside any function, in the beginning of your file (or before you define any function that uses your variable e.g right before the definition of sysCall_actuation).
-- Beginning of the file.
local i = 0
..
function sysCall_actuation()
..
i = i + 1
..
end
Define your variable in sysCall_init function, which is the appropriate approach in CoppeliaSim.
function sysCall_init()
i = 0
..
end
Finally, you can use your variable in your sysCall_actuation function with basic comparison operations:
function sysCall_actuation()
..
if i > 20 then
i = 0 -- Reset 'i' so this function will not be running every step again and again.
-- Do something here.
..
end
As a side note, practice using local variables whenever you can, to keep the memory clean and avoid having ambiguous variables.

Interfacing GSM module with nodemcu

I wrote this code to interface the gsm module, can anyone check the code and give me some propositions ?
hex1= '0x1A';
function delay_s(delay)
delay = delay or 1
local time_to = os.time() + delay
while os.time() < time_to do end
end
uart.alt(1);
uart.setup(0, 9600, 8, uart.PARITY_NONE, uart.STOPBITS_1, 1)
uart.write(0,"AT+IPR=9600\n")
for j = 1, 10 do
uart.write(0, "AT\n")
end
delay_s(1000)
uart.write(0, "AT\n")
delay_s(1000)
uart.write(0, 'AT+CSCS="GSM"\n')
delay_s(1000)
uart.write(0, 'AT+CMGF=1\n')
delay_s(1000)
uart.write(0, 'AT+CMGS="+21654102832"\n')
delay_s(1000)
uart.write(0, " Salut tout le mond !!!\n")
delay_s(1000)
uart.write(0, hex1)
delay_s(1000)
This code won't even run on NodeMCU because the standard Lua os.time() will fail since the os module is not available. I suggest you dig into http://nodemcu.readthedocs.io/en/latest/en/lua-developer-faq/#how-is-nodemcu-lua-different-to-standard-lua.
Besides, even if it were available os.time() has 1 second resolution.
The returned value is a number, whose meaning depends on your system. In POSIX, Windows, and some other systems, this number counts the number of seconds since some given start time (the "epoch").
Hence, your delay_s(1000) would delay execution for 1000 seconds. Doing that with busy-waiting is...not optimal.
You probably want to use the tmr module instead.
uart.alt(x);
0 - standard pins
1 - alternate the pins
You havent specify which pins you are gonna use for the communication, or else use uart.alt(0); for standard pins

Problems interpreting a square wave

I'm trying to use an ESP8266 SoC to read a water flow sensor that is said to produce a square wave as output. I thought it would be a simple matter of using a GPIO port in interrupt mode, to count rising edge transitions -- and in fact that initially seemed to work. Then I upgraded the firmware from 0.96 to 1.5 and it has since ceased to work, I see no transitions when the wheel spins anymore.
However, if I run a wire to the pin [for the GPIO I'm using] and touch it to VCC momentarily, the interrupt routine is called as expected, so I know the sensor is wired to the right pin, and the interrupt routine is registered correctly. My code:
function intCb(level)
SpinCount = SpinCount + 1
local levelString = "up"
if level == gpio.HIGH then
levelString = "down"
end
gpio.trig(pin, levelString, intCb)
end
gpio.write(pin, 0)
gpio.trig(pin, "up", intCb)
gpio.mode(pin, gpio.INT, gpio.FLOAT)
So what am I missing? Do I need more support circuitry to read a square wave as input? If so then how did it work initially?
For anything that involves hardware it's really hard to give a definite answer here on SO. In most cases one bases it on hints (and hunches sometimes). A few ideas:
gpio.FLOAT should probably be gpio.PULLUP instead (unless you have an external pull-up resistor).
Your setup doesn't seem to be fundamentally different from e.g. using a push button or a switch to trigger some event. Hence, you probably want to use some kind of debounce or throttle function.
Since you seem to be interested in both rising and falling edges (as you switch between up and down) you might just as well listen for both, no?
So, assuming I drew the right conclusions something like the following generic skeleton may prove to be useful:
-- inspired by https://github.com/hackhitchin/esp8266-co-uk/blob/master/tutorials/introduction-to-gpio-api.md
-- and http://www.esp8266.com/viewtopic.php?f=24&t=4833&start=5#p29127
local pin = 4 --> GPIO2
function debounce (func)
local last = 0
local delay = 5000
return function (...)
local now = tmr.now()
local delta = now - last
-- if delta < 0 then delta = delta + 2147483647 end; proposed because of delta rolling over
if delta < delay then return end;
last = now
return func(...)
end
end
function onChange ()
print('The pin value has changed to '..gpio.read(pin))
end
gpio.mode(pin, gpio.INT, gpio.PULLUP) -- see https://github.com/hackhitchin/esp8266-co-uk/pull/1
gpio.trig(pin, 'both', debounce(onChange))
I solved this using a 555 timer chip as a schmitt trigger:

Lua Coroutine Error

I'm currently working on a simple 'guess the number' game using Lua. I'm programming through an app on my iPad called TouchLua+. One of the game modes is you have a certain amount of time to guess the number. I thought that to do this, I would create a coroutine that counts down from the given time. For some reason, I can't input a number while the coroutine is running. Can anyone help? Here is what I have so far.
target = math.random(1, 100)
coroutine.resume(coroutine.create(function()
for i = 1, roundTime do
sleep(1000)
sys.alert("tock")
end
lose = true
coroutine.yield()
end))
repeat
local n = tonumber(io.read())
if (n > target) then
print("Try a lower number.\n")
elseif (n < target) then
print("Try a higher number.\n")
else
win = true
end
until (lose or win)
return true
Coroutines are not a form of multiprocessing, they are a form of cooperative multithreading. As such, while the coroutine is running, nothing else is running. A coroutine is meant to yield control back to the caller often, and the caller is meant to resume the coroutine so the coroutine can continue where it yielded. You can see how this will appear to be parallel processing.
So in your case you would want to yield from inside the loop, after a small sleep time:
co = coroutine.create(function()
for i = 1, roundTime do
sleep(1)
sys.alert("tock")
coroutine.yield()
end
lose = true
end)
Unfortunately, you can't interrupt io.read(), which means the above is of no use. Ideally you would want a "io.peek" function so you could do the following:
while coroutine.status(co) ~= "dead" do
coroutine.resume(co)
if io.peek() then -- non-blocking, just checks if a key has been pressed
... get the answer and process ...
end
end
I am not aware of a non-blocking keyboard IO in Lua. You could create a C extension that exposes some of C non-blocking keyboard input to Lua, assuming that TouchLua+ supports C extensions. I doubt it, given that it is an iOS app.
It doesn't appear that there is a time loop or callbacks or such, and couldn't find docs. If you have option of creating a text box where user can enter answer and they have to click accept then you can measure how long it took. If there is a time loop you could check time there and show message if run out of time. All this is very easy to do in Corona, maybe not possible in TouchLua+.

Resources