Share My Creation Wind speed and direction datalogger

Background:

The aim was to measure the wind direction and speed (m/s) passing through a moving bed of iron ore. The bed is ignited and air is sucked through the bed. The conveyor is 30m long and 4 m wide. An aluminium profile is placed across the conveyor and the "buggy" is moved to a series of points and the data collected. The data is used to determine if the suction is uniform over the width of the bed. The bed temperature is up to 1000°C but above the bed is room temperature. No cables can be used, therefore no power cable is possible.

Solution:

The buggy is made from aluminium with sides of styropor. Three wheels are free turning and the third is powered by a Nema23 format 5V motor, controlled by a RPi 3. The RPi software is written in B4J and the control/logger software on a tablet in B4A. The connection is via Bluetooth which works up to 10m. The sensor is mounted under the buggy (Black) and comes from the company Windsonic. This sensor is VERY sensitive. Walking past the sensor will give a measurement. The power for the buggy and sensor comes from a powerpack (15000 mAh) and can last up to 16 hours from one charge.

Photos:

Pict2992.jpg

PICT2993.JPG

Pict2994.jpg


The motor control is a L293 chip on a custom board. The B4J app is set to load at boot by including it in the "/etc/rc.local" file.

The main problem was finding a motor which would run at 5V and drive the buggy which has a total weight of 2.75 kg! The one I selected draws 2A which is the limit of the powerpack.

The mini aluminium profile is from the company Maker Beam for those who are interested.

B4J Code:

B4X:
'Non-UI application (console / server application)
#Region  Project Attributes
    #CommandLineArgs:
    #MergeLibraries: True
#End Region

#AdditionalJar: bluecove-gpl-2.1.1-SNAPSHOT
#AdditionalJar: bluecove-bluez-2.1.1-SNAPSHOT

Sub Process_Globals
    'variables for connection
    Private bt As Bluetooth
    Private astream As AsyncStreams                'connection to tablet
    Private connected As Boolean=False            'bt connection or not
    Private rcvStr As String                    'data received

    'variables for motor control
    Type State (MotorOutput1 As Boolean, MotorOutput2 As Boolean, MotorOutput3 As Boolean, MotorOutput4 As Boolean)
    Private timer1 As Timer
    Private controller As GpioController
    Private mA, mB, mAA, mBB, MotorEnable, RPiStatus As GpioPinDigitalOutput
    Private states As List
    Private currentStateIndex As Int
    Private CW As Boolean=True
    Private StepDelay As Int
    Private SlowSpeed As Int=500
    Private FastSpeed As Int=50
    Private shl As Shell
    Private Feedback As String

    'Variables for windsonic
    Private bstream As AsyncStreams                'connection to windsonic
    Private myserial As Serial                    'serial port for windsonic
    Private uart_list As List                    'list of ports
    Private WSDataNotRequired As Boolean=True    'WS data is only required in sensor mode
End Sub

Sub AppStart (Args() As String)
    controller.Initialize
    MotorEnable.Initialize(0, False)
    RPiStatus.Initialize(1, False)        'prepare green LED to show ready status of RPi
    mA.Initialize(2, False)                'white        A        * Color coding for my motor, 6 pin *
    mAA.Initialize(3, False)            'red        A'
    mB.Initialize(4, False)                'blue        B
    mBB.Initialize(5, False)            'yellow        B'

    ' * Color coding for my 8 pin motor *
    ' red                                        A
    ' red/white shorted with black/white
    ' black                                        A'
    ' green                                        B
    ' yellow/white sorted with green/white
    ' yellow                                    B'

    StepDelay=10
    states.Initialize
    states.Add(CreateState(True, True, False, False))
    states.Add(CreateState(False, True, True,False))
    states.Add(CreateState(False, False, True, True))
    states.Add(CreateState(True, False, False, True))

    'prepare timer for mtor control
    timer1.Initialize("timer1", StepDelay)
    timer1.Enabled = False
   
    If CW=True Then
           currentStateIndex = states.Size 'it will be incremented in Timer1_Tick
    Else
        currentStateIndex=-1
    End If
   
    'Timer1_Tick 'start with the first state
   
    'Start bluetooth
    bt.Initialize("bt")
    If bt.IsEnabled = False Then
        Log("Bluetooth not available1")
        ExitApplication
    End If

    RPiStatus.State=True    ' turn on green LED to show ready status of RPi

    Log($"My address: ${GetBluetoothAddress}"$)
    Log("***************************************************************************")
    bt.Listen        'bt_Connected is called when connection is made

    StartMessageLoop
