Skip to content

Commit 5c2845a

Browse files
authored
Merge pull request #307 from mavlink/pr-update-proto-and-version
Update proto and mavsdk_server version
2 parents e026f87 + bb0e0ed commit 5c2845a

File tree

7 files changed

+1050
-96
lines changed

7 files changed

+1050
-96
lines changed

MAVSDK_SERVER_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
v0.35.1
1+
v0.36.0
22

33

44

mavsdk/gimbal.py

Lines changed: 288 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,172 @@ def __str__(self):
4242
return self.name
4343

4444

45+
class ControlMode(Enum):
46+
"""
47+
Control mode
48+
49+
Values
50+
------
51+
NONE
52+
Indicates that the component does not have control over the gimbal
53+
54+
PRIMARY
55+
To take primary control over the gimbal
56+
57+
SECONDARY
58+
To take secondary control over the gimbal
59+
60+
"""
61+
62+
63+
NONE = 0
64+
PRIMARY = 1
65+
SECONDARY = 2
66+
67+
def translate_to_rpc(self):
68+
if self == ControlMode.NONE:
69+
return gimbal_pb2.CONTROL_MODE_NONE
70+
if self == ControlMode.PRIMARY:
71+
return gimbal_pb2.CONTROL_MODE_PRIMARY
72+
if self == ControlMode.SECONDARY:
73+
return gimbal_pb2.CONTROL_MODE_SECONDARY
74+
75+
@staticmethod
76+
def translate_from_rpc(rpc_enum_value):
77+
""" Parses a gRPC response """
78+
if rpc_enum_value == gimbal_pb2.CONTROL_MODE_NONE:
79+
return ControlMode.NONE
80+
if rpc_enum_value == gimbal_pb2.CONTROL_MODE_PRIMARY:
81+
return ControlMode.PRIMARY
82+
if rpc_enum_value == gimbal_pb2.CONTROL_MODE_SECONDARY:
83+
return ControlMode.SECONDARY
84+
85+
def __str__(self):
86+
return self.name
87+
88+
89+
class ControlStatus:
90+
"""
91+
Control status
92+
93+
Parameters
94+
----------
95+
control_mode : ControlMode
96+
Control mode (none, primary or secondary)
97+
98+
sysid_primary_control : int32_t
99+
Sysid of the component that has primary control over the gimbal (0 if no one is in control)
100+
101+
compid_primary_control : int32_t
102+
Compid of the component that has primary control over the gimbal (0 if no one is in control)
103+
104+
sysid_secondary_control : int32_t
105+
Sysid of the component that has secondary control over the gimbal (0 if no one is in control)
106+
107+
compid_secondary_control : int32_t
108+
Compid of the component that has secondary control over the gimbal (0 if no one is in control)
109+
110+
"""
111+
112+
113+
114+
def __init__(
115+
self,
116+
control_mode,
117+
sysid_primary_control,
118+
compid_primary_control,
119+
sysid_secondary_control,
120+
compid_secondary_control):
121+
""" Initializes the ControlStatus object """
122+
self.control_mode = control_mode
123+
self.sysid_primary_control = sysid_primary_control
124+
self.compid_primary_control = compid_primary_control
125+
self.sysid_secondary_control = sysid_secondary_control
126+
self.compid_secondary_control = compid_secondary_control
127+
128+
def __equals__(self, to_compare):
129+
""" Checks if two ControlStatus are the same """
130+
try:
131+
# Try to compare - this likely fails when it is compared to a non
132+
# ControlStatus object
133+
return \
134+
(self.control_mode == to_compare.control_mode) and \
135+
(self.sysid_primary_control == to_compare.sysid_primary_control) and \
136+
(self.compid_primary_control == to_compare.compid_primary_control) and \
137+
(self.sysid_secondary_control == to_compare.sysid_secondary_control) and \
138+
(self.compid_secondary_control == to_compare.compid_secondary_control)
139+
140+
except AttributeError:
141+
return False
142+
143+
def __str__(self):
144+
""" ControlStatus in string representation """
145+
struct_repr = ", ".join([
146+
"control_mode: " + str(self.control_mode),
147+
"sysid_primary_control: " + str(self.sysid_primary_control),
148+
"compid_primary_control: " + str(self.compid_primary_control),
149+
"sysid_secondary_control: " + str(self.sysid_secondary_control),
150+
"compid_secondary_control: " + str(self.compid_secondary_control)
151+
])
152+
153+
return f"ControlStatus: [{struct_repr}]"
154+
155+
@staticmethod
156+
def translate_from_rpc(rpcControlStatus):
157+
""" Translates a gRPC struct to the SDK equivalent """
158+
return ControlStatus(
159+
160+
ControlMode.translate_from_rpc(rpcControlStatus.control_mode),
161+
162+
163+
rpcControlStatus.sysid_primary_control,
164+
165+
166+
rpcControlStatus.compid_primary_control,
167+
168+
169+
rpcControlStatus.sysid_secondary_control,
170+
171+
172+
rpcControlStatus.compid_secondary_control
173+
)
174+
175+
def translate_to_rpc(self, rpcControlStatus):
176+
""" Translates this SDK object into its gRPC equivalent """
177+
178+
179+
180+
181+
rpcControlStatus.control_mode = self.control_mode.translate_to_rpc()
182+
183+
184+
185+
186+
187+
rpcControlStatus.sysid_primary_control = self.sysid_primary_control
188+
189+
190+
191+
192+
193+
rpcControlStatus.compid_primary_control = self.compid_primary_control
194+
195+
196+
197+
198+
199+
rpcControlStatus.sysid_secondary_control = self.sysid_secondary_control
200+
201+
202+
203+
204+
205+
rpcControlStatus.compid_secondary_control = self.compid_secondary_control
206+
207+
208+
209+
210+
45211
class GimbalResult:
46212
"""
47213
Result type.
@@ -243,6 +409,40 @@ async def set_pitch_and_yaw(self, pitch_deg, yaw_deg):
243409
raise GimbalError(result, "set_pitch_and_yaw()", pitch_deg, yaw_deg)
244410

245411

412+
async def set_pitch_rate_and_yaw_rate(self, pitch_rate_deg_s, yaw_rate_deg_s):
413+
"""
414+
Set gimbal angular rates around pitch and yaw axes.
415+
416+
This sets the desired angular rates around pitch and yaw axes of a gimbal.
417+
Will return when the command is accepted, however, it might
418+
take the gimbal longer to actually reach the angular rate.
419+
420+
Parameters
421+
----------
422+
pitch_rate_deg_s : float
423+
Angular rate around pitch axis in degrees/second (negative downward)
424+
425+
yaw_rate_deg_s : float
426+
Angular rate around yaw axis in degrees/second (positive is clock-wise)
427+
428+
Raises
429+
------
430+
GimbalError
431+
If the request fails. The error contains the reason for the failure.
432+
"""
433+
434+
request = gimbal_pb2.SetPitchRateAndYawRateRequest()
435+
request.pitch_rate_deg_s = pitch_rate_deg_s
436+
request.yaw_rate_deg_s = yaw_rate_deg_s
437+
response = await self._stub.SetPitchRateAndYawRate(request)
438+
439+
440+
result = self._extract_result(response)
441+
442+
if result.result is not GimbalResult.Result.SUCCESS:
443+
raise GimbalError(result, "set_pitch_rate_and_yaw_rate()", pitch_rate_deg_s, yaw_rate_deg_s)
444+
445+
246446
async def set_mode(self, gimbal_mode):
247447
"""
248448
Set gimbal mode.
@@ -314,4 +514,91 @@ async def set_roi_location(self, latitude_deg, longitude_deg, altitude_m):
314514

