Pictures and videos

Here are som pictures and videos of the robot:

Youtube video

The case

In order to validate if the idea about cross-cutting transitions (or global transitions) is better in terms of lower complexity in the state machine two master students where given the assignment to program a robot in ThingML. The robot is Arduino controlled, it have a mortor shield, two dc motors, three bumper sensors, three range sensors, a sound module, two speakers and a lot of LEDs.

The robot is suposed to go forward and adjust the speed depending on the range to the object in front. If it senses things from the sides it shall divert and go in an oposite direction. If the robot crash it should back up a little, find a new direction and make some sound to signal that it is not happy with crashing. The LEDs can be used as the students want.

The solutions

The students where given a precode with all the sensors and things implemented and what they had to do was to define the states, the actions in the states and the transitions. By combining these three elements the behaviour of the robot can be defined.

In the first part of the case study the two master students wrote their own implementation of the robot. The first students program had eigth states and 28 transitions, the source can be seen here:

Student 1 first program
import "Devices/RangeSensor2.thingml"
import "Devices/MotorShieldDFduino.thingml"
import "Devices/LightResitorArray.thingml"
import "Devices/somo-14d.thingml"
import "Devices/Bumper.thingml"
import "../../../core/timer.thingml"
import "Devices/LightChain.thingml"

thing BigRobot includes RangeMsgs, MotorShieldMsgs, TimerMsgs, LightArrayMsgs, SoundMsgs, BumperMsgs, LightChainMsgs {

    required port Sounds{
        sends r2d2
        //sends chrash
        //sends happy
        //sends cranky
        //sends set_sound //set sound with 1 2 3 or 4
        //sends play_set_sound
        sends stop_sound    
    }

    required port Bumper {
        receives bump
    }

    required port LightIn{
        receives forward_dir    
        receives left_dir               
        receives right_dir
        receives dont_know_dir  
    }

    required port Motor {
        sends forward_fast
        //sends forward_medium
        sends forward_slow
        sends stop
        //sends backwards_fast
        sends backward_slow
        sends right
        sends left
        //sends set_motors_speed
    }

    required port Timer{
        sends timer_start
        receives timer_timeout
    }

    required port Robot {
        sends get_range
        receives range
    }

    required port Light{
        sends start_green
        sends start_blue
        sends stop_green
        sends stop_blue 
        sends blink
        //sends fade_blue
        //sends fade_green
        sends start_crazy
        sends stop_crazy
    }

    property range : UInt16 = 0

    statechart BigRobotImpl init idle {

        state idle {
            on entry do
                Timer!timer_start(500)
                Motor!stop()
                Light!stop_crazy()
                Sounds!stop_sound()
            end

            transition -> run
            event Timer?timer_timeout
        }

        state run{
                transition -> forward
                event LightIn?forward_dir               
                transition-> stop
                event LightIn?dont_know_dir 
                transition -> crashed
                event Bumper?bump
                transition -> left
                event LightIn?left_dir
                transition -> right
                event LightIn?right_dir
        }

        state forward {
                on entry do
                        if(range > 75) do 
                                Motor!forward_fast()
                                Light!stop_green()
                                Light!stop_blue()
                        end

                        if(range > 25 and range < 75) do
                                Motor!forward_slow()
                                Light!stop_blue()
                                Light!start_green()
                        end
                end

                on exit do
                        Light!stop_green()
                        Light!stop_blue()
                end

                transition-> stop
                event  LightIn?forward_sir
                guard range < 25
                transition -> forward
                event LightIn?forward_dir
                transition-> stop
                event LightIn?dont_know_dir
                transition -> crashed
                event Bumper?bump
                transition -> left
                event LightIn?left_dir
                transition -> right
                event LightIn?right_dir
         }

         state stop {
                on entry do
                        Light!start_crazy()
                        Sounds!r2d2 ()
                        if(range < 15) do
                                Motor!stop()
                        end
                end

                on exit do
                        Light!stop_crazy()
                end

                transition -> forward
                event LightIn?forward_dir
                transition-> stop
                event LightIn?dont_know_dir 
                transition -> crashed
                event Bumper?bump
                transition -> left
                event LightIn?left_dir
                transition -> right
                event LightIn?right_dir
         }

        state left {
                on entry do
                        Motor!left()
                end

                transition -> forward
                event LightIn?forward_dir
                transition-> stop
                event LightIn?dont_know_dir 
                transition -> crashed
                event Bumper?bump
                transition -> left
                event LightIn?left_dir
                transition -> right
                event LightIn?right_dir
        }

        state right {
                on entry do
                        Motor!right()
                end

                transition -> forward
                event LightIn?forward_dir
                transition-> stop
                event LightIn?dont_know_dir 
                transition -> crashed
                event Bumper?bump
                transition -> left
                event LightIn?left_dir                  
                transition -> right
                event LightIn?right_dir
         }

         state crashed {

                property time : UInt16 = 0

                on entry do
                        time = 400
                        Timer!timer_start(time)
                        Light!start_crazy()
                        Motor!backward_slow()
                end

                internal event Timer?timer_timeout
                guard time == 400
                action do
                        time = 500
                        Timer!timer_start(time)
                        Motor!right()
                end

                transition -> run
                event Timer?timer_timeout
                guard time == 500
                action do
                        Motor!stop()
                        Light!stop_crazy()
                end
        }

        region Measure init MeasureDistance {
                state MeasureDistance{
                        on entry do
                           Robot!get_range()
                        end
                        internal event m : Robot?range
                        action do 
                                range = m.cm
                                Robot!get_range()
                        end
                }
            }
        }
}