End Sub

' Called when a command is received from tablet
Sub astream_NewData (Buffer() As Byte)
    rcvStr = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    Log("***************************************************************************")
    Log("Received command: " & rcvStr)
    Log("***************************************************************************")

    If connected=False Then Return    'cannot react to commands without connection

    'Here we react to the commands from the tablet
    'Motor and RPi commands
#Region
    Select rcvStr
        Case "forward"
            CW=True
            StepDelay=SlowSpeed
            timer1.Interval=StepDelay
            MotorEnable.State=True            'activate motor
            timer1.Enabled=True
        Case "fastforward"
            CW=True
            StepDelay=FastSpeed
            timer1.Interval=StepDelay
            MotorEnable.State=True
            timer1.Enabled=True
        Case "back"
            CW=False
            StepDelay=SlowSpeed
            timer1.Interval=StepDelay
            MotorEnable.State=True
            timer1.Enabled=True
        Case "fastback"
            CW=False
            StepDelay=FastSpeed
            timer1.Interval=StepDelay
            MotorEnable.State=True
            timer1.Enabled=True
        Case "stop"                            'de-activate motor
            timer1.Enabled=False
            MotorEnable.State=False           
        Case "reboot"                        'reboot the RPi
            astream_Terminated                'reset GPIO
            astream.Close
            myserial.Close
            shl.Initialize("shl", "reboot", Array As String())
            shl.Run(-1)
        Case "shutdown"
            astream_Terminated                'reset GPIO
            astream.Close
            bstream.Close
            myserial.Close
            shl.Initialize("shl", "halt", Array As String())
            shl.Run(-1)
#End Region

        Case "MotorMode"
            WSDataNotRequired=True
            'bstream.Close                       
            'myserial.Close   
        Case "SensorMode"
            WSDataNotRequired=False
            ' Open com port for windsonic data
            If bstream.IsInitialized Then Return
            myserial.Initialize("")
            uart_list = myserial.ListPorts
            Dim Myport As Int
            'Log("UART List: " & uart_list)
            Myport=uart_list.IndexOf("/dev/ttyUSB0")
            myserial.Open(uart_list.Get(Myport))
            myserial.SetParams(9600,8,1,0)
            Log("Com Port Initialized:" & uart_list.Get(Myport))
            bstream.Initialize(myserial.GetInputStream,Null,"bstream")
                                       
    End Select

' speed commands
#Region
    If rcvStr.Contains("SlowSpeed")    Then             'change slow speed, high time value command format: SlowSpeed 100
            Dim lines() As String
            lines=Regex.Split(" ", rcvStr)
            SlowSpeed=lines(1)
            Log("SlowSpeed set to " & SlowSpeed)
    End If

    If rcvStr.Contains("FastSpeed")    Then            'change fast speed, low time value
            Dim lines() As String
            lines=Regex.Split(" ", rcvStr)
            FastSpeed=lines(1)
            Log("FastSpeed set to " & FastSpeed)
    End If
#End Region

End Sub

' Called when com port gets new data from windsonic
Sub bstream_NewData (Buffer() As Byte)
     If WSDataNotRequired=True Then Return                                'ignore data coming from windsonic
    rcvStr = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    Log("Sensor Data: " & rcvStr)
    astream.Write(rcvStr.GetBytes("UTF8"))                                'write to tablet
End Sub

'move motor
Sub Timer1_Tick
    If CW=False Then
           currentStateIndex=currentStateIndex-1
        If currentStateIndex=-1 Then currentStateIndex = states.Size-1
    Else
        currentStateIndex = (currentStateIndex + 1) mod states.Size
    End If

    Dim st As State = states.Get(currentStateIndex)
    mA.State = st.MotorOutput1
    mB.State = st.MotorOutput2
    mAA.State = st.MotorOutput3
    mBB.state = st.MotorOutput4

    Feedback="step " & CW                            'Comand=STEP TRUE or STEP FALSE
    Feedback=Feedback.ToUpperCase
    Log(Feedback)

    astream.Write(Feedback.GetBytes("UTF8"))        'send step command to tablet
End Sub

'setup states in a list
Sub CreateState(Motor1 As Boolean, Motor2 As Boolean, Motor3 As Boolean, Motor4 As Boolean) As State
   ' Motor connection A  B  A'  B'
   Dim st As State
   st.Initialize
   st.MotorOutput1 = Motor1
   st.MotorOutput2 = Motor2
   st.MotorOutput3 = Motor3
   st.MotorOutput4 = Motor4
   Return st
