B4R Question Handle ASyncstream NewData with Timer or Looper

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi,

an Arduino is connected to a PC with B4J server.
The B4J Server sends data using the serial connection and asyncstream.write.
The Arduino is also using Asyncstream and is waiting till new data comes in.
When new data received, the Arduino takes action and replies back to the B4J server.

B4R Code
Handle new data received from the B4J server. Either character 1 or 2:
B4X:
Sub Astream_NewData (Buffer() As Byte)
    Log("Astream Received: ", Buffer, " = ", Buffer(0))
    Dim p As UInt = Buffer(0)
    If p = 49 Or P = 50 Then MoveCraneArm(p - 48)
End Sub

The Arduino replies back to the B4J server in JSON format using asyncstream write:
B4X:
Sub MoveCraneArm
...
    Dim s As String
    s = "{""Angle"":"
    AStream.Write(s.GetBytes)
    s = NumberFormat(ServoArmAnglePos,0,0)
    AStream.Write(s.GetBytes)
    s = "}"
    AStream.Write(s.GetBytes)
...

B4J Code
Write data via the asyncstream to the Arduino:
B4X:
Public Sub AStream_WriteData(data As String)
    Log($"AStream_WriteData: ${data}"$)
    AStream.Write(data.GetBytes("UTF8"))
End Sub

Handling the incoming data received from the Arduino:
B4X:
Sub AStream_NewData(Buffer() As Byte)
    Dim data As String = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    Log($"AStream_NewData: ${data}"$)
...

Questions:
  • When using above, the B4J server is constantly receiving weird characters instead of expected JSON string. What could the cause be? The COM parameter are equal.
  • In the B4R code is it required to set up a timer or looper to check if new data comes in OR is the async new data sub enough of handling that?
 

johndb

Active Member
Licensed User
Longtime User
I am currently using B4J and B4R in a similar Server/Controller configuration but in my case the server is communicating with an Arduino with LCD shield for display and menu control. I have found that a delay must be placed after a B4R command which takes some time to execute. In your case, you are controlling a servo. I have found with servos that you need at least 100ms if not longer for the command/servo to execute.

You shouldn't need a timer or looper for the async operation. I have one that checks the buttons so it may be worth while to create a "dummy" looper to see if it cleans up the com.

John
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Thanks John for comprehensive answer.

Have found the issue in the B4R code replying back to B4J. The NumberFormat is causing trouble. If leaving out, then all fine.
B4X:
s = NumberFormat(ServoArmAnglePos,0,0)
AStream.Write(s.GetBytes)
Tried several conversions from UInt to Double, then to String but all did not work with AStream.Write.
It might be a bug = not sure yet.

In addition have included a dummy looper. The timer you mentioned, been already in place = generous at 250 to show the red led on.

BTW: showed this experiments to several kids, all been fancy about it.
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Pls find the B4R Sub MoveCraneArm and the full project attached (B4R + B4J).
If in MoveCraneArm the
B4X:
AStream.Write(NumberFormat(ServoArmAnglePos,0,0))
is taken out, then the program is running fine means the arm is controlled via the B4J Server. ServoArmAnglePos is a Double (changed from UInt) - but same issue.

B4X:
Sub MoveCraneArm(direction As UInt)
  ServoArm.Attach(ServoArmPin.PinNumber)
  ServoArmAnglePos = ServoArm.Read
    LEDRedPinOn = True
    LEDRedPin.DigitalWrite(LEDRedPinOn)
    LEDGreenPinOn = False
    LEDGreenPin.DigitalWrite(LEDGreenPinOn)
    If direction = 1 Then
        If ServoArmAnglePos <= (ServoArmAngleMax - ServoArmAngleMove) Then
            ServoArmAnglePos = ServoArmAnglePos + ServoArmAngleMove
        Else
            ServoArmAnglePos = ServoArmAngleMax
        End If
    End If
    If direction = 2 Then
        If ServoArmAnglePos >= (ServoArmAngleMin + ServoArmAngleMove) Then
            ServoArmAnglePos = ServoArmAnglePos - ServoArmAngleMove
        Else
            ServoArmAnglePos = ServoArmAngleMin
        End If
    End If
    ServoArm.Write(ServoArmAnglePos)
    Delay(250)
    LEDRedPinOn = False
    LEDRedPin.DigitalWrite(LEDRedPinOn)
    LEDGreenPinOn = True
    LEDGreenPin.DigitalWrite(LEDGreenPinOn)
    ServoArm.Detach
    'Send message in JSON format to the B4J server
    AStream.Write("{""Angle"":")
    AStream.Write(NumberFormat(ServoArmAnglePos,0,0))
    AStream.Write("}")
End Sub
 

Attachments

  • B4RHowToServoMotorCraneBrowser.zip
    14.6 KB · Views: 392
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Seems to work fine here:
B4X:
B4J: AStream_NewData: {"Angle":10}B4R:MoveCrane:Done
AStream_WriteData: 2
Waiting for value (100 ms)
B4J: AStream_NewData: B4R: Astream Received: 2 = 50 = Action:2
B4R: MoveCrane:2
B4J: AStream_NewData: {"Angle":10}B4R:MoveCrane:Done
AStream_WriteData: 1
Waiting for value (100 ms)
B4J: AStream_NewData: B4R: Astream Received: 1 = 49 = Action:1
B4R: MoveCrane:1
B4J: AStream_NewData: {"Angle":20}B4R:MoveCrane:Done
AStream_WriteData: 1
Waiting for value (100 ms)
B4J: AStream_NewData: B4R: Astream Received: 1 = 49 = Action:1
B4R: MoveCrane:1
AStream_WriteData: 1
Waiting for value (100 ms)
B4J: AStream_NewData: {"Angle":30}B4R:MoveCrane:Done
B4R: Astream Received: 1 = 49 = Action:1
B4R: MoveCrane:1
AStream_WriteData: 1
Waiting for value (100 ms)
B4J: AStream_NewData: {"Angle":40}B4R:MoveCrane:Done
B4R: Astream Received: 1 = 49 = Action:1
B4R: MoveCrane:1
AStream_WriteData: 2
Waiting for value (100 ms)
B4J: AStream_NewData: {"Angle":50}B4R:MoveCrane:Done
B4R: Astream Received: 2 = 50 = Action:2
B4R: MoveCrane:2
AStream_WriteData: 2
Waiting for value (100 ms)
B4J: AStream_NewData: {"Angle":40}B4R:MoveCrane:Done
B4R: Astream Received: 2 = 50 = Action:2
B4R: MoveCrane:2
B4J: AStream_NewData: {"Angle":30}B4R:MoveCrane:Done
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Thanks for the check and support.
After further checks, finally found the cause:
For tests with the ESP8266 did replace the rCore library with the one you shared here post #33.
After re-installing the original rCore v1, the issue with NumberFormat is resolved and the experiment is running fine :).

Will write up a next tutorial (experiment) on how to control a Servo Motor via B4J webserver running on a Raspberry Pi to which an Arduino is connected via USB.
The (ultimate) goal, would be to run this experiment on a ESP8266 - then no need for an Arduino and Raspberry Pi. The ESP8266 can then be placed in f.e. a Lego Crane. Real Fun.

Here a screenshot of the Webbrowser:
upload_2016-6-19_10-55-56.png
 

Attachments

  • upload_2016-6-19_10-55-30.png
    upload_2016-6-19_10-55-30.png
    12.6 KB · Views: 364
Upvote 0
Top