001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj.smartdashboard; 006 007import static edu.wpi.first.units.Units.Meters; 008 009import edu.wpi.first.math.geometry.Pose2d; 010import edu.wpi.first.math.geometry.Rotation2d; 011import edu.wpi.first.networktables.NTSendable; 012import edu.wpi.first.networktables.NTSendableBuilder; 013import edu.wpi.first.networktables.NetworkTable; 014import edu.wpi.first.units.measure.Distance; 015import edu.wpi.first.util.sendable.SendableRegistry; 016import java.util.ArrayList; 017import java.util.List; 018 019/** 020 * 2D representation of game field for dashboards. 021 * 022 * <p>An object's pose is the location shown on the dashboard view. Note that for the robot, this 023 * may or may not match the internal odometry. For example, the robot is shown at a particular 024 * starting location, the pose in this class would represent the actual location on the field, but 025 * the robot's internal state might have a 0,0,0 pose (unless it's initialized to something 026 * different). 027 * 028 * <p>As the user is able to edit the pose, code performing updates should get the robot pose, 029 * transform it as appropriate (e.g. based on wheel odometry), and set the new pose. 030 * 031 * <p>This class provides methods to set the robot pose, but other objects can also be shown by 032 * using the getObject() function. Other objects can also have multiple poses (which will show the 033 * object at multiple locations). 034 */ 035public class Field2d implements NTSendable, AutoCloseable { 036 /** Constructor. */ 037 @SuppressWarnings("this-escape") 038 public Field2d() { 039 FieldObject2d obj = new FieldObject2d("Robot"); 040 obj.setPose(Pose2d.kZero); 041 m_objects.add(obj); 042 SendableRegistry.add(this, "Field"); 043 } 044 045 @Override 046 public void close() { 047 for (FieldObject2d obj : m_objects) { 048 obj.close(); 049 } 050 } 051 052 /** 053 * Set the robot pose from a Pose object. 054 * 055 * @param pose 2D pose 056 */ 057 public synchronized void setRobotPose(Pose2d pose) { 058 m_objects.get(0).setPose(pose); 059 } 060 061 /** 062 * Set the robot pose from x, y, and rotation. 063 * 064 * @param xMeters X location, in meters 065 * @param yMeters Y location, in meters 066 * @param rotation rotation 067 */ 068 public synchronized void setRobotPose(double xMeters, double yMeters, Rotation2d rotation) { 069 m_objects.get(0).setPose(xMeters, yMeters, rotation); 070 } 071 072 /** 073 * Set the robot pose from x, y, and rotation. 074 * 075 * @param x X location 076 * @param y Y location 077 * @param rotation rotation 078 */ 079 public synchronized void setRobotPose(Distance x, Distance y, Rotation2d rotation) { 080 m_objects.get(0).setPose(x.in(Meters), y.in(Meters), rotation); 081 } 082 083 /** 084 * Get the robot pose. 085 * 086 * @return 2D pose 087 */ 088 public synchronized Pose2d getRobotPose() { 089 return m_objects.get(0).getPose(); 090 } 091 092 /** 093 * Get or create a field object. 094 * 095 * @param name The field object's name. 096 * @return Field object 097 */ 098 public synchronized FieldObject2d getObject(String name) { 099 for (FieldObject2d obj : m_objects) { 100 if (obj.m_name.equals(name)) { 101 return obj; 102 } 103 } 104 FieldObject2d obj = new FieldObject2d(name); 105 m_objects.add(obj); 106 if (m_table != null) { 107 synchronized (obj) { 108 obj.m_entry = m_table.getDoubleArrayTopic(name).getEntry(new double[] {}); 109 } 110 } 111 return obj; 112 } 113 114 /** 115 * Get the robot object. 116 * 117 * @return Field object for robot 118 */ 119 public synchronized FieldObject2d getRobotObject() { 120 return m_objects.get(0); 121 } 122 123 @Override 124 public void initSendable(NTSendableBuilder builder) { 125 builder.setSmartDashboardType("Field2d"); 126 127 synchronized (this) { 128 m_table = builder.getTable(); 129 for (FieldObject2d obj : m_objects) { 130 synchronized (obj) { 131 obj.m_entry = m_table.getDoubleArrayTopic(obj.m_name).getEntry(new double[] {}); 132 obj.updateEntry(true); 133 } 134 } 135 } 136 } 137 138 private NetworkTable m_table; 139 private final List<FieldObject2d> m_objects = new ArrayList<>(); 140}