End Sub

' If bt is connected, setup astream to tablet
Sub bt_Connected (Success As Boolean, Connection As BluetoothConnection)
    If Success Then
        If astream.IsInitialized Then
            astream.Close
        End If
        Log($"Connected to: ${Connection.Name} - ${Connection.MacAddress}"$)
        Log("***************************************************************************")
   
        'astream is the connection to tablet, works in both directions.
        astream.Initialize(Connection.InputStream, Connection.OutputStream, "astream")
        bt.Listen
        connected=True
    Else
        Log("Error connecting...")
    End If
End Sub

'Trap errors
Sub astream_Error
    astream_Terminated
End Sub

Sub astream_Terminated
    'bluetooth connection has been lost, reset the GPIO
    RPiStatus.State=False
    MotorEnable.State=False
    mA.State=False           
    mAA.State=False       
    mB.State=False           
    mBB.State=False
    Log("GPIO has been reset!")

End Sub

Sub GetBluetoothAddress As String
    Dim jo As JavaObject = bt
    Dim raw As String = jo.GetFieldJO("device").RunMethod("getBluetoothAddress", Null)
    Dim sb As StringBuilder
    sb.Initialize
    For i = 0 To raw.Length - 1 Step 2
        If sb.Length > 0 Then sb.Append(":")
        sb.Append(raw.SubString2(i, i + 2))
    Next
    Return sb.ToString
End Sub

Just to complete the project, a few screenshots from the tablet and the code.

Screen1.png


Screen2.png


Screen3.png


B4X:
#Region  Project Attributes
    #ApplicationLabel: Buggy remote Windsonic
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: landscape
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim astream As AsyncStreams
    Dim serial1 As Serial
    Dim connected As Boolean =False
    Dim Timer1 As Timer
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    '
    'These variables are used for the motor control
    Dim btn_connect As Button
    Dim btn_Quit As Button
    Dim iv_back As ImageView
    Dim iv_fback As ImageView
    Dim iv_fforward As ImageView
    Dim iv_forward As ImageView
    Dim iv_stop As ImageView
    Dim btn_HaltRpi As Button
    Dim btn_RebootRPi As Button
    Dim btn_Zero As Button
    Dim Label4 As Label
    Dim lbl_Distance As Label
    Dim lbl_MaxDistance As Label
    Dim lbl_MinDistance As Label
    Dim sb_Distance As SeekBar
    Dim btn_Sensor As Button
    Dim rcvStr As String
    Dim BuggyPosition As Int=0
    Dim btn_SendFast As Button
    Dim btn_SendSlow As Button
    Dim edt_Fast As EditText
    Dim edt_Slow As EditText
    Dim lbl_SpeedFast As Label
    Dim lbl_SpeedSlow As Label
    Dim  st, ft As Int
    Dim  ss, fs As Double
 
    '
    'These variables are used for the data and graph
    Dim pnlData As Panel
    Dim btn_CreateNewFile As Button
    Dim btn_Motor As Button
    Dim btn_StartStop As Button
    Dim Label1 As Label
    Dim Label2 As Label
    Dim Label4 As Label
    Dim Label5 As Label
    Dim Label6 As Label
    Dim lbl_Connected As Label
    Dim lbl_Direction As Label
    Dim lbl_ElapsedTime As Label
    Dim lbl_FileName As Label
    Dim lbl_LoggerStatus As Label
    Dim lbl_Speed As Label
    Dim LogFilename As String
    Dim FileDirectory As String
    Dim StartTime As Long
    Dim ElapsedTime As String
    Dim Writer As TextWriter
    Dim NewFileCreated As Boolean=False
    Dim rcvStr As String
     
 
    ' These are required for the graph
    Dim pnlGraph As Panel
    Dim bufsize As Int = 20                                   'set the data buffer size here i.e how many values to display in the plot area was 180
    Dim xlab(bufsize) As String
    Dim lc1 As RealTimeLineChart
    Dim xlabeltrack As Int = 0
     
    Dim DebugMode As Boolean=True
    Dim btn_Debug As ToggleButton
    Dim pnlMenu As Panel
    Dim btnGraph As Button
    Dim Label7 As Label
    Dim LoggerStatus As Boolean=False
    Dim pnl_back As Panel
    Dim pnl_fback As Panel
    Dim pnl_fforward As Panel
    Dim pnl_forward As Panel
    Dim pnl_stop As Panel
    Dim OneStep As Double=1.195        ' mm per step rotation
    Dim motorsteps As Int=0            'used to debug distance
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    Activity.LoadLayout("layout1")
    pnlData.Initialize("")
    Activity.AddView(pnlData,0,0,Activity.Width,Activity.Height)    'add data panel to screen
    pnlData.LoadLayout("layout2")                                    'load data screen into panel
    pnlData.Visible=False                                            'and hide it.
 
    If serial1.IsInitialized Then serial1.Disconnect
 
    If FirstTime Then
        serial1.Initialize("serial")                        'prepare serial connection via bluetooth
        Timer1.Initialize("timer1",1000)
    End If
 
    btn_connect.TextColor=Colors.red                        'set not connected
    lbl_Distance.Text=BuggyPosition
 
    btn_Debug.Checked=DebugMode
 
    'set default timings
    st=45
    edt_Slow.Text=st
