Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investigate Impact of supporting WeDo 2.0 #58

Closed
tthiery opened this issue Jul 14, 2020 · 17 comments · Fixed by #198
Closed

Investigate Impact of supporting WeDo 2.0 #58

tthiery opened this issue Jul 14, 2020 · 17 comments · Fixed by #198

Comments

@tthiery
Copy link
Member

tthiery commented Jul 14, 2020

Lesson Learnt from #48

Note: Note to everyone: I do not have the hardware and have in the foreseeable future no interest in purchasing them. If you want support for this hardware in this library, please contribute. I will guide you through the process and assist with everything needed.

@Sodoshi
Copy link

Sodoshi commented Aug 3, 2020

Managed to get this working with my Bluegiga dongle and the new 88012 hubs that came with the Liebherr Excavator, but it was not simple to make work as the Bluegiga acts as a singleton on a serial port and this meant some of the async connection tasks broke... I got around it by making a separate repository and translating to/from the sharpbrick objects, but this will need cleaning up. The TechnicMediumHub ports work for the internals (LED light, etc), but the motors appear to be on different ports, so am probing the HubAttachedIO to try and work out where they are... Anyway, https://github.com/Sodoshi/SharpBrick.PoweredUp.Bluegiga is where I am at...

@tthiery
Copy link
Member Author

tthiery commented Aug 3, 2020

@Sodoshi can you open a separate Issue for this. Very interested in how this further evolves. I was confused first but then I realized you talk about Control+ and not WeDo 2.0.

The motors however, should work if the internals work. A bit concerned about that. Maybe post a example. The motors self-register at the beginning of the connection. Maybe you loose some characteristics notification at the beginning.

I also took a mental note that the Bluetooth Abstraction is now an external contract. At the current early state, I cannot promise that I - or you 😀 - will not break it.

@mennolodder
Copy link
Contributor

I've just started using the library with my Mercedes Zetros Truck .

I think it has this motor (it's the bottom one):
unnamed

It is reported on the hub as device type 'Motor (id 1)'. Which doesn't seem supported.

I would love to help adding support for this motor, I am an experienced c# programmer, but I have no clue what needs to be done here :)

@tthiery
Copy link
Member Author

tthiery commented Jan 2, 2024

@mennolodder

So this is the "LEGO 6290182 - 21980 - Electric, Motor WeDo 2.0 Medium". But it seems to operate on a Technic Medium Hub. Which is good since the communication partner of this library is the hub not the motor.

The first thing you should do, is use the command line to dump the motor self-description. Let us see what that provides.

https://github.com/sharpbrick/powered-up/blob/master/docs/development/adding-new-device.md

@mennolodder
Copy link
Contributor

mennolodder commented Jan 2, 2024

I'm afraid for my system the commandline tool hangs on receiving messages (also if I do poweredup device list):

I'm sure it is on port 2, the others motors I can access.

>poweredup device dump-static-port -p 2
Scan Started. Please select the Hub (using a number keys or 'q' to terminate):
1: TechnicMediumHub (with address 158897338045109)
1
Selected TechnicMediumHub with key 1
Discover Port 2. Receiving Messages ...
........

@tthiery
Copy link
Member Author

tthiery commented Jan 2, 2024

That is ugly. I do not have a device and my knowledge is a bit rusty to read raw traces. Maybe you can try first running the it on the raw Lego Wireless Protocol (that is the Bluetooth Library) and write power on/off into the device.

The technic motors have three levels. Try using the raw messages against the WeDo 2.0 motor. That might work. The README has a tutorial.

  1. BasicMotor which is purely power based using StartPowerAsync with PortOutputCommandStartPowerMessage
  2. TachoMotor which extend with speed using StartSpeedAsync with PortOutputCommandStartSpeedMessage
  3. AbsoluteMotor which extend with position.

@mennolodder
Copy link
Contributor

Yeah, the poweredup device list fails always, unless I unplug all motors (so just the hub with nothing attached).

I will give that a try, might take a while to get back to you though. Thx for all the quick responses.

@tthiery
Copy link
Member Author

tthiery commented Jan 2, 2024

I just run the tool on TechnicXLargeMotor on the TechnicMediumHub on port A. Still works here. No idea if they screwed up the firmware maybe meanwhile.

I have checked the code with the JavaScript library. They support the WeDo 2.0 motor. However, that library is not as "sophisticated" as this library (I tried to implement the protocol not just make the devices work). That is the reason that library works. Which is good news, because it can work in theory.

I also checked there the code (either 1 or 2) and both only support power messages with this function. In this library the equivalent function is here. So I am quite confident that this message will work on the raw protocol.

Once we have evaluated which functions work, we can try to build a device which ignores the discoverability and provides just the methods. Let us create then a new issue (other than this) and run a release (v5.0 hopefully) including it.

ps: there was a "typo" above it was PortOutputCommandStartPower2Message but it should be PortOutputCommandStartPowerMessage

@mennolodder
Copy link
Contributor

mennolodder commented Jan 9, 2024

I tried your suggestions, I think :)

