3.14 ModbusClient 마스터 기능
개요
Arm::modbusClient 는 로봇이 Modbus 마스터로 동작할 때의 시리얼 파라미터 관리, 슬레이브 세션 생성, 레지스터 읽기/쓰기, 시리얼 passthrough 기능에 대응합니다.
현재 C++17 공개 기능은 두 계층으로 나뉩니다:
ModbusClient인터페이스 모듈:GetSlave/GetParam/SetParam담당modbus_client::Slave세션: 실제 읽기/쓰기, 시리얼 송수신, 세션별 파라미터 조회 담당
권장 호출 경로
cpp
Arm arm; // 로봇 세션 객체 생성
STATUS_CODE connectRet = arm.Connect("10.27.1.254", ""); // 컨트롤러 또는 라우터 주소에 연결
if (connectRet != STATUS_CODE::OK) { // 연결 실패 여부 확인
return; // 연결 실패 시 현재 흐름 종료
} // 연결 판단 종료
auto [slave, slaveRet] = arm.modbusClient.GetSlave( // Modbus 슬레이브 세션 생성
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 컨트롤러 485 채널 지정
1, // 슬레이브 ID 를 1 로 지정
0 // masterId 를 0 으로 지정
); // 슬레이브 세션 생성 호출 종료
if (slaveRet != STATUS_CODE::OK || !slave.IsValid()) { // 세션 생성 성공 및 유효 여부 확인
return; // 세션을 사용할 수 없으면 현재 흐름 종료
} // 세션 판단 종료
auto [values, readRet] = slave.ReadCoils(0, 2); // 주소 0 부터 코일 값 2개 읽기
if (readRet != STATUS_CODE::OK) { // 읽기 실패 여부 확인
return; // 읽기 실패 시 현재 흐름 종료
} // 읽기 판단 종료인터페이스 개요
ModbusClient 인터페이스 모듈
cpp
GetSlave(channel, slaveId, masterId) -> std::pair<modbus_client::Slave, STATUS_CODE>
GetParam(channel, masterId = 1) -> std::pair<modbus_client::SerialParams, STATUS_CODE>
SetParam(const modbus_client::SerialParams& params) -> std::pair<int32_t, STATUS_CODE>| 메서드 | 입력 | 출력 | 주요 동작 |
|---|---|---|---|
GetSlave | 채널, 슬레이브 ID, 마스터 ID | std::pair<modbus_client::Slave, STATUS_CODE> | 로컬 세션만 생성하며 즉시 요청을 보내지 않음 |
GetParam | 채널, 마스터 ID | std::pair<modbus_client::SerialParams, STATUS_CODE> | TCP_TO_485 채널은 masterId 기준으로 조회 |
SetParam | 시리얼 파라미터 | std::pair<int32_t, STATUS_CODE> | 컨트롤러가 확인한 파라미터 레코드 id 반환 |
modbus_client::Slave 세션
cpp
IsValid() const -> bool
ReadCoils(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
WriteCoils(addr, values) -> STATUS_CODE
ReadHoldingRegs(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
WriteHoldingRegs(addr, values) -> STATUS_CODE
ReadDiscreteInputs(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
ReadInputRegs(addr, num) -> std::pair<std::vector<int32_t>, STATUS_CODE>
WriteInputRegs(addr, values) -> STATUS_CODE
GetParam() -> std::pair<modbus_client::SerialParams, STATUS_CODE>
SetParam(params) -> std::pair<int32_t, STATUS_CODE>
SerialSend(msg) -> STATUS_CODE
SerialReceive() -> std::pair<std::string, STATUS_CODE>| 메서드 | 입력 | 출력 | 주요 동작 |
|---|---|---|---|
IsValid | 없음 | bool | 세션이 여전히 유효한 Arm 에 바인딩되어 있는지만 확인 |
ReadCoils | 시작 주소, 개수 | std::pair<std::vector<int32_t>, STATUS_CODE> | 1..120 및 주소 범위를 로컬에서 검증 |
WriteCoils | 시작 주소, 값 목록 | STATUS_CODE | 쓰기 개수 1..1024 를 로컬에서 검증 |
ReadHoldingRegs | 시작 주소, 개수 | std::pair<std::vector<int32_t>, STATUS_CODE> | ReadCoils 와 동일한 동작 |
WriteHoldingRegs | 시작 주소, 값 목록 | STATUS_CODE | WriteCoils 와 동일한 동작 |
ReadDiscreteInputs | 시작 주소, 개수 | std::pair<std::vector<int32_t>, STATUS_CODE> | ReadCoils 와 동일한 동작 |
ReadInputRegs | 시작 주소, 개수 | std::pair<std::vector<int32_t>, STATUS_CODE> | ReadCoils 와 동일한 동작 |
WriteInputRegs | 시작 주소, 값 목록 | STATUS_CODE | WriteCoils 와 동일한 동작 |
GetParam | 없음 | std::pair<modbus_client::SerialParams, STATUS_CODE> | 현재 Slave 가 저장한 채널 / 마스터 컨텍스트 사용 |
SetParam | 시리얼 파라미터 | std::pair<int32_t, STATUS_CODE> | 현재 세션을 통해 설정 인터페이스 호출 |
SerialSend | 텍스트 시리얼 메시지 | STATUS_CODE | 채널별 시리얼 passthrough 프로토콜 사용 |
SerialReceive | 없음 | std::pair<std::string, STATUS_CODE> | passthrough 로 수신한 원본 문자열 반환 |
전제 조건과 수명 주기
| 항목 | 규칙 |
|---|---|
| 연결 전제 | 먼저 Arm::Connect() 에 성공해야 하며, 그렇지 않으면 ModbusClient 인터페이스 모듈은 NOT_CONNECTED 를 반환 |
GetSlave | 로컬 Slave 를 생성합니다. 원격 슬레이브 상태는 이후 읽기/쓰기 결과로 확인합니다. |
| 세션 무효화 | Arm::Disconnect() 후에는 기존 modbus_client::Slave 가 모두 무효화됨 |
IsValid | 현재 세션이 유효한 Arm 과 계속 바인딩되어 있는지 확인합니다. 원격 온라인 상태는 읽기/쓰기 결과로 확인합니다. |
| 버스 설정 충돌 | 호출자가 컨트롤러의 버스 설정 충돌 여부를 직접 확인해야 합니다. |
파라미터 검증 및 실패 기준
| 시나리오 | 반환 |
|---|---|
modbus_client::Slave 세션 무효 | INVALID_SESSION |
addr < 0 | INVALID_PARAMETER |
num < 1 또는 num > 120 | INVALID_PARAMETER |
addr + num - 1 > 65535 | INVALID_PARAMETER |
values.size() < 1 또는 values.size() > 1024 | INVALID_PARAMETER |
addr + values.size() - 1 > 65535 | INVALID_PARAMETER |
| 컨트롤러가 예상과 다른 JSON 구조 반환 | OTHER_ERR |
추가 설명:
- 읽기 인터페이스가 반환하는
std::vector<int32_t>는 컨트롤러가 반환한 원본 정수 배열이며, 코일 값도 컨트롤러 결과대로 표시합니다. - 쓰기 인터페이스는 주소 범위와 개수를 검증합니다.
values내용의 업무 의미는 컨트롤러가 처리합니다. SetParam()/GetParam()은 baud rate, port 같은 업무 파라미터를 컨트롤러로 전달해 유효성을 판단합니다.
상세 의미
GetSlave
시그니처
cpp
std::pair<modbus_client::Slave, STATUS_CODE> GetSlave(
modbus_client::MODBUS_CHANNEL channel,
int32_t slaveId,
int32_t masterId
);| 입력 | 타입 | 설명 |
|---|---|---|
channel | modbus_client::MODBUS_CHANNEL | 채널 enum |
slaveId | int32_t | 슬레이브 ID, 생성 시 세션에 바로 기록 |
masterId | int32_t | 마스터 ID, 이후 읽기/쓰기 요청에 그대로 포함 |
| 출력 | 설명 |
|---|---|
modbus_client::Slave | 성공 시 사용 가능한 세션 반환, 실패 시 기본 생성된 빈 세션 반환 |
STATUS_CODE | OK / NOT_CONNECTED |
제약 및 동작
GetSlave()는 로컬 세션을 생성합니다. 원격 슬레이브 상태는 이후 읽기/쓰기 결과로 확인합니다.slaveId/masterId는 컨트롤러 의미대로 전달합니다.- 성공적으로 반환된
Slave는 현재Arm수명 주기에 의존하므로Disconnect()이후 재사용할 수 없습니다.
호출 예제
cpp
auto [slave, ret] = arm.modbusClient.GetSlave( // Modbus 슬레이브 세션 생성
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 컨트롤러 485 채널 지정
7, // 슬레이브 ID 를 7 로 지정
0 // masterId 를 0 으로 지정
); // 슬레이브 세션 생성 호출 종료
if (ret != STATUS_CODE::OK || !slave.IsValid()) { // 세션 생성 성공 및 계속 유효한지 확인
return; // 세션을 사용할 수 없으면 현재 흐름 종료
} // 세션 판단 종료GetParam
시그니처
cpp
std::pair<modbus_client::SerialParams, STATUS_CODE> GetParam(
modbus_client::MODBUS_CHANNEL channel,
int32_t masterId = 1
);| 입력 | 타입 | 설명 |
|---|---|---|
channel | modbus_client::MODBUS_CHANNEL | 조회할 채널 |
masterId | int32_t | CONTROLLER_TCP_TO_485 채널에서만 실제 의미가 있으며 기본값은 1 |
| 출력 | 설명 |
|---|---|
modbus_client::SerialParams | 성공 시 파라미터 반환, 실패 시 기본 생성값 반환 |
STATUS_CODE | OK / NOT_CONNECTED / 기타 컨트롤러 오류 코드 |
제약 및 동작
CONTROLLER_TCP_TO_485채널은 컨트롤러에masterId를 보냅니다.- 다른 시리얼 채널은 컨트롤러에 채널 enum 값을 보내며
masterId는 무시됩니다. - 이는 상대 프로토콜의 기존 기준이며 SDK 가 새로 정의한 규칙이 아닙니다.
호출 예제
cpp
auto [params, ret] = arm.modbusClient.GetParam( // Modbus 시리얼 파라미터 조회
modbus_client::MODBUS_CHANNEL::CONTROLLER_TCP_TO_485, // TCP-to-485 채널 지정
12 // masterId 를 12 로 지정
); // 시리얼 파라미터 조회 호출 종료
if (ret == STATUS_CODE::OK) { // 파라미터 조회 성공 여부 확인
std::cout << "ip=" << params.ip << "\n"; // 조회된 대상 IP 출력
} // 파라미터 조회 판단 종료SetParam
시그니처
cpp
std::pair<int32_t, STATUS_CODE> SetParam(const modbus_client::SerialParams& params);| 입력 | 타입 | 설명 |
|---|---|---|
params | modbus_client::SerialParams | 시리얼 파라미터 객체 |
| 출력 | 설명 |
|---|---|
int32_t | 성공 시 컨트롤러가 확인한 파라미터 레코드 id 반환, 실패 시 0 반환 |
STATUS_CODE | OK / NOT_CONNECTED / 기타 컨트롤러 오류 코드 |
제약 및 동작
channel,ip,port,baud,dataBit,stopBit,parity,timeout은 모두 직렬화되어 컨트롤러로 직접 전송됩니다.
호출 예제
cpp
modbus_client::SerialParams params; // 시리얼 파라미터 객체 생성
params.channel = modbus_client::MODBUS_CHANNEL::CONTROLLER_485; // 컨트롤러 485 채널 지정
params.ip = "10.27.1.99"; // 대상 IP 설정
params.port = 1502; // 대상 포트 설정
auto [id, ret] = arm.modbusClient.SetParam(params); // 시리얼 파라미터 저장, 컨트롤러 설정 변경
if (ret == STATUS_CODE::OK) { // 파라미터 저장 성공 여부 확인
std::cout << "saved_param_id=" << id << "\n"; // 컨트롤러가 확인한 파라미터 레코드 ID 출력
} // 파라미터 저장 판단 종료ReadCoils / ReadHoldingRegs / ReadDiscreteInputs / ReadInputRegs
이 네 인터페이스는 동일한 로컬 검증 규칙과 반환 기준을 공유합니다.
시그니처 패턴
cpp
std::pair<std::vector<int32_t>, STATUS_CODE> ReadXxx(
int32_t addr,
int32_t num
);| 입력 | 설명 |
|---|---|
addr | 시작 주소, addr >= 0 필요 |
num | 읽기 개수, 1 <= num <= 120 필요 |
| 출력 | 설명 |
|---|---|
std::vector<int32_t> | 성공 시 정수 배열 반환, 실패 시 빈 배열 반환 |
STATUS_CODE | OK / INVALID_SESSION / INVALID_PARAMETER / 기타 컨트롤러 오류 코드 |
제약 및 동작
addr + num - 1은65535를 초과할 수 없습니다.Slave가 무효이면 바로INVALID_SESSION을 반환합니다.- 컨트롤러가 정수 배열이 아닌 값을 반환하면 SDK 는
OTHER_ERR를 반환합니다.
호출 예제
cpp
auto [coils, ret] = slave.ReadCoils(10, 3); // 주소 10 부터 코일 값 3개 읽기
if (ret == STATUS_CODE::OK) { // 코일 읽기 성공 여부 확인
std::cout << "coils=" << coils.size() << "\n"; // 읽은 코일 개수 출력
} // 코일 읽기 판단 종료WriteCoils / WriteHoldingRegs / WriteInputRegs
이 쓰기 인터페이스들은 대상 Modbus 영역만 다르고 나머지 규칙은 동일합니다.
시그니처 패턴
cpp
STATUS_CODE WriteXxx(int32_t addr, const std::vector<int32_t>& values);| 입력 | 설명 |
|---|---|
addr | 시작 주소, addr >= 0 필요 |
values | 쓸 값 목록, 개수는 1..1024 필요 |
| 출력 | 설명 |
|---|---|
STATUS_CODE | OK / INVALID_SESSION / INVALID_PARAMETER / 기타 컨트롤러 오류 코드 |
제약 및 동작
addr + values.size() - 1은65535를 초과할 수 없습니다.- SDK 는 주소와 개수를 검증합니다. 각 요소의 업무 의미는 컨트롤러가 처리합니다.
호출 예제
cpp
STATUS_CODE ret = slave.WriteHoldingRegs(20, {11, 12}); // 주소 20 부터 holding register 값 2개 쓰기
if (ret != STATUS_CODE::OK) { // holding register 쓰기 실패 여부 확인
return; // 쓰기 실패 시 현재 흐름 종료
} // holding register 쓰기 판단 종료
// STATUS_CODE inputRet = slave.WriteInputRegs(20, {11, 12}); // input register 쓰기는 슬레이브 상태를 변경하므로 확인 후 실행Slave::GetParam / Slave::SetParam
이 두 인터페이스는 ModbusClient::GetParam / SetParam 의미를 재사용하며, 차이는 세션 컨텍스트가 현재 Slave 에서 온다는 점입니다:
Slave::GetParam()은 세션 생성 시 기록된channel / masterId를 사용합니다.Slave::SetParam(params)는 현재 유효한 세션을 통해 요청을 보냅니다.
Slave 가 이미 무효이면 두 인터페이스 모두 INVALID_SESSION 을 반환합니다.
SerialSend / SerialReceive
시그니처
cpp
STATUS_CODE SerialSend(const std::string& msg);
std::pair<std::string, STATUS_CODE> SerialReceive();| 인터페이스 | 입력 | 출력 | 주요 동작 |
|---|---|---|---|
SerialSend | 원본 문자열 | STATUS_CODE | 현재 channel 기준으로 전송 요청, slaveId / masterId 미포함 |
SerialReceive | 없음 | std::pair<std::string, STATUS_CODE> | 성공 시 원본 문자열 반환, 실패 시 빈 문자열 반환 |
제약 및 동작
- Passthrough 프로토콜은 채널 기준으로 동작하므로
Slave에 저장된slaveId는 시리얼 passthrough 에 영향을 주지 않습니다. SerialReceive()성공 시 컨트롤러가 반환한data는 문자열이어야 하며, 그렇지 않으면OTHER_ERR를 반환합니다.
일반 타입
modbus_client::MODBUS_CHANNEL
| enum 값 | 값 | 설명 |
|---|---|---|
CONTROLLER_TCP_TO_485 | 2 | 컨트롤러 TCP-to-485 채널 |
WRIST_485_0 | 3 | 손목 485_0 채널 |
WRIST_485_1 | 4 | 손목 485_1 채널 |
CONTROLLER_485 | 5 | 컨트롤러 485 채널 |
modbus_client::MODBUS_PARITY
| enum 값 | 값 | 설명 |
|---|---|---|
NONE | 78 | ASCII N |
ODD | 79 | ASCII O |
EVEN | 69 | ASCII E |
modbus_client::SerialParams
| 필드 | 타입 | 기본값 | 설명 |
|---|---|---|---|
id | int32_t | 1 | 파라미터 레코드 ID |
channel | modbus_client::MODBUS_CHANNEL | CONTROLLER_TCP_TO_485 | 채널 |
ip | std::string | 빈 문자열 | 대상 IP |
port | int32_t | 502 | 포트 |
baud | int32_t | 9600 | baud rate |
dataBit | int32_t | 8 | data bit |
stopBit | int32_t | 1 | stop bit |
parity | modbus_client::MODBUS_PARITY | NONE | parity |
timeout | int32_t | 1000 | timeout, 밀리초 |
예제
C++17 최소 예제
cpp
#include <iostream> // Modbus 조회 결과를 출력하기 위한 표준 출력 스트림 포함
#include "arm_api.h" // Arm 메인 진입점을 포함하며, 연결 후 arm.modbusClient 로 Modbus 인터페이스에 접근
int main() // 예제 프로그램 진입점
{ // 예제 main 함수 시작
Arm arm; // 로봇 세션 객체 생성
STATUS_CODE connectRet = arm.Connect("10.27.1.254", ""); // 컨트롤러 또는 라우터 주소에 연결, 티치 펜던트 주소를 비워 기본 규칙 사용
if (connectRet != STATUS_CODE::OK) { // 연결 실패 여부 확인
return 1; // 연결 실패 시 바로 종료
} // 연결 결과 판단 종료
auto [params, getRet] = arm.modbusClient.GetParam( // 지정한 Modbus 채널의 시리얼 파라미터 조회
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 컨트롤러 485 채널 지정
0 // masterId 지정, TCP_TO_485 가 아닌 채널에서는 일반적으로 컨트롤러가 무시
); // 시리얼 파라미터 조회 호출 종료
if (getRet == STATUS_CODE::OK) { // 조회 성공 시에만 시리얼 파라미터 출력
std::cout << "modbus_ip=" << params.ip << "\n"; // 시리얼 파라미터의 대상 IP 출력
} // 시리얼 파라미터 조회 판단 종료
auto [slave, slaveRet] = arm.modbusClient.GetSlave( // Modbus 슬레이브 세션 하나 생성
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 컨트롤러 485 채널 지정
1, // 슬레이브 ID 를 1 로 지정
0 // masterId 를 0 으로 지정
); // 슬레이브 세션 생성 호출 종료
if (slaveRet != STATUS_CODE::OK || !slave.IsValid()) { // 슬레이브 세션 생성 성공 및 유효 여부 확인
return 1; // 세션이 무효이면 오류 코드 반환
} // 슬레이브 세션 판단 종료
auto [coils, readRet] = slave.ReadCoils(0, 2); // 주소 0 부터 코일 값 2개 읽기
if (readRet != STATUS_CODE::OK) { // 코일 읽기 실패 여부 확인
return 1; // 읽기 실패 시 오류 코드 반환
} // 코일 읽기 판단 종료
std::cout << "coil_count=" << coils.size() << "\n"; // 읽은 코일 개수 출력
return 0; // 예제 정상 종료
} // 예제 main 함수 종료C++17 시나리오 예제
아래 여러 코드 조각은 "Modbus 파라미터 인터페이스, 슬레이브 세션, 레지스터 읽기/쓰기, 시리얼 passthrough" 관점에서 이 페이지의 API 를 교차로 다룹니다. 코드 조각은 최소 예제에서 이미 연결에 성공한 arm 객체를 이어받는다고 가정합니다. 레지스터 쓰기, 시리얼 파라미터 변경, 시리얼 passthrough 는 현장 장치에 접근하므로 확인 후 실행하십시오.
시리얼 파라미터 조회 및 설정
cpp
auto [facadeParams, facadeGetRet] = arm.modbusClient.GetParam( // ModbusClient 인터페이스 모듈로 시리얼 파라미터 조회
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 컨트롤러 485 채널 지정
0 // masterId 를 0 으로 지정
); // 파라미터 조회 호출 종료
modbus_client::SerialParams params = facadeParams; // SetParam 호출 형태를 보여주기 위해 현재 파라미터 복사
params.channel = modbus_client::MODBUS_CHANNEL::CONTROLLER_485; // 설정할 채널 지정
// auto [savedId, facadeSetRet] = arm.modbusClient.SetParam(params); // 시리얼 파라미터 설정은 컨트롤러 설정을 변경하므로 확인 후 실행슬레이브 세션 생성 및 세션별 파라미터 조회
cpp
auto [slave, slaveRet] = arm.modbusClient.GetSlave( // ModbusClient 인터페이스 모듈로 슬레이브 세션 생성
modbus_client::MODBUS_CHANNEL::CONTROLLER_485, // 컨트롤러 485 채널 지정
1, // 슬레이브 ID 를 1 로 지정
0 // masterId 를 0 으로 지정
); // 슬레이브 세션 생성 호출 종료
if (slaveRet != STATUS_CODE::OK || !slave.IsValid()) { // Slave::IsValid 로 로컬 세션 유효 여부 확인
return; // 세션이 무효이면 현재 흐름 종료
} // 슬레이브 세션 판단 종료
auto [slaveParams, slaveGetRet] = slave.GetParam(); // 현재 Slave 세션으로 시리얼 파라미터 조회
// auto [slaveSavedId, slaveSetRet] = slave.SetParam(slaveParams); // Slave 를 통한 시리얼 파라미터 설정은 컨트롤러 설정을 변경하므로 확인 후 실행Modbus 데이터 영역 읽기 및 쓰기
cpp
auto [coils, coilsRet] = slave.ReadCoils(0, 2); // 코일 영역 데이터 읽기
auto [holdingRegs, holdingRet] = slave.ReadHoldingRegs(0, 2); // holding register 데이터 읽기
auto [discreteInputs, discreteRet] = slave.ReadDiscreteInputs(0, 2); // discrete input 데이터 읽기
auto [inputRegs, inputRet] = slave.ReadInputRegs(0, 2); // input register 데이터 읽기
if (coilsRet == STATUS_CODE::OK || holdingRet == STATUS_CODE::OK || discreteRet == STATUS_CODE::OK || inputRet == STATUS_CODE::OK) { // 읽기 중 하나 이상 성공했는지 확인
std::cout << "coil_count=" << coils.size() << " holding_count=" << holdingRegs.size() << "\n"; // 읽기 결과 요약 출력
} // Modbus 읽기 판단 종료
// STATUS_CODE writeCoilsRet = slave.WriteCoils(0, {1, 0}); // 코일 쓰기는 슬레이브 상태를 변경하므로 확인 후 실행
// STATUS_CODE writeHoldingRet = slave.WriteHoldingRegs(0, {100, 200}); // holding register 쓰기는 슬레이브 상태를 변경하므로 확인 후 실행
// STATUS_CODE writeInputRet = slave.WriteInputRegs(0, {100, 200}); // input register 쓰기는 슬레이브 상태를 변경하므로 확인 후 실행시리얼 passthrough
cpp
// STATUS_CODE serialSendRet = slave.SerialSend("010300000002"); // 시리얼 passthrough 전송은 현장 버스에 접근하므로 확인 후 실행
// auto [serialText, serialReceiveRet] = slave.SerialReceive(); // 시리얼 passthrough 수신은 현장 데이터를 기다리므로 확인 후 실행예제 코드
cpp
#include "query_master_params/run.h"
#include "operate_slave/run.h"
#include "set_master_params/run.h"
int main(void)
{
// [ZH] 默认只调用一个门面方法;如需体验其他接口,请把下一行替换成下面任意一行。
// [EN] The main function calls only one facade by default. Replace the next line with any line below to try other APIs.
return RunModbusBasicQueryMasterParams();
// return RunModbusBasicOperateSlave();
// return RunModbusBasicSetMasterParams();
}cpp
#include <stdio.h>
#include <string.h>
extern "C" {
#include "c_arm_api.h"
}
int main(void)
{
// [ZH] 本示例直接在源码中写死连接地址,不解析命令行参数。
// [EN] This example hard-codes the connection addresses in the source code and does not parse command-line arguments.
// [ZH] 创建并连接 SDK 句柄。
// [EN] Create the SDK handle and connect to the robot.
ArmHandle* handle = Arm_Create();
if (handle == NULL) {
printf("[c99_modbus] 创建句柄失败 / Failed to create the handle\n");
return 1;
}
int ret = Arm_Connect(handle, "10.27.1.2", "10.27.1.102");
if (ret != 0) {
printf("[c99_modbus] 连接失败 / Connect failed, 状态码 / Status code: %d\n", ret);
Arm_Destroy(handle);
return 1;
}
printf("[c99_modbus] 机器人连接成功 / Robot connected successfully\n");
// [ZH] 准备主站串口参数并读取当前值。
// [EN] Prepare master serial params and read the current values.
ArmSerialParams masterParams = {0};
int32_t paramId = 0;
snprintf(masterParams.ip, sizeof(masterParams.ip), "127.0.0.1");
masterParams.channel = ARM_MODBUS_CHANNEL_CONTROLLER_485;
masterParams.id = 1;
masterParams.port = 502;
masterParams.baud = 9600;
masterParams.dataBit = 8;
masterParams.stopBit = 1;
masterParams.parity = ARM_MODBUS_PARITY_NONE;
masterParams.timeout = 1000;
ret = Arm_Modbus_GetParam(handle, ARM_MODBUS_CHANNEL_CONTROLLER_485, 0, &masterParams);
printf("[c99_modbus] GetParam 状态码 / GetParam status code: %d, channel=%d, baud=%d\n", ret, masterParams.channel, masterParams.baud);
ret = Arm_Modbus_SetParam(handle, &masterParams, ¶mId);
printf("[c99_modbus] SetParam 状态码 / SetParam status code: %d, id=%d\n", ret, paramId);
// [ZH] 获取从站句柄并顺序执行全部从站接口。
// [EN] Acquire the slave handle and execute all slave APIs in sequence.
ArmModbusSlaveHandle* slave = NULL;
ret = Arm_Modbus_GetSlave(handle, ARM_MODBUS_CHANNEL_CONTROLLER_485, 1, 0, &slave);
printf("[c99_modbus] GetSlave 状态码 / GetSlave status code: %d\n", ret);
if (slave != NULL) {
int valid = Arm_ModbusSlave_IsValid(slave);
printf("[c99_modbus] Slave_IsValid / Slave_IsValid: %d\n", valid);
int32_t values[8] = {0};
size_t valueCount = 0U;
ret = Arm_ModbusSlave_ReadCoils(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadCoils 状态码 / ReadCoils status code: %d, count=%zu\n", ret, valueCount);
int32_t writeCoils[2] = {1, 0};
ret = Arm_ModbusSlave_WriteCoils(slave, 0, writeCoils, 2U);
printf("[c99_modbus] WriteCoils 状态码 / WriteCoils status code: %d\n", ret);
ret = Arm_ModbusSlave_ReadHoldingRegs(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadHoldingRegs 状态码 / ReadHoldingRegs status code: %d, count=%zu\n", ret, valueCount);
int32_t holdingRegs[2] = {1, 2};
ret = Arm_ModbusSlave_WriteHoldingRegs(slave, 0, holdingRegs, 2U);
printf("[c99_modbus] WriteHoldingRegs 状态码 / WriteHoldingRegs status code: %d\n", ret);
ret = Arm_ModbusSlave_ReadDiscreteInputs(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadDiscreteInputs 状态码 / ReadDiscreteInputs status code: %d, count=%zu\n", ret, valueCount);
ret = Arm_ModbusSlave_ReadInputRegs(slave, 0, 2, values, 8U, &valueCount);
printf("[c99_modbus] ReadInputRegs 状态码 / ReadInputRegs status code: %d, count=%zu\n", ret, valueCount);
int32_t inputRegs[2] = {3, 4};
ret = Arm_ModbusSlave_WriteInputRegs(slave, 0, inputRegs, 2U);
printf("[c99_modbus] WriteInputRegs 状态码 / WriteInputRegs status code: %d\n", ret);
ret = Arm_ModbusSlave_SetParam(slave, &masterParams, ¶mId);
printf("[c99_modbus] Slave_SetParam 状态码 / Slave_SetParam status code: %d, id=%d\n", ret, paramId);
ret = Arm_ModbusSlave_GetParam(slave, &masterParams);
printf("[c99_modbus] Slave_GetParam 状态码 / Slave_GetParam status code: %d, baud=%d\n", ret, masterParams.baud);
ret = Arm_ModbusSlave_SerialSend(slave, "hello from c99 example");
printf("[c99_modbus] SerialSend 状态码 / SerialSend status code: %d\n", ret);
char recvBuf[256] = {0};
ret = Arm_ModbusSlave_SerialReceive(slave, recvBuf, sizeof(recvBuf));
printf("[c99_modbus] SerialReceive 状态码 / SerialReceive status code: %d, 内容 / Text: %s\n", ret, recvBuf);
Arm_ModbusSlave_Destroy(slave);
printf("[c99_modbus] 从站句柄已释放 / Slave handle destroyed\n");
}
// [ZH] 断开连接并销毁句柄。
// [EN] Disconnect and destroy the handle.
Arm_Disconnect(handle);
Arm_Destroy(handle);
printf("[c99_modbus] 示例结束 / Example finished\n");
return 0;
}