'    ss=(1000/st)*OneStep/10
    ss=CalcSpeed(st)
    lbl_SpeedSlow.Text=NumberFormat(ss,1,2) & " cm/s"
 
    ft=15
    edt_Fast.Text=ft
'    fs=(1000/ft)*OneStep/10
    fs=CalcSpeed(ft)
    lbl_SpeedFast.Text=NumberFormat(fs,1,2) & " cm/s"
 
    'Setup data screen
    PrepareDataScreen
 
    pnl_stop.Color=Colors.Green
 
End Sub

Sub CalcSpeed (s As Double) As Double
    Return (1000/s)*OneStep/10
End Sub


' Connect via bluetooth - done
Sub btn_connect_Click
    Log("Button connect")
    If connected=False Then
        Try
        ' Get a map of the paired devices
        Dim PairedDevices As Map
        PairedDevices = serial1.GetPairedDevices
        Dim l As List
        l.Initialize
        For i = 0 To PairedDevices.Size - 1
              l.Add(PairedDevices.GetKeyAt(i))
        Next
        Dim Res As Int
        Res = InputList(l, "Choose device", -1) 'show list with paired devices
        If Res <> DialogResponse.CANCEL Then
            Log("Trying to connect to " & PairedDevices.Get(l.Get(Res)))
              serial1.Connect(PairedDevices.Get(l.Get(Res))) 'convert the name to mac address and connect
        End If
        Catch
            Log(LastException)
            ToastMessageShow(LastException.Message, True)
        End Try
 
    End If 
End Sub

' If bluetooth serial connect is successfull, then open stream and update UI - done
Sub Serial_Connected (Success As Boolean)
    Log($"Connected ${Success}"$)
    If Success Then
        If astream.IsInitialized Then astream.Close
        astream.Initialize(serial1.InputStream, serial1.OutputStream, "astream")
        connected = True
        Log("Stream opened")
        btn_connect.TextColor=Colors.Green
    Else
        Msgbox("Bluetooth connection failed.","Error") 
    End If
 
End Sub

' ****************************************************************
' Buggy controls - done
#Region
Sub iv_forward_Click
    If astream.IsInitialized=False Then Return
    astream.Write("forward".GetBytes("UTF8"))
    Log("Sent command: forward")
    ResetImageBorder
    pnl_forward.Color=Colors.Green
End Sub

Sub iv_fforward_Click
    If astream.IsInitialized=False Then Return
    astream.Write("fastforward".GetBytes("UTF8"))
    Log("Sent command: fastforward")
    ResetImageBorder
    pnl_fforward.Color=Colors.Green
End Sub

Sub iv_fback_Click
    If astream.IsInitialized=False Then Return
    astream.Write("fastback".GetBytes("UTF8"))
    Log("Sent command: fastback")
    ResetImageBorder
    pnl_fback.Color=Colors.Green
End Sub

Sub iv_back_Click
    If astream.IsInitialized=False Then Return
    astream.Write("back".GetBytes("UTF8"))
    Log("Sent command: back")
    ResetImageBorder
    pnl_back.Color=Colors.Green
End Sub

Sub iv_stop_Click
    If astream.IsInitialized=False Then Return
    astream.Write("stop".GetBytes("UTF8"))
    Log("Sent command: stop")
    ResetImageBorder
    pnl_stop.Color=Colors.Green
'    Log("Steps moved: " & motorsteps)
End Sub

Sub ResetImageBorder
    pnl_forward.Color=Colors.red
    pnl_fforward.Color=Colors.red
    pnl_fback.Color=Colors.red
    pnl_back.Color=Colors.red
    pnl_stop.Color=Colors.red
End Sub

