5252
5353#include " protobuf/ssl_vision/ssl_wrapper.pb.h"
5454#include " protobuf/ssl_gc/state/ssl_gc_referee_message.pb.h"
55+ #include " protobuf/world.pb.h"
5556
5657/* *
5758 * Stand alone Erforce simulator
@@ -598,6 +599,7 @@ class SimProxy: public QObject {
598599 void sendSSLSimError (const QList<SSLSimError>& errors, ErrorSource source); // out
599600 void sendRadioResponses (const QList<robot::RadioResponse> &responses); // out
600601 void gotPacket (const QByteArray &data, qint64 time, QString sender); // out
602+ void sendGroundTruth (const QByteArray& data); // out - world::SimulatorState at 200Hz
601603 void gotCommand (const Command &command); // internal
602604 void handleRadioCommands (const SSLSimRobotControl& control, bool isBlue, qint64 processingStart); // in
603605public slots:
@@ -643,6 +645,7 @@ void SimProxy::handleCommand(const Command &command) {
643645 connect (this , &SimProxy::handleRadioCommands, m_sim, &Simulator::handleRadioCommands);
644646 connect (m_sim, &Simulator::sendSSLSimError, this , &SimProxy::sendSSLSimError);
645647 connect (m_sim, &Simulator::sendRadioResponses, this , &SimProxy::sendRadioResponses);
648+ connect (m_sim, &Simulator::sendGroundTruth, this , &SimProxy::sendGroundTruth);
646649 auto * simCommand = m_teamCommand->mutable_simulator ();
647650 simCommand->set_enable (true );
648651 auto * trCommand = m_teamCommand->mutable_transceiver ();
@@ -853,12 +856,12 @@ private slots:
853856class RefereeTeamDetector : public QObject {
854857 Q_OBJECT
855858public:
856- RefereeTeamDetector (const QString& teamName, bool localhost)
859+ RefereeTeamDetector (const QString& teamName, bool localhost, quint16 port = SSL_GAME_CONTROLLER_PORT )
857860 : m_socket(this )
858861 , m_teamName(teamName.toLower().trimmed())
859862 {
860863 m_socket.bind (QHostAddress::AnyIPv4,
861- SSL_GAME_CONTROLLER_PORT ,
864+ port ,
862865 QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
863866 if (!localhost) {
864867 m_socket.joinMulticastGroup (QHostAddress (SSL_GAME_CONTROLLER_ADDRESS ));
@@ -919,30 +922,35 @@ class IbisFeedbackAdaptor : public QObject {
919922 }
920923
921924public slots:
922- void handleVisionData (const QByteArray& data, qint64, QString) {
923- SSL_WrapperPacket pkt;
924- if (!pkt.ParseFromArray (data.data (), data.size ()) || !pkt.has_detection ()) {
925+ // world::SimulatorState から IbisVisionState を更新する(200Hz)
926+ // world::SimRobot の座標系: p_x/p_y はゲーム座標系のメートル単位(Bullet座標 / SIMULATOR_SCALE)
927+ // SSL座標系への変換: x_mm = p_y * 1000, y_mm = -p_x * 1000
928+ // 方向角: クォータニオン (i,j,k,real) の回転行列第1列から yaw を算出
929+ void handleGroundTruth (const QByteArray& data) {
930+ world::SimulatorState state;
931+ if (!state.ParseFromArray (data.data (), data.size ())) {
925932 return ;
926933 }
927- const auto & det = pkt.detection ();
928- for (const auto & r : det.robots_blue ()) {
929- if (!r.has_robot_id ()) { continue ; }
930- const uint32_t id = r.robot_id ();
931- if (id < kMaxRobots ) {
932- m_vision[0 ][id] = {r.x (), r.y (),
933- r.has_orientation () ? r.orientation () : 0 .0f ,
934- true };
935- }
936- }
937- for (const auto & r : det.robots_yellow ()) {
938- if (!r.has_robot_id ()) { continue ; }
939- const uint32_t id = r.robot_id ();
940- if (id < kMaxRobots ) {
941- m_vision[1 ][id] = {r.x (), r.y (),
942- r.has_orientation () ? r.orientation () : 0 .0f ,
943- true };
934+ auto updateTeam = [this ](const auto & robots, int teamIdx) {
935+ for (const auto & r : robots) {
936+ const uint32_t id = r.id ();
937+ if (id >= kMaxRobots ) { continue ; }
938+ const float qx = r.rotation ().i ();
939+ const float qy = r.rotation ().j ();
940+ const float qz = r.rotation ().k ();
941+ const float qw = r.rotation ().real ();
942+ const float dir_x = 1 .0f - 2 .0f * (qy*qy + qz*qz);
943+ const float dir_y = 2 .0f * (qx*qy + qw*qz);
944+ m_vision[teamIdx][id] = {
945+ r.p_y () * 1000 .0f ,
946+ -r.p_x () * 1000 .0f ,
947+ std::atan2 (dir_y, dir_x),
948+ true
949+ };
944950 }
945- }
951+ };
952+ updateTeam (state.blue_robots (), 0 );
953+ updateTeam (state.yellow_robots (), 1 );
946954 }
947955
948956 void handleRobotResponse (const QList<robot::RadioResponse>& responses) {
@@ -1071,6 +1079,7 @@ int main(int argc, char* argv[])
10711079 QCommandLineOption ibisAccSpeedupOpt (" ibis-acc-speedup" , " Acceleration limit for speedup [m/s^2]" , " accel" , " 4.0" );
10721080 QCommandLineOption ibisAccBrakeOpt (" ibis-acc-brake" , " Acceleration limit for braking [m/s^2]" , " accel" , " 6.0" );
10731081 QCommandLineOption ibisFeedbackHzOpt (" ibis-feedback-hz" , " ibis feedback send rate in Hz (default: 125)" , " hz" , " 125" );
1082+ QCommandLineOption ibisRefereePortOpt (" ibis-referee-port" , " Game Controller multicast port for team color detection" , " port" , QString::number (SSL_GAME_CONTROLLER_PORT ));
10741083 parser.addOption (ibisPortOpt);
10751084 parser.addOption (ibisFeedbackAddrOpt);
10761085 parser.addOption (ibisFeedbackPortBaseOpt);
@@ -1079,6 +1088,7 @@ int main(int argc, char* argv[])
10791088 parser.addOption (ibisAccSpeedupOpt);
10801089 parser.addOption (ibisAccBrakeOpt);
10811090 parser.addOption (ibisFeedbackHzOpt);
1091+ parser.addOption (ibisRefereePortOpt);
10821092
10831093 parser.process (app);
10841094
@@ -1160,6 +1170,7 @@ int main(int argc, char* argv[])
11601170 const quint16 fbPortBase = static_cast <quint16>(parser.value (ibisFeedbackPortBaseOpt).toUInt ());
11611171 const bool useReferee = parser.isSet (ibisUseRefereeOpt);
11621172 const int feedbackHz = qMax (1 , parser.value (ibisFeedbackHzOpt).toInt ());
1173+ const quint16 refereePort = static_cast <quint16>(parser.value (ibisRefereePortOpt).toUInt ());
11631174
11641175 auto * ibisCmd = new IbisCommandAdaptor (cmdPort, &timer, accSpeedup, accBrake);
11651176 auto * ibisFb = new IbisFeedbackAdaptor (fbAddr, fbPortBase, useReferee, feedbackHz);
@@ -1171,17 +1182,18 @@ int main(int argc, char* argv[])
11711182 QObject::connect (ibisCmd, &IbisCommandAdaptor::sendRadioCommands,
11721183 &sim, &SimProxy::handleRadioCommands);
11731184
1174- // IbisFeedbackAdaptor receives vision data for position/orientation
1175- QObject::connect (&sim, &SimProxy::gotPacket ,
1176- ibisFb, &IbisFeedbackAdaptor::handleVisionData );
1185+ // IbisFeedbackAdaptor receives ground truth positions at 200Hz for position/orientation
1186+ QObject::connect (&sim, &SimProxy::sendGroundTruth ,
1187+ ibisFb, &IbisFeedbackAdaptor::handleGroundTruth );
11771188 // IbisFeedbackAdaptor receives radio responses for velocity and ball detection
11781189 QObject::connect (&sim, &SimProxy::sendRadioResponses,
11791190 ibisFb, &IbisFeedbackAdaptor::handleRobotResponse);
11801191
11811192 if (useReferee) {
11821193 auto * referee = new RefereeTeamDetector (
11831194 parser.value (ibisFeedbackTeamNameOpt),
1184- parser.isSet (localhostConfig));
1195+ parser.isSet (localhostConfig),
1196+ refereePort);
11851197 QObject::connect (referee, &RefereeTeamDetector::teamDetected,
11861198 ibisFb, &IbisFeedbackAdaptor::handleRefereePacket);
11871199 referee->moveToThread (&rcv_thread);
0 commit comments