With respect to the raw messages, do you mean: 'Connect to Hub and Send a Message and retrieving answers (directly on protocol layer)'. This seems to be a bit outdated, as it doesn't compile (and the examples dir doesn't have a compiling example that does the same).

For instance: BluetoothKernel does not have a property BluetoothAddress
SendMessageAsync requires a LegoWirelessMessage

EDIT the issue below seems to be the same as #190

I adapted it like this, but it fails to connect:

     var kernel = scope.ServiceProvider.GetService<BluetoothKernel>(); // .BluetoothAddress = bluetoothAddress;
     kernel.BluetoothDeviceInfo = new PoweredUpBluetoothDeviceInfoWithMacAddress()
     {
         MacAddressAsUInt64 = adressAsLong
     };

     var protocol = scope.ServiceProvider.GetService<ILegoWirelessProtocol>();

     await protocol.ConnectAsync(); // nullpointer thrown here

The error is:

System.ArgumentNullException
  HResult=0x80004003
  Message=Value cannot be null. Arg_ParamName_Name
  Source=SharpBrick.PoweredUp.WinRT
  StackTrace:
   at SharpBrick.PoweredUp.WinRT.WinRTPoweredUpBluetoothDevice..ctor(BluetoothLEDevice device)
   at SharpBrick.PoweredUp.WinRT.WinRTPoweredUpBluetoothAdapter.<GetDeviceAsync>d__1.MoveNext()
   at SharpBrick.PoweredUp.Bluetooth.BluetoothKernel.<ConnectAsync>d__12.MoveNext()
   at SharpBrick.PoweredUp.Protocol.LegoWirelessProtocol.<ConnectAsync>d__15.MoveNext()
   at LegoCar.Program.<RunRawSingleMotor>d__4.MoveNext() in C:\Repos\lego_automated_car\LegoCar\LegoCar\Program.cs:line 78
   at LegoCar.Program.<MainAsync>d__2.MoveNext() in C:\Repos\lego_automated_car\LegoCar\LegoCar\Program.cs:line 41
   at LegoCar.Program.Main(String[] args) in C:\Repos\lego_automated_car\LegoCar\LegoCar\Program.cs:line 26

I'm pretty sure I know my devices mac adress, I converted it to long using the helper class BlueGigaBLEHelper, double checked it with the Hub.PrimaryMacAddress and it is the same as the hex input there. (note that I use the default WinRt bluetooth).
However, I also can't connect to it using but it also fails when I try to connect it in the way the ExampleTwoHubsMotorControl does:

  var host = serviceProvider.GetService<PoweredUpHost>();

  //var hub = await host.DiscoverAsync<TechnicMediumHub>();
  var hub = await host.CreateByStateAsync<TechnicMediumHub>(adressAsLong);
  await hub.ConnectAsync();

Also after that I can't use the style var motor = technicMediumHub.A.GetDevice<BasicMotor>();, because BasicMotor is not a IPoweredUpDevice.

@tthiery
Copy link
Member Author

tthiery commented Jan 10, 2024

Yeah seems like the README needs some update. Discovery and DI scope creation works easiest when re-using host logic and host functions. I justed tested this with a TechnicMediumHub and a TechnicXLargeMotor.

using SharpBrick.PoweredUp;

using Microsoft.Extensions.DependencyInjection; // SharpBrick.PoweredUp uses the DI system
using Microsoft.Extensions.Logging;
using SharpBrick.PoweredUp.Bluetooth;
using SharpBrick.PoweredUp.Protocol;
using SharpBrick.PoweredUp.Protocol.Messages; // SharpBrick.PoweredUp also logs stuff

var serviceProvider = new ServiceCollection()
    .AddLogging()
    .AddPoweredUp()
#if WINDOWS
    .AddWinRTBluetooth() // using WinRT Bluetooth on Windows (separate NuGet SharpBrick.PoweredUp.WinRT; others are available)
#endif
    .BuildServiceProvider();

// getting utilities
var bt = serviceProvider.GetService<IPoweredUpBluetoothAdapter>();
var host = serviceProvider.GetService<PoweredUpHost>();

// discover a LWP bluetooth device 
var tcs = new TaskCompletionSource<ILegoWirelessProtocol>();

bt.Discover(async deviceInfo =>
{
    if (!tcs.Task.IsCompleted)
    {
        var p = host.CreateProtocol(deviceInfo);

        tcs.SetResult(p);
    }
});

var protocol = await tcs.Task;

// connect the protocol
await protocol.ConnectAsync();

// send a raw message which should work with ANY motor connected to a hub
var response = await protocol.SendPortOutputCommandAsync(new PortOutputCommandStartPowerMessage(
    0, // PORT A
    PortOutputCommandStartupInformation.ExecuteImmediately, PortOutputCommandCompletionInformation.CommandFeedback,
    100
)
{
    HubId = 0, // as if we ever see another one
});