#End Region
'RPi commands - done
#Region     
' Reboot the RPi
Sub btn_RebootRPi_Click
    If astream.IsInitialized=False Then Return                    'cannot reboot without a connection
    Dim result As Int
    result=Msgbox2( "Reboot RPi?","Confirmation required.","Yes","","No",Null)
    If result=DialogResponse.NEGATIVE Then
        Return
    End If
    astream.Write("reboot".GetBytes("UTF8"))
    Log("Sent command: reboot RPi")
    btn_connect.TextColor=Colors.red
    'tidy up
    If astream.IsInitialized Then astream.Close
    If serial1.IsInitialized Then serial1.Disconnect
End Sub

' Shutdown the RPi
Sub btn_HaltRpi_Click
    If astream.IsInitialized=False Then Return
    Dim result As Int
    result=Msgbox2( "Shutdown RPi?","Confirmation required.","Yes","","No",Null)
    If result=DialogResponse.NEGATIVE Then
        Return
    End If
    astream.Write("shutdown".GetBytes("UTF8"))
    Log("Sent command: shutdown RPi")
    btn_connect.TextColor=Colors.red
    'tidy up
    If astream.IsInitialized Then astream.Close
    If serial1.IsInitialized Then serial1.Disconnect
End Sub

' Change the slow speed
Sub edt_Slow_EnterPressed
    st=edt_Slow.Text
    If st<ft Or st>45 Then
        ToastMessageShow("Slow speed cannot be less than fast speed or is too slow...using default",False)
        edt_Slow.Text="45"
        st=edt_Slow.Text
    End If
    ss=CalcSpeed(st)
    lbl_SpeedSlow.Text=NumberFormat(ss,1,1) & " cm/s"
End Sub

' Change the fast speed
Sub edt_Fast_EnterPressed
    ft=edt_Fast.Text
    If ft>st Or ft<15 Then
        ToastMessageShow("Fast speed MUST be less than slow speed or is too fast...using default",False)
        edt_Fast.Text="15"
        ft=edt_Fast.Text
    End If
    fs=CalcSpeed(ft)
    lbl_SpeedFast.Text=NumberFormat(fs,1,1) & " cm/s"
End Sub

' Send new spped to RPi
Sub btn_SendSlow_Click
    If astream.IsInitialized=False Then Return
    Dim t As String
    t="SlowSpeed " & st
    astream.Write(t.GetBytes("UTF8"))
    Log("Sent command: " & t)
End Sub

' Send new spped to RPi
Sub btn_SendFast_Click
    If astream.IsInitialized=False Then Return
    Dim t As String
    t="FastSpeed " & ft
    astream.Write(t.GetBytes("UTF8"))
    Log("Sent command: " & t)
End Sub

#End Region

'click events for buttons

' Set current position to zero
Sub btn_Zero_Click
    Dim result As Int
    result=Msgbox2( "Reset position to zero?","Confirmation required.","Yes","","No",Null)
    If result=DialogResponse.NEGATIVE Then
        Return
    End If
    BuggyPosition=0
    lbl_Distance.Text=NumberFormat(BuggyPosition/1000,1,1)
    sb_Distance.Value=NumberFormat(BuggyPosition/1000,1,0)
    motorsteps=0
End Sub

' Switch to sensor mode                                                                                    still to do!
Sub btn_Sensor_Click
    'switch to sensor data screen
    pnlData.Visible=True
    If connected=True Then
        lbl_Connected.Color=Colors.Green
        lbl_Connected.Text="Connected"
        astream.Write("SensorMode".GetBytes("UTF8"))            'activate windsonic
        Log("Sent command: " & "SensorMode")
    End If
    Timer1.Enabled=True
End Sub

' create new file based on date and time
Sub btn_CreateNewFile_Click
    lbl_FileName.Text=CreateFileName
    NewFileCreated=True 
End Sub

' create a filename from date and time
Sub CreateFileName () As String
    Dim d, t As String  
    DateTime.DateFormat = "yyyyMMdd"
    DateTime.TimeFormat="HHmm"
    d = DateTime.Date(DateTime.Now)
    t = DateTime.Time(DateTime.Now)
       LogFilename= d & "-" & t & ".txt"
    Return LogFilename
End Sub