Student 2's program contained 9 states and 23 transitions and the source code looks like this:

Student 2's first program

import "Devices/RangeSensor2.thingml"
import "Devices/MotorShieldDFduino.thingml"
import "Devices/LightResitorArray.thingml"
import "Devices/somo-14d.thingml"
import "Devices/Bumper.thingml"
import "../../../core/timer.thingml"
import "Devices/LightChain.thingml"

thing BigRobot includes RangeMsgs, MotorShieldMsgs, TimerMsgs, LightArrayMsgs, SoundMsgs, BumperMsgs, LightChainMsgs {

    required port Sounds{
        //sends r2d2
        sends chrash
        sends happy
        sends cranky
        sends set_sound //set sound with 1 2 3 or 4
        sends play_set_sound
        sends stop_sound
    }

    required port Bumper {
        receives bump
    }

    required port LightIn{
        receives forward_dir    
        receives left_dir               
        receives right_dir
        receives dont_know_dir  
    }   
    required port Motor {
        sends forward_fast
        sends forward_medium
        sends forward_slow
        sends stop
        sends backwards_fast
        sends backward_slow
        sends right
        sends left
        // sends set_motors_speed
    }

    required port Timer{
        sends timer_start
        receives timer_timeout
    }

    required port Robot {
        sends get_range
        receives range
    }

    required port Light{
        sends start_green
        sends start_blue
        sends stop_green
        sends stop_blue
        sends blink
        sends fade_blue
        sends fade_green
        sends start_crazy
        sends stop_crazy
    }

    property range : UInt16 = 0
    property rand : UInt16 = 0

        statechart BigRobotImpl init Stop {

            state Start{

                on entry do
                        Antenna!start () //er dette riktig?
                        Light!stop_crazy ()
                        Light!stop_blue ()
                        Light!start_green ()
                        Sounds!happy ()
                end

            transition -> Drivefast
            event LightIn?forward_dir
            guard range > 30
            transition -> Driveslow
            event  LightIn?forward_dir
            guard range < 30
            transition -> Turnleft
            event LightIn?left_dir
            transition -> Turnright
            event LightIn?right_dir 
            transition -> Stop
            event LightIn?dont_know_dir
        }

        state Stop {

            on entry do 
                Motor!stop ()
                Timer!timer_start (1000)
                Light!stop_green ()
                Light!stop_blue ()
                Light!stop_crazy ()
                Sounds!cranky ()
            end

            transition -> Start
            event Timer?timer_timeout
        } 

        state Drivefast {

            on entry 
                Motor!forward_fast ()
                Light!stop_blue ()
                Light!stop_crazy ()
                Light!start_green ()
            end

            transition -> Driveslow
            event LightIn?forward_dir
            guard range < 30
            transition -> Drivefast
            event LightIn?forward_dir
            transition -> Turnleft
            event LightIn?left_dir
            transition -> Turnright
            event LightIn?right_dir 
            transition -> Stop
            event LightIn?dont_know_dir
            transition -> Chrash
            event Bumper?bump
        }

        state Driveslow {

                on entry do 
                        Motor!forward_slow ()
                        Light!stop_blue ()
                        Light!stop_crazy ()
                        Light!start_green ()
                end

                transition -> Drivefast
                event LightIn?forward_dir
                guard range > 30
                transition -> Backwards
                event LightIn?forward_dir
                guard range < 20
                transition -> Driveslow
                event LightIn?forward_dir
                guard range < 30
                transition -> Turnleft
                event LightIn?left_dir
                transition -> Turnright
                event LightIn?right_dir 
                transition -> Stop
                event LightIn?dont_know_diR
                transition -> Chrash
                event Bumper?bump
        }


        state Chrash {

            on entry do
                Timer!timer_start (500)
                Motor!stop ()
                Sounds!chrash ()
                Light!stop_green ()
                Light!stop_blue ()
                Light!start_crazy ()                              
            end

            transition -> Backwards
            event Timer?timer_timeout
        } 

        state Backwards {

            on entry do 
                Timer!timer_start (750)
                Motor!backwards_fast ()
                Light!stop_crazy ()
                Light!stop_green ()
                Light!start_blue ()

                if (range < 20)
                    do 
                    Motor!backward_slow ()
                    Light!fade_blue ()
                 end

                rand = 'random(3);'
                if(rand == 1)do
                        rand = 'random(2);'
                        if (rand == 0) do
                                Motor!left ()
                        end
                        if(rand == 1) do
                                Motor!right ()
                        end
                end
            end

            transition -> Start
            event Timer?timer_timeout
        }


        state Turnleft {

                on entry do
                        Timer!timer_start (750)
                        Motor!left ()
                        Light!stop_crazy ()
                        Light!stop_green ()
                        Light!start_blue ()
                        Sounds!set_sound (1)
                        Sounds!play_set_sound ()
                end

           transition -> Start
           event Timer?timer_timeout
         }

        state Turnright {

                on entry do 
                        Timer!timer_start (750)
                        Motor!right ()
                        Light!stop_crazy ()
                        Light!stop_green ()
                        Light!start_blue ()
                        Sounds!set_sound (2)
                        Sounds!play_set_sound ()
                end

           transition -> Start
           event Timer?timer_timeout
        }

            region Measure init MeasureDistance {
                state MeasureDistance{
                        on entry do
                           Robot!get_range()
                        end
                        internal event m : Robot?range
                        action do 
                                range = m.cm
                                Robot!get_range() 
                        end
                }
            }
        }
}

Global transitions

After writing this code both students where introdused with the consept og global transitions, and they where asked to rewrite their programs in according to the new set of rules. Then both students could remove one state from their program, and they got a lot less transitions. Student 1 ended up with only seven transitions and student 2 ended up with eight transitions. This means that the cyclomatic complexity will be a lot lower for the new programs. Student 1's program can be viewed here:

Student 1's second program


import "Devices/RangeSensor2.thingml"
import "Devices/MotorShieldDFduino.thingml"
import "Devices/LightResitorArray.thingml"
import "Devices/somo-14d.thingml"
import "Devices/Bumper.thingml"
import "../../../core/timer.thingml"
import "Devices/LightChain.thingml"

thing BigRobot includes RangeMsgs, MotorShieldMsgs, TimerMsgs, LightArrayMsgs, SoundMsgs, BumperMsgs, LightChainMsgs {

    required port Sounds {
        sends r2d2
        //sends chrash
        //sends happy
        //sends cranky
        //sends set_sound //set sound with 1 2 3 or 4
        //sends play_set_sound
        sends stop_sound
    }

    required port Bumper {
        receives bump
    }

    required port LightIn{
        receives forward_dir    
        receives left_dir               
        receives right_dir
        receives dont_know_dir  
    }

    required port Motor {
        sends forward_fast
        //sends forward_medium
        sends forward_slow
        sends stop
        //sends backwards_fast
        sends backward_slow
        sends right
        sends left
        //sends set_motors_speed
    }

    required port Timer{
        sends timer_start
        receives timer_timeout
    }

    required port Robot {
        sends get_range
        receives range
    }

    required port Light {
        sends start_green
        sends start_blue
        sends stop_green
        sends stop_blue 
        sends blink
        //sends fade_blue
        //sends fade_green
        sends start_crazy
        sends stop_crazy
    }

    property range : UInt16 = 0

        statechart BigRobotImpl init idle {

                transitions LightIn?forward_dir {
                        (range > 25) -> forward
                        -> stop
                } crashed
                transitions LightIn?dont_know_dir {
                        -> stop
                } crashed
                transitions LightIn?left_dir {
                        -> left
                } crashed
                transitions LightIn?right_dir {
                        -> right
                } crashed
                transitions Bumper?bump {
                        -> crashed
                }

                state idle {

                        on entry do
                                Motor!stop()
                                Light!stop_crazy()
                                Sounds!stop_sound()
                        end
                }

                state forward {

                        on entry do
                                if(range > 75) do 
                                        Motor!forward_fast()
                                        Light!stop_green()
                                        Light!stop_blue()
                                end

                                if(range > 25 and range < 75) do
                                        Motor!forward_slow()
                                        Light!stop_blue()
                                        Light!start_green()
                                end
                        end

                        on exit do
                                Light!stop_green()
                                Light!stop_blue()
                        end
                }

                state stop {

                    on entry do
                        Light!start_crazy()
                        Sounds!r2d2 ()
                        if(range < 15) do
                                Motor!stop()
                        end
                    end

                    on exit do
                       Light!stop_crazy()
                    end
                }
                state left {

                        on entry do
                                Motor!left()
                        end
                }

                state right {

                        on entry do
                                Motor!right()
                        end
                }

                state crashed {

                        property time : UInt16 = 0

                        on entry do
                                time = 400
                                Timer!timer_start(time)
                                Light!start_crazy()
                                Motor!backward_slow()
                        end

                        internal event Timer?timer_timeout
                        guard time == 400
                        action do
                                time = 500
                                Timer!timer_start(time)
                                Motor!right()
                        end

                        transitions -> forward
                        event Timer?timer_timeout
                        guard time == 500
                        action do
                                Motor!stop()
                                Light!stop_crazy()
                        end
                }

                region Measure init MeasureDistance {
                        state MeasureDistance{
                                on entry do
                                        Robot!get_range()
                                end
                                internal event m : Robot?range
                                action do 
                                        range = m.cm
                                        Robot!get_range()
                                end
                        }
            }
        }
}

Student 2's improved program can be seen here:

Student 2's second program

import "Devices/RangeSensor2.thingml"
import "Devices/MotorShieldDFduino.thingml"
import "Devices/LightResitorArray.thingml"
import "Devices/somo-14d.thingml"
import "Devices/Bumper.thingml"
import "../../../core/timer.thingml"
import "Devices/LightChain.thingml"


thing BigRobot includes RangeMsgs, MotorShieldMsgs, TimerMsgs, LightArrayMsgs, SoundMsgs, BumperMsgs, LightChainMsgs {

    required port Sounds{
        //sends r2d2
        sends chrash
        sends happy
        sends cranky
        sends set_sound //set sound with 1 2 3 or 4
        sends play_set_sound
        sends stop_sound
    }

    required port Bumper {
        receives bump
    }

    required port LightIn{
        receives forward_dir    
        receives left_dir               
        receives right_dir
        receives dont_know_dir  
    }   
    required port Motor {
        sends forward_fast
        sends forward_medium
        sends forward_slow
        sends stop
        sends backwards_fast
        sends backward_slow
        sends right
        sends left
        // sends set_motors_speed
    }

    required port Timer{
        sends timer_start
        receives timer_timeout
    }

        required port Robot {
        sends get_range
        receives range
    }

    required port Light{
        sends start_green
        sends start_blue
        sends stop_green
        sends stop_blue
        sends blink
        sends fade_blue
        sends fade_green
        sends start_crazy
        sends stop_crazy
    }

    property range : UInt16 = 0
    property rand : UInt16 = 0

        statechart BigRobotImpl init Stop {

        transitions m : LightIn?forward_dir {
            (range > 30) -> Drivefast
            (range < 30) -> Driveslow
            (range < 20) -> Backwards 
                } Chrash
        transitions m : LightIn?left_dir {
            -> Turnleft, Chrash
        } 
        transitions m : LightIn?right_dir {
            -> Turnright, Chrash
        }   
        transitions m : LightIn?dont_know_dir {
            -> Stop, Chrash
        }    
        transitions m : Bumper?bump {
            -> Chrash
        }

        state Stop {

            on entry do 
                Motor!stop ()
                Light!stop_green ()
                Light!stop_blue ()
                Light!stop_crazy ()
                Sounds!cranky ()
            end
        } 

        state Drivefast {

            on entry do 
                Motor!forward_fast ()
                Light!stop_blue ()
                Light!stop_crazy ()
                Light!start_green ()
            end
        }

        state Driveslow {

            on entry do 
                Motor!forward_slow ()
                Light!stop_blue ()
                Light!stop_crazy ()
                Light!start_green ()
            end   
        }

        state Chrash {

            on entry do
                 Timer!timer_start (500)
                 Motor!stop ()
                 Sounds!chrash ()
                 Light!stop_green ()
                 Light!stop_blue ()
                 Light!start_crazy ()

            end
            transition -> Backwards
            event Timer?timer_timeout
        } 

        state Backwards {

            on entry do 
                Motor!backwards_fast ()
                Light!stop_crazy ()
                Light!stop_green ()
                Light!start_blue ()

                if (range < 20) do 
                    Motor!backward_slow ()
                    Light!fade_blue ()
                 end

                rand = 'random(3);'
                if(rand == 1) do
                        rand = 'random(2);'
                        if (rand == 0) do 
                                Motor!left ()
                        end
                        if(rand == 1) do
                                Motor!right ()
                        end
                end
            end
        }

        state Turnleft {

                on entry do
                        Motor!left ()
                        Light!stop_crazy ()
                        Light!stop_green ()
                        Light!start_blue ()
                        Sounds!set_sound (1)
                        Sounds!play_set_sound ()
                end
         }

        state Turnright {

                on entry do 
                        Motor!right ()
                        Light!stop_crazy ()
                        Light!stop_green ()
                        Light!start_blue ()
                        Sounds!set_sound (2)
                        Sounds!play_set_sound ()
                end
        }

                region Measure init MeasureDistance {
                state MeasureDistance{
                        on entry do
                             Robot!get_range()
                        end
                        internal event m : Robot?range
                        action do 
                                range = m.cm
                                Robot!get_range() 
                                end
                        }
            }
        }
}

The linecount in the second program dropped with aproximately with 20% for both students. This means that there is less code to write while using global transitions, and therefore the programs can be written faster and is easier to maintian over time.

Source code !!!!

Here is the complete source code to run the program yourself Attach:bigrobotsource.zip

Figure O1 !!

Figure O2 !!

Figure O3 !!

Figure O4 !!

Figure O5 !!

Figure O6 !!

Figure O7 !!