315515
if result.result is not GimbalResult.Result.SUCCESS:
316516
raise GimbalError(result, "set_roi_location()", latitude_deg, longitude_deg, altitude_m)
317-
517+
518+
519+
async def take_control(self, control_mode):
520+
"""
521+
Take control.
522+
523+
There can be only two components in control of a gimbal at any given time.
524+
One with "primary" control, and one with "secondary" control. The way the
525+
secondary control is implemented is not specified and hence depends on the
526+
vehicle.
527+
528+
Components are expected to be cooperative, which means that they can
529+
override each other and should therefore do it carefully.
530+
531+
Parameters
532+
----------
533+
control_mode : ControlMode
534+
Control mode (primary or secondary)
535+
536+
Raises
537+
------
538+
GimbalError
539+
If the request fails. The error contains the reason for the failure.
540+
"""
541+
542+
request = gimbal_pb2.TakeControlRequest()
543+
544+
request.control_mode = control_mode.translate_to_rpc()
545+
546+
547+
response = await self._stub.TakeControl(request)
548+
549+
550+
result = self._extract_result(response)
551+
552+
if result.result is not GimbalResult.Result.SUCCESS:
553+
raise GimbalError(result, "take_control()", control_mode)
554+
555+
556+
async def release_control(self):
557+
"""
558+
Release control.
559+
560+
Release control, such that other components can control the gimbal.
561+
562+
Raises
563+
------
564+
GimbalError
565+
If the request fails. The error contains the reason for the failure.
566+
"""
567+
568+
request = gimbal_pb2.ReleaseControlRequest()
569+
response = await self._stub.ReleaseControl(request)
570+
571+
572+
result = self._extract_result(response)
573+
574+
if result.result is not GimbalResult.Result.SUCCESS:
575+
raise GimbalError(result, "release_control()")
576+
577+
578+
async def control(self):
579+
"""
580+
Subscribe to control status updates.
581+
582+
This allows a component to know if it has primary, secondary or
583+
no control over the gimbal. Also, it gives the system and component ids
584+
of the other components in control (if any).
585+
586+
Yields
587+
-------
588+
control_status : ControlStatus
589+
Control status
590+
591+
592+
"""
593+
594+
request = gimbal_pb2.SubscribeControlRequest()
595+
control_stream = self._stub.SubscribeControl(request)
596+
597+
try:
598+
async for response in control_stream:
599+
600+
601+
602+
yield ControlStatus.translate_from_rpc(response.control_status)
603+
finally:
604+
control_stream.cancel()

0 commit comments

Comments
 (0)