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 !!