' Start logger
Sub btn_StartStop_Click
    ' Cannot start looger if we are not connected or no filename
    If NewFileCreated=False Then
        Msgbox("Please create a file first!.","Error")
        Return
    End If
 
    If connected=False Then
        Msgbox("In debug mode, data cannot be logged!","Error")
        Return
    End If
     
    If LoggerStatus=False Then                                                    'Logger is off, turn on
        LoggerStatus=True                                                 
        lbl_LoggerStatus.Color=Colors.Green                                        'change background color
        btn_StartStop.Text="Stop Logger"                                        'change button text
        Timer1.Enabled=True                                                        'start timer
        DateTime.TimeFormat="HH:mm:ss"
        StartTime=DateTime.Now                                                    'Store start time for logger
        Writer.Initialize(File.OpenOutput(FileDirectory, LogFilename, True))    'Open stream for ascii file
        If DebugMode=True Then                                                     'make sure we do not log in debug mode
            DebugMode=False                                 
            btn_Debug.Checked=False
        End If
        ScreenShot 
    Else
        LoggerStatus=False
        lbl_LoggerStatus.Color=Colors.Red
        btn_StartStop.Text="Start Logger"
        Writer.Close                                                                'Close logger file
        Timer1.Enabled=False
        Timer1.Enabled=True
    End If 
End Sub

'Turn on/off graph panel
Sub btnGraph_Click
    pnlGraph.Visible=Not(pnlGraph.Visible)
End Sub

Sub btn_Debug_CheckedChange(Checked As Boolean)
    If connected=False Then
        btn_Debug.Checked=True
        Return                    'Cannot switch to sensor when not connected
    End If 
 
    DebugMode=Not(DebugMode)
    btn_Debug.Checked=DebugMode
    If DebugMode Then
        Log("Debug Mode")
        LoggerStatus=False
        lbl_LoggerStatus.Color=Colors.Red
        btn_StartStop.Text="Start Logger"
        If LoggerStatus Then Writer.Close                                                                'Close logger file if we are logging
        Timer1.Enabled=False
        Timer1.Enabled=True
    Else
        Log("Sensor Mode")
    End If
End Sub

'return to buggy control
Sub btn_Motor_Click
    Dim result As Int
    result=Msgbox2("Return to buggy control?","Confirmation required.","Yes","","No",Null)
    If result<>DialogResponse.POSITIVE Then
        Return
    End If
 
    If connected=True Then
        astream.Write("MotorMode".GetBytes("UTF8"))
        Log("Sent command: " & "MotorMode")
 
        ' reset to debug mode
        If LoggerStatus Then Writer.Close                                            'Close logger file
        LoggerStatus=False
        lbl_LoggerStatus.Color=Colors.Red
        btn_StartStop.Text="Start Logger"
     
        If DebugMode=False Then                                                     'make sure we do not log in debug mode
            DebugMode=True                                                            'timer1 can continue as we are in debug mode                         
            btn_Debug.Checked=True
        End If
        NewFileCreated=False                                                        'reset new file
    End If
 
    pnlData.Visible=False
End Sub

Sub btn_Quit_Click
Dim result As Int
    result=Msgbox2( "Do you really want to exit?","Confirmation required.","Yes","","No",Null)
    If result=DialogResponse.NEGATIVE Then
        Return
    End If
    If astream.IsInitialized Then astream.Close
    If serial1.IsInitialized Then serial1.Disconnect
    Activity.Finish
End Sub

' ****************************************************************
' End of commands
' ****************************************************************

' Called when data is received from RPi
' RPi sends a step command when a step is made or it sends data
Sub astream_NewData (Buffer() As Byte)
    rcvStr = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
 
    Select rcvStr
        Case "STEP TRUE"
            Log("moved forward")
            BuggyPosition=BuggyPosition+OneStep
            lbl_Distance.Text=NumberFormat(BuggyPosition/10,1,1) & " cm"
            sb_Distance.Value=NumberFormat(BuggyPosition/10,1,0)
            motorsteps=motorsteps+1
            Log("Steps moved: " & motorsteps)
'            If BuggyPosition>500 Then
'                ToastMessageShow("Forward movement limited to 500cm!",True)
'                iv_stop_Click
'            End If
        Case "STEP FALSE"
            Log("moved back")
            BuggyPosition=BuggyPosition-OneStep
            lbl_Distance.Text=NumberFormat(BuggyPosition/10,1,1) & " cm"
            sb_Distance.Value=NumberFormat(BuggyPosition/10,1,0)
            motorsteps=motorsteps-1
            Log("Steps moved: " & motorsteps)
'            If BuggyPosition<0 Then
'                ToastMessageShow("Cannot move less than 0cm!",True)
'                iv_stop_Click
'            End If
        Case Else
            ' otherwise we have received data from the windsonic
            'Log("Received data: " & rcvStr)
            If DebugMode=False Then                                    'only update if we are in sensor mode
                Dim lines() As String
                lines=Regex.Split(",", rcvStr)
                If lines.Length=6 Then
                    lbl_Speed.Text=lines(2)
                    lbl_Direction.Text=lines(1)
                End If
            End If
    End Select
         
End Sub

' Used in demo mode AND real mode. Calc elapsed time, update UI
Sub Timer1_Tick
    '**************************************************************************************************************
    If DebugMode Then                                                ' use random data
        lbl_Speed.Text=NumberFormat(Rnd(100,200)/100,0, 2)            'speed between 1 and 2 m/s
        lbl_Direction.Text=Rnd(180,360)                                'direction between 180 and 360 degrees
 
    '**************************************************************************************************************
    Else
        If LoggerStatus=True Then
            Dim t, String1 As String  
                DateTime.TimeFormat="HH:mm:ss"
            t = DateTime.Time(DateTime.Now)
     
            ElapsedTime=ConvertTicksToTimeString(DateTime.Now-StartTime)    'calculate elapsed time
            lbl_ElapsedTime.Text=ElapsedTime                                'update UI
            'This is one line in text file
            String1=t & "," & ElapsedTime & "," & lbl_Speed.Text & "," & lbl_Direction.Text & "," & lbl_Distance.Text & Chr(13)
            Log(String1)
            Writer.WriteLine(String1)                                        'write to file
        End If
    End If
 
    '**************************************************************************************************************
    ' chart code
#Region      
    Dim Speed, Direction As Float
    Speed=lbl_Speed.Text
    Direction=lbl_Direction.Text/180
    lc1.addData(Speed,Direction,0,0,0)
 
    '   If xlabeltrack = bufsize + 1 Then
'         t.Enabled = False
'      lc1.ClearAllData                        'THIS WILL CLEAR THE DATA
'   End If
'************************ If you comment this code then the x-axis labels will be the index of the buffer
   xlabeltrack = xlabeltrack + 1
   If xlabeltrack > bufsize Then
         xlab = shiftarray(xlab)
      xlab(bufsize - 1) = "x-" & xlabeltrack
      lc1.XAxisLabels = xlab
   End If
   xlab(bufsize - 1) = "x-" & xlabeltrack
'**************************************************************************************************************
#End Region
End Sub

Sub astream_Error
    astream_Terminated
End Sub

Sub astream_Terminated
    'oops we lost the bluetooth connection
    Msgbox("Bluetooth connection lost","Error")
    'Try and reconnect
    If serial1.IsInitialized Then
        serial1.Disconnect
        'serial1.Connect(txtMAC)
    End If
    btn_connect.TextColor=Colors.red
End Sub

Sub Activity_Resume
    Log("Serial1 is initialised: " & serial1.IsInitialized)
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub PrepareGraph
    lc1.GraphTitleColor = Colors.White
    lc1.GraphTitleSkewX = -0.15
    lc1.GraphTitleBold = True
    lc1.GraphTitleTextSize = 20.0
    lc1.GraphPlotAreaBackgroundColor = Colors.DarkGray          'this will paint the plotting area DarkGray regardless of what GraphBackgroundColor has been set to
    lc1.GraphBackgroundColor = Colors.Transparent               'this will paint everything within the outer frame to be white
    lc1.GraphFrameColor = Colors.Red                            'this adjusts only the outer frame color
    lc1.GraphFrameWidth = 2.0
    lc1.GraphBufferSize = bufsize
    lc1.GraphTitle = "Real Time Data"

    lc1.DomainLabelColor = Colors.Cyan
    lc1.DomainLabelTextSize = 20
    lc1.DomianLabel = ""
 
    lc1.YaxisRangeMode = lc1.YaxisMode_FIXED                    'the other option is FIXED
    lc1.YaxisRange(0, 2)
    lc1.YaxisDivisions = 4
    lc1.YaxisLabelTicks = 1
    lc1.YaxisShowZero = True
    lc1.YaxisTitleTextSize = 20.0
    lc1.YaxisTitleColor = Colors.Green
    lc1.YaxisGridLineColor = Colors.Yellow
    lc1.YaxisLabelTextSize = 15
    lc1.YaxisLabelColor = Colors.Green
    lc1.YaxisLabelOrientation = 0
    lc1.YaxisTitle = "[m/s]"
 