await Task.Delay(2000);

await protocol.DisconnectAsync();

with the following csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>    
    <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net8.0-windows10.0.19041.0;net8.0</TargetFrameworks>
    <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net8.0</TargetFrameworks>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\src\SharpBrick.PoweredUp\SharpBrick.PoweredUp.csproj" />
  </ItemGroup>

  <ItemGroup Condition=" '$(TargetFramework)' == 'net8.0-windows10.0.19041.0' ">
    <ProjectReference Include="..\..\src\SharpBrick.PoweredUp.WinRT\SharpBrick.PoweredUp.WinRT.csproj" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
  </ItemGroup>

</Project>

and the following invocation

dotnet run -f net8.0-windows10.0.19041.0

@mennolodder
Copy link
Contributor

I fixed the problem with the manual connection, the address conversion is wrong (at least for the WinRT version). I just used the commandline logged one from poweredup device list. that works.

I ran your example, it works!

I get the following errors (I updated the not supported messages in the Device.GetStaticPortInfoMessages to add some info, I can make a PR if you want it):

// Device 'RgbLight' does not support Systemtype 'LegoWeDo20_WeDoHub' on Hardware '1.0.0.0' and Software '1.0.0.0'
// Device 'Current' does not support Systemtype 'LegoWeDo20_WeDoHub' on Hardware '1.0.0.0' and Software '1.0.0.0'
// Device 'Voltage' does not support Systemtype 'LegoWeDo20_WeDoHub' on Hardware '1.0.0.0' and Software '1.0.0.0'

You also get those? (I also get them if I run without any motors, should be the same as you have).

@mennolodder
Copy link
Contributor

Added PR #194 which is needed to support this.

The output of discovery now works (for this, not yet for my large lineair motors.

Discover Ports Function: 9 / 9
LegoTechnic_MediumHub
##################################################
0B-00-43-02-01-01-01-00-00-01-00
05-00-43-02-02
11-00-44-02-00-00-4C-50-46-32-2D-4D-4D-4F-54-4F-52
0E-00-44-02-00-01-00-00-C8-C2-00-00-C8-42
0E-00-44-02-00-02-00-00-C8-C2-00-00-C8-42
0E-00-44-02-00-03-00-00-C8-C2-00-00-C8-42
0A-00-44-02-00-04-00-00-00-00
08-00-44-02-00-05-00-10
0A-00-44-02-00-80-01-00-04-00
##################################################

Are you interested in a PR that adds some improved error messages?

@mennolodder
Copy link
Contributor

And here is the output from device list:

 - Port: 0x02 / 2
    - IOTypeId: Motor / 0x0001 / 1
      Revision: SW: 0.0.0.0, HW: 0.0.0.0
      Capabilities: Output
      ModeCombinations: []
    - Mode 0: Name: LPF2-MMOTOR, Symbol: , Capability: Output
      - DataSet: 1x SByte, TotalFigures: 4, Decimals: 0
        Output Mapping: Absolute
        Raw Min:    -100, Max:     100
        Pct Min:    -100, Max:     100 (pass-through)
        SI  Min:    -100, Max:     100 (pass-through)

@tthiery
Copy link
Member Author

tthiery commented Jan 14, 2024

I lost a bit oversight of what you all did. Let me try to summarize

@mennolodder
Copy link
Contributor

mennolodder commented Jan 14, 2024

Yeah I can image, I'm doing everything at the same time and didn't really know what I am doing lol :)

  1. WeDo devicelist / port dump hang and threw an error because of the fix in Decoding name now also supports strings without padding nulls. #194
  2. The TechnicLargeLinearMotor device list hang because it used different static port info messages, described here poweredup device list hangs #193 . I will make a PR for that later.
  3. a, Perhaps the port dump device list would also be helped if it didn't use the static messages here, creating issue
  4. I made good progress with supporting the WeDo motor, I guess we should name this 'SimpleMediumLinearMotor'. Can you easily see from the dump /device list if this is a BasicMotor or anything of the other motor types? If not I will investigate.
  5. Will make a separate PR for some better error messages.

@tthiery
Copy link
Member Author

tthiery commented Jan 14, 2024

used different static port info messages

This should not be. Either we discover the device OR use static port inform messages. Do not remember why the behavior is like that. Device enumeration not necessarily need to discover the devices but my just pretty print our existing knowledge.

Fix what you find, do PRs. I completely open to it. If you want to do some major rework, discuss it first.

@mennolodder
Copy link
Contributor

Ok I'll make a separate ticket for that then, I really think it did both. It was requesting port mode information and got a reply for 5 modes, but actually requested information for 6 modes, which is the amount in the static port info.

tthiery pushed a commit that referenced this issue Jan 15, 2024
* Created SimpleMediumLinearMotor

#58 non-breaking

Co-authored-by: Menno Lodder <menno@lodder>
@tthiery tthiery added this to the v5.0 (breaking) milestone Jan 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants