Scouting: Add function to convert actions to stats
Signed-off-by: Emily Markova <emily.markova@gmail.com>
Change-Id: I92b418f528a06b1b4d267655d384805fe465c44c
diff --git a/scouting/webserver/requests/BUILD b/scouting/webserver/requests/BUILD
index 4c4870c..935d721 100644
--- a/scouting/webserver/requests/BUILD
+++ b/scouting/webserver/requests/BUILD
@@ -60,6 +60,7 @@
"//scouting/webserver/requests/messages:request_notes_for_team_go_fbs",
"//scouting/webserver/requests/messages:request_shift_schedule_go_fbs",
"//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
+ "//scouting/webserver/requests/messages:submit_actions_go_fbs",
"//scouting/webserver/requests/messages:submit_data_scouting_go_fbs",
"//scouting/webserver/requests/messages:submit_data_scouting_response_go_fbs",
"//scouting/webserver/requests/messages:submit_driver_ranking_go_fbs",
diff --git a/scouting/webserver/requests/messages/submit_actions.fbs b/scouting/webserver/requests/messages/submit_actions.fbs
index dfb980f..ebbaa5c 100644
--- a/scouting/webserver/requests/messages/submit_actions.fbs
+++ b/scouting/webserver/requests/messages/submit_actions.fbs
@@ -55,7 +55,10 @@
}
table SubmitActions {
- actions_list:[Action] (id:0);
-}
-
-root_type SubmitActions;
\ No newline at end of file
+ team_number:string (id: 0);
+ match_number:int (id: 1);
+ set_number:int (id: 2);
+ comp_level:string (id: 3);
+ actions_list:[Action] (id:4);
+ collected_by:string (id: 5);
+}
\ No newline at end of file
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 467542a..062398a 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -454,6 +454,104 @@
w.Write(builder.FinishedBytes())
}
+func ConvertActionsToStat(submitActions *submit_actions.SubmitActions) (db.Stats2023, error) {
+ overall_time := int64(0)
+ cycles := int64(0)
+ picked_up := false
+ lastPlacedTime := int64(0)
+ stat := db.Stats2023{TeamNumber: string(submitActions.TeamNumber()), MatchNumber: submitActions.MatchNumber(), SetNumber: submitActions.SetNumber(), CompLevel: string(submitActions.CompLevel()),
+ StartingQuadrant: 0, LowCubesAuto: 0, MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 0,
+ LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0, HighCubes: 0,
+ CubesDropped: 0, LowCones: 0, MiddleCones: 0, HighCones: 0, ConesDropped: 0, AvgCycle: 0, CollectedBy: string(submitActions.CollectedBy()),
+ }
+ // Loop over all actions.
+ for i := 0; i < submitActions.ActionsListLength(); i++ {
+ var action submit_actions.Action
+ if !submitActions.ActionsList(&action, i) {
+ return db.Stats2023{}, errors.New(fmt.Sprintf("Failed to parse submit_actions.Action"))
+ }
+ actionTable := new(flatbuffers.Table)
+ action_type := action.ActionTakenType()
+ if !action.ActionTaken(actionTable) {
+ return db.Stats2023{}, errors.New(fmt.Sprint("Failed to parse sub-action or sub-action was missing"))
+ }
+ if action_type == submit_actions.ActionTypeStartMatchAction {
+ var startMatchAction submit_actions.StartMatchAction
+ startMatchAction.Init(actionTable.Bytes, actionTable.Pos)
+ stat.StartingQuadrant = startMatchAction.Position()
+ } else if action_type == submit_actions.ActionTypePickupObjectAction {
+ var pick_up_action submit_actions.PickupObjectAction
+ pick_up_action.Init(actionTable.Bytes, actionTable.Pos)
+ if picked_up == true {
+ object := pick_up_action.ObjectType().String()
+ auto := pick_up_action.Auto()
+ if object == "kCube" && auto == false {
+ stat.CubesDropped += 1
+ } else if object == "kCube" && auto == true {
+ stat.CubesDroppedAuto += 1
+ } else if object == "kCone" && auto == false {
+ stat.ConesDropped += 1
+ } else if object == "kCube" && auto == true {
+ stat.ConesDroppedAuto += 1
+ }
+ } else {
+ picked_up = true
+ }
+ } else if action_type == submit_actions.ActionTypePlaceObjectAction {
+ var place_action submit_actions.PlaceObjectAction
+ place_action.Init(actionTable.Bytes, actionTable.Pos)
+ if !picked_up {
+ return db.Stats2023{}, errors.New(fmt.Sprintf("Got PlaceObjectAction without corresponding PickupObjectAction"))
+ }
+ object := place_action.ObjectType()
+ level := place_action.ScoreLevel()
+ auto := place_action.Auto()
+ if object == 0 && level == 0 && auto == true {
+ stat.LowCubesAuto += 1
+ } else if object == 0 && level == 0 && auto == false {
+ stat.LowCubes += 1
+ } else if object == 0 && level == 1 && auto == true {
+ stat.MiddleCubesAuto += 1
+ } else if object == 0 && level == 1 && auto == false {
+ stat.MiddleCubes += 1
+ } else if object == 0 && level == 2 && auto == true {
+ stat.HighCubesAuto += 1
+ } else if object == 0 && level == 2 && auto == false {
+ stat.HighCubes += 1
+ } else if object == 1 && level == 0 && auto == true {
+ stat.LowConesAuto += 1
+ } else if object == 1 && level == 0 && auto == false {
+ stat.LowCones += 1
+ } else if object == 1 && level == 1 && auto == true {
+ stat.MiddleConesAuto += 1
+ } else if object == 1 && level == 1 && auto == false {
+ stat.MiddleCones += 1
+ } else if object == 1 && level == 2 && auto == true {
+ stat.HighConesAuto += 1
+ } else if object == 1 && level == 2 && auto == false {
+ stat.HighCones += 1
+ } else {
+ return db.Stats2023{}, errors.New(fmt.Sprintf("Got unknown ObjectType/ScoreLevel/Auto combination"))
+ }
+ picked_up = false
+ if lastPlacedTime != int64(0) {
+ // If this is not the first time we place,
+ // start counting cycle time. We define cycle
+ // time as the time between placements.
+ overall_time += int64(action.Timestamp()) - lastPlacedTime
+ cycles += 1
+ }
+ lastPlacedTime = int64(action.Timestamp())
+ }
+ }
+ if cycles != 0 {
+ stat.AvgCycle = int32(overall_time / cycles)
+ } else {
+ stat.AvgCycle = 0
+ }
+ return stat, nil
+}
+
// Handles a Request2023DataScouting request.
type request2023DataScoutingHandler struct {
db Database
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index efd770b..26b79c5 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -23,6 +23,7 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
+ "github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_data_scouting_response"
"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking"
@@ -391,6 +392,103 @@
}
}
+// Validates that we can request the 2023 stats.
+func TestConvertActionsToStat(t *testing.T) {
+ builder := flatbuffers.NewBuilder(1024)
+ builder.Finish((&submit_actions.SubmitActionsT{
+ TeamNumber: "4244",
+ MatchNumber: 3,
+ SetNumber: 1,
+ CompLevel: "quals",
+ CollectedBy: "katie",
+ ActionsList: []*submit_actions.ActionT{
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypeStartMatchAction,
+ Value: &submit_actions.StartMatchActionT{
+ Position: 1,
+ },
+ },
+ Timestamp: 0,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePickupObjectAction,
+ Value: &submit_actions.PickupObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ Auto: true,
+ },
+ },
+ Timestamp: 400,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePickupObjectAction,
+ Value: &submit_actions.PickupObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ Auto: true,
+ },
+ },
+ Timestamp: 800,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePlaceObjectAction,
+ Value: &submit_actions.PlaceObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ ScoreLevel: submit_actions.ScoreLevelkLow,
+ Auto: true,
+ },
+ },
+ Timestamp: 2000,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePickupObjectAction,
+ Value: &submit_actions.PickupObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCone,
+ Auto: false,
+ },
+ },
+ Timestamp: 2800,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePlaceObjectAction,
+ Value: &submit_actions.PlaceObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCone,
+ ScoreLevel: submit_actions.ScoreLevelkHigh,
+ Auto: false,
+ },
+ },
+ Timestamp: 3100,
+ },
+ },
+ }).Pack(builder))
+
+ submitActions := submit_actions.GetRootAsSubmitActions(builder.FinishedBytes(), 0)
+ response, err := ConvertActionsToStat(submitActions)
+
+ if err != nil {
+ t.Fatal("Failed to convert actions to stats: ", err)
+ }
+
+ expected := db.Stats2023{
+ TeamNumber: "4244", MatchNumber: 3, SetNumber: 1,
+ CompLevel: "quals", StartingQuadrant: 1, LowCubesAuto: 1,
+ MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 1,
+ LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0,
+ ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0,
+ HighCubes: 0, CubesDropped: 0, LowCones: 0,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 0,
+ AvgCycle: 1100, CollectedBy: "katie",
+ }
+
+ if expected != response {
+ t.Fatal("Expected ", expected, ", but got ", response)
+ }
+}
+
func TestSubmitNotes(t *testing.T) {
database := MockDatabase{}
scoutingServer := server.NewScoutingServer()