'************************ If you comment this code then the x-axis labels will be the index value of the buffer
'    For i = 0 To bufsize - 1
'        'xlab(i) = "x-" & i
'        xlab(i) = TimeInSeconds
'    Next
'    lc1.XAxisLabels = xlab
'*************************************************************************************************************
    
    lc1.XaxisLabelTextSize = 15
    lc1.XaxisLabelTextColor = Colors.Cyan
    lc1.XaxisGridLineColor = Colors.Yellow
    lc1.XaxisLabelOrientation = 0
    lc1.XaxisDivisions = 19    'was 59
    lc1.XaxisLabelTicks = 19


    lc1.LegendTextSize = 15.0
    lc1.LegendTextColor = Colors.White
    lc1.LegendBackgroundColor = Colors.Transparent

    'setup for Line 1
    lc1.Line_1_LineColor = Colors.green
    lc1.Line_1_LineWidth = 2.0
    lc1.Line_1_DrawDash = True
    lc1.Line_1_LegendText = "Speed"
 
    'setup for Line 2 
    lc1.Line_2_LineColor = Colors.red
    lc1.Line_2_LineWidth = 2.0
    lc1.Line_2_DrawDash = False
    lc1.Line_2_LegendText = "Direction /180"
 
    lc1.NumberOfLineCharts = 2
    lc1.DrawTheGraphs

End Sub

'required for graph
Sub shiftarray (oldarray() As String) As String()
    Dim newarray(bufsize)
    For i = 0 To bufsize - 2
        newarray(i) = oldarray(i + 1)
    Next
    Return newarray
End Sub

' Used to calc elapsed time
Sub ConvertTicksToTimeString(t As Long) As String
    Dim  hours, minutes, seconds As Int
    hours = t / DateTime.TicksPerHour
    minutes = (t Mod DateTime.TicksPerHour) / DateTime.TicksPerMinute
    seconds = (t Mod DateTime.TicksPerMinute) / DateTime.TicksPerSecond
    'TimeInSeconds=(hours*3600)+(minutes*60)+seconds
    Return NumberFormat(hours, 2, 0) & ":" _
        & NumberFormat(minutes, 2, 0) & ":" & NumberFormat(seconds, 2, 0)
End Sub

' Make a screenshot with date and time stamp
Sub ScreenShot
    ' Take a screenshot.
    Dim Obj1, Obj2 As Reflector
    Dim bmp As Bitmap
    Dim c As Canvas
    Dim Fname As String

    Obj1.Target = Obj1.GetActivityBA
    Obj1.Target = Obj1.GetField("vg")
    bmp.InitializeMutable(Activity.Width, Activity.Height)
    c.Initialize2(bmp)
    Dim args(1) As Object
    Dim types(1) As String
    Obj2.Target = c
    Obj2.Target = Obj2.GetField("canvas")
    args(0) = Obj2.Target
    types(0) = "android.graphics.Canvas"
    Obj1.RunMethod4("draw", args, types)
    Dim Out As OutputStream
    Fname=CreateFileName
    Fname=Fname.Replace(".txt", ".png")
    Out = File.OpenOutput(File.DirRootExternal, Fname, False)
    bmp.WriteToStream(Out, 100, "PNG")
    Out.Close
End Sub

Sub PrepareDataScreen
    ' Make directory to hold logger files
    If File.IsDirectory(File.DirRootExternal,"windsonic/") = False Then
        File.MakeDir(File.DirRootExternal,"windsonic")
        Log("Directory created!")
    End If
 
    pnlGraph.Visible=False
    FileDirectory=File.DirRootExternal & "/windsonic/"
    Log(FileDirectory)
    lbl_LoggerStatus.Color=Colors.Red
    lbl_FileName.Color=Colors.White
    lbl_FileName.TextColor=Colors.Black
    lbl_FileName.Text="Please create new file to start"
    lbl_Speed.Color=Colors.White
    lbl_Speed.TextColor=Colors.Black
    lbl_Direction.Color=Colors.White
    lbl_Direction.TextColor=Colors.Black
    lbl_ElapsedTime.Color=Colors.White
    lbl_ElapsedTime.TextColor=Colors.Black
 
    Activity.Title="Windsonic Datalogger Version 1"
    PrepareGraph
 
    If DebugMode Then
        DateTime.TimeFormat="HH:mm:ss"
        StartTime=DateTime.Now
        'Timer1.Enabled=True
    End If
 
    lc1.START                                                    'Start graph
End Sub

The complete B4A code is in the zip file.
 

Attachments

  • B4A-Code.zip
    139.8 KB · Views: 231
Last